Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e54b1406c | ||
|
|
f52c9772a7 | ||
|
|
ea5203d8c3 | ||
|
|
0fad2f9953 | ||
|
|
d3a9392421 | ||
|
|
208927544d | ||
|
|
7621155a89 | ||
|
|
4ddc4ebf46 | ||
|
|
786f0b5ca2 | ||
|
|
b4ff429bfa | ||
|
|
f2cf0ec459 | ||
|
|
0380d70a46 | ||
|
|
28099b9812 | ||
|
|
2ce4f602c0 | ||
|
|
5e81fb4754 | ||
|
|
c9f1a95343 | ||
|
|
97d8d07947 | ||
|
|
4f0adad78e | ||
|
|
0499005db5 | ||
|
|
aedffb3cfe | ||
|
|
fff96e69db | ||
|
|
abc99c9dd8 | ||
|
|
6e4b76a3b4 | ||
|
|
92d8642133 | ||
|
|
184124586b | ||
|
|
4d32b6976a | ||
|
|
45a99e576d | ||
|
|
fac6d54986 | ||
|
|
036c35729c | ||
|
|
e442fddc66 | ||
|
|
a3c3afba48 | ||
|
|
794ceac440 | ||
|
|
6299d41cda | ||
|
|
2e5ce0249e | ||
|
|
560298655b | ||
|
|
4086df27b2 | ||
|
|
d76ae413c4 | ||
|
|
8b1df2e9ca | ||
|
|
c8855f97e8 | ||
|
|
bbf1aa1668 | ||
|
|
141f3bcec3 | ||
|
|
8f11fd7c62 | ||
|
|
9f960c25a5 | ||
|
|
11a616917a | ||
|
|
a89f03f27d | ||
|
|
3faf36440c | ||
|
|
45d4f46024 | ||
|
|
896f2aeb74 | ||
|
|
7de39611f3 | ||
|
|
7e6be23287 | ||
|
|
cac76d4739 | ||
|
|
194e5dc94e | ||
|
|
f7629362d7 | ||
|
|
ea0c396114 | ||
|
|
057e2d8056 | ||
|
|
487fe21e25 | ||
|
|
54dce9b60e | ||
|
|
f09a3142a6 | ||
|
|
121c8d8a48 | ||
|
|
b9561ec8db | ||
|
|
b1d8eff019 | ||
|
|
f9c4a40d60 | ||
|
|
8e318f76a7 | ||
|
|
7d21ea93a6 | ||
|
|
8630ba4a2d | ||
|
|
17a448e045 | ||
|
|
7ff11dce35 | ||
|
|
e2a4854bcf | ||
|
|
bef96e231d | ||
|
|
325df8a6e3 | ||
|
|
3620f72b6c | ||
|
|
42a90b2d40 | ||
|
|
97aab6950c | ||
|
|
31258247b3 | ||
|
|
beed4e8aa8 | ||
|
|
c60a0bc062 | ||
|
|
733c2d4152 | ||
|
|
79b5857f72 | ||
|
|
7260eba26a | ||
|
|
7e7a1b2caf | ||
|
|
99181e3302 | ||
|
|
d57d2b96d6 | ||
|
|
24bed8c548 | ||
|
|
6c9e704aa8 | ||
|
|
d3eb31e4c3 | ||
|
|
698b01f85a | ||
|
|
4c88e97330 | ||
|
|
25babff827 | ||
|
|
23e833c69e | ||
|
|
22bb3fe876 | ||
|
|
eee10d3ee7 | ||
|
|
c7591045af | ||
|
|
6ddfef6383 | ||
|
|
9852e30b39 | ||
|
|
2d3ce32314 | ||
|
|
d8e0bea110 | ||
|
|
b2cf6a6ea8 | ||
|
|
2ebcd673c8 | ||
|
|
aa5f186a96 | ||
|
|
934f73f696 | ||
|
|
993c6f0e7b | ||
|
|
1d79e22468 | ||
|
|
8ba92d8b99 | ||
|
|
af23258152 | ||
|
|
b2e50b42a3 | ||
|
|
003b4d0218 | ||
|
|
545472f9c4 | ||
|
|
8f781c27f9 | ||
|
|
589dc34b99 | ||
|
|
564622e38b | ||
|
|
d3744d6f66 | ||
|
|
2613ef0633 | ||
|
|
be3cdcd71a | ||
|
|
d48ac09e25 | ||
|
|
e5a0ba7bf3 |
333
Cargo.lock
generated
333
Cargo.lock
generated
@@ -1,5 +1,10 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.5"
|
||||
@@ -24,7 +29,7 @@ version = "0.3.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -48,7 +53,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.1.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -73,7 +78,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.7"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -81,7 +86,7 @@ name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -94,16 +99,39 @@ name = "crossbeam-utils"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossterm_winapi 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"signal-hook 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -112,7 +140,7 @@ name = "dirs-sys"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -148,6 +176,40 @@ name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "git-version"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"git-version-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git-version-macro"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gmp-mpfr-sys"
|
||||
version = "1.1.14"
|
||||
@@ -162,6 +224,23 @@ name = "indexmap"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@@ -172,7 +251,7 @@ name = "lexical"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lexical-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -181,7 +260,7 @@ name = "lexical-core"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -192,12 +271,20 @@ name = "libc"
|
||||
version = "0.2.62"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -210,14 +297,53 @@ name = "memchr"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -227,9 +353,9 @@ name = "nix"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -306,6 +432,33 @@ dependencies = [
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
@@ -314,9 +467,17 @@ dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prolog_parser"
|
||||
version = "0.8.40"
|
||||
version = "0.8.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -334,6 +495,14 @@ dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
@@ -373,14 +542,6 @@ name = "redox_syscall"
|
||||
version = "0.1.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_termios"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.3.1"
|
||||
@@ -422,9 +583,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustyline"
|
||||
version = "5.0.3"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -441,25 +603,55 @@ name = "ryu"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "scryer-prolog"
|
||||
version = "0.8.118"
|
||||
dependencies = [
|
||||
"crossterm 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"downcast 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"git-version 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"prolog_parser 0.8.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"prolog_parser 0.8.49 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustyline 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustyline 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.6.13"
|
||||
@@ -468,6 +660,11 @@ dependencies = [
|
||||
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "stackvector"
|
||||
version = "1.0.2"
|
||||
@@ -491,6 +688,16 @@ dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.10.2"
|
||||
@@ -502,16 +709,6 @@ dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.3.0"
|
||||
@@ -527,6 +724,11 @@ name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_reader"
|
||||
version = "1.0.0"
|
||||
@@ -554,6 +756,11 @@ name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
@@ -563,6 +770,11 @@ dependencies = [
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
@@ -573,36 +785,58 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff"
|
||||
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
||||
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
|
||||
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
"checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55"
|
||||
"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
|
||||
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
|
||||
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499"
|
||||
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
|
||||
"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff"
|
||||
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
|
||||
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
|
||||
"checksum crossterm 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8a3223215bc00c666d6be730e88aef245ad4a4f837e87a16c347e8acf701643"
|
||||
"checksum crossterm_winapi 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "057b7146d02fb50175fd7dbe5158f6097f33d02831f43b4ee8ae4ddf67b68f5c"
|
||||
"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
||||
"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
|
||||
"checksum downcast 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d"
|
||||
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
|
||||
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum git-version 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "94918e83f1e01dedc2e361d00ce9487b14c58c7f40bab148026fa39d42cb41e2"
|
||||
"checksum git-version-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "34a97a52fdee1870a34fa6e4b77570cba531b27d1838874fef4429a791a3d657"
|
||||
"checksum gmp-mpfr-sys 1.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72592cd7513feefa5e41414825c42e839120d2f09e10c6094105d066072955fb"
|
||||
"checksum indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6d89e0948bf10c08b9ecc8ac5b83f07f857ebe2c0cbe38de15b4e4f510356"
|
||||
"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c106ed999697325a540c43d66a8d5175668cd96d7eb0bdba03a3bd98256cd698"
|
||||
"checksum lexical-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e82e023e062f1d25f807ad182008fba1b46538e999f908a08cc0c29e084462e"
|
||||
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
|
||||
"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
|
||||
"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
|
||||
"checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
@@ -613,35 +847,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
"checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6"
|
||||
"checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d"
|
||||
"checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc"
|
||||
"checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1"
|
||||
"checksum proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420"
|
||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
"checksum prolog_parser 0.8.40 (registry+https://github.com/rust-lang/crates.io-index)" = "013131c03328aef02b069e6b325b01fb47597034af169b8b8a1bb8f2cfab0868"
|
||||
"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
|
||||
"checksum prolog_parser 0.8.49 (registry+https://github.com/rust-lang/crates.io-index)" = "82f46113e58039861f82f6b6cdaca94c0997eda2c7317a4c4f13d549c4601eec"
|
||||
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d"
|
||||
"checksum ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6"
|
||||
"checksum rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "592f3a1bba452fcfb91127354012c2b3aa580b266caef1923b16638057c038b5"
|
||||
"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
|
||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
"checksum rustyline 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4795e277e6e57dec9df62b515cd4991371daa80e8dc8d80d596e58722b89c417"
|
||||
"checksum rustyline 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de64be8eecbe428b6924f1d8430369a01719fbb182c26fa431ddbb0a95f5315d"
|
||||
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||
"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
"checksum signal-hook 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "10b9f3a1686a29f53cfd91ee5e3db3c12313ec02d33765f02c1a9645a1811e2c"
|
||||
"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
|
||||
"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
|
||||
"checksum stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c049c77bf85fbc036484c97b008276d539d9ebff9dfbde37b632ebcd5b8746b6"
|
||||
"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
|
||||
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
|
||||
"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
|
||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
|
||||
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
"checksum unicode_reader 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f886d405a2be65db804cb1088f969dbd99528a9eec9bcf941584b17de4cd3034"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
|
||||
@@ -16,16 +16,17 @@ default = ["rug", "prolog_parser/rug"]
|
||||
num = ["num-rug-adapter", "prolog_parser/num"]
|
||||
|
||||
[dependencies]
|
||||
crossterm = "0.16.0"
|
||||
dirs = "2.0.2"
|
||||
downcast = "0.10.0"
|
||||
git-version = "0.3.4"
|
||||
indexmap = "1.0.2"
|
||||
lazy_static = "1.4.0"
|
||||
libc = "0.2.62"
|
||||
nix = "0.15.0"
|
||||
num-rug-adapter = { optional = true, version = "0.1.1" }
|
||||
ordered-float = "0.5.0"
|
||||
prolog_parser = { version = "0.8.40", default-features = false }
|
||||
prolog_parser = { version = "0.8.49", default-features = false }
|
||||
ref_thread_local = "0.0.0"
|
||||
rug = { version = "1.4.0", optional = true }
|
||||
rustyline = "5.0.3"
|
||||
termion = "1.4.0"
|
||||
rustyline = "6.0.0"
|
||||
163
README.md
163
README.md
@@ -30,7 +30,7 @@ Extend Scryer Prolog to include the following, among other features:
|
||||
- [x] Built-in predicates for list processing and top-level declarative
|
||||
control (`setup_call_cleanup/3`, `call_with_inference_limit/3`,
|
||||
etc.)
|
||||
- [x] ~~Default representation of strings as list of chars, using a packed
|
||||
- [x] ~~Default representation of strings as lists of characters, using a packed
|
||||
internal representation.~~
|
||||
- [x] `term_expansion/2` and `goal_expansion/2`.
|
||||
- [x] Definite Clause Grammars.
|
||||
@@ -52,11 +52,11 @@ Extend Scryer Prolog to include the following, among other features:
|
||||
"Delimited Continuations for Prolog").
|
||||
- [x] Tabling library based on delimited continuations
|
||||
(documented in "Tabling as a Library with Delimited Control").
|
||||
- [x] A _redone_ representation of strings as difference list of
|
||||
chars, using a packed internal representation.
|
||||
- [ ] clp(B) and clp(ℤ) as builtin libraries (_in progress_).
|
||||
- [x] A _redone_ representation of strings as difference lists of
|
||||
characters, using a packed internal representation.
|
||||
- [x] clp(B) and clp(ℤ) as builtin libraries.
|
||||
- [ ] Streams and predicates for stream control (_in progress_).
|
||||
- [ ] An incremental compacting garbage collector satisfying the five
|
||||
- [ ] A compacting garbage collector satisfying the five
|
||||
properties of "Precise Garbage Collection in Prolog."
|
||||
- [ ] Mode declarations.
|
||||
|
||||
@@ -92,8 +92,14 @@ strings.
|
||||
|
||||
First, install the latest stable version of
|
||||
[Rust](https://www.rust-lang.org/en-US/install.html) using your
|
||||
preferred method. Then install Scryer Prolog with cargo,
|
||||
like so:
|
||||
preferred method. Scryer tends to use features from newer Rust
|
||||
releases, whereas Rust packages in Linux distributions, Macports,
|
||||
etc. tend to lag behind. [rustup](http://rustup.rs) will keep your
|
||||
Rust updated to the latest stable release; any existing Rust
|
||||
distribution should be uninstalled from your system before rustup is
|
||||
used.
|
||||
|
||||
Scryer Prolog can be installed with cargo, like so:
|
||||
|
||||
```
|
||||
$> cargo install scryer-prolog
|
||||
@@ -117,11 +123,6 @@ $> cargo run [--release]
|
||||
The optional `--release` flag will perform various optimizations,
|
||||
producing a faster executable.
|
||||
|
||||
Note on compatibility: Scryer Prolog should work on Linux, Mac OS X,
|
||||
and BSD variants on which Rust runs. Windows support hinges on
|
||||
rustyline and Termion being functional in that environment, which to
|
||||
my knowledge is not presently the case.
|
||||
|
||||
## Tutorial
|
||||
To enter a multi-clause predicate, the directive "[user]" is used.
|
||||
|
||||
@@ -155,11 +156,10 @@ Wildcards work as well:
|
||||
member(X, [X|_]).
|
||||
member(X, [_|Xs]) :- member(X, Xs).
|
||||
?- member(X, [a, b, c]).
|
||||
true .
|
||||
X = a ;
|
||||
X = b ;
|
||||
X = c ;
|
||||
false.
|
||||
X = a
|
||||
; X = b
|
||||
; X = c
|
||||
; false.
|
||||
```
|
||||
and so do conjunctive queries:
|
||||
```
|
||||
@@ -169,10 +169,9 @@ f(X) :- g(X).
|
||||
g(x). g(y). g(z).
|
||||
h(call(f, X)).
|
||||
?- h(X), X.
|
||||
true .
|
||||
X = call(f, x) ;
|
||||
X = call(f, y) ;
|
||||
X = call(f, z).
|
||||
X = call(f,x)
|
||||
; X = call(f,y)
|
||||
; X = call(f,z).
|
||||
```
|
||||
|
||||
Note that the values of variables belonging to successful queries are
|
||||
@@ -190,46 +189,128 @@ Scryer supports dynamic operators. Using the built-in
|
||||
arithmetic operators with the usual precedences,
|
||||
|
||||
```
|
||||
?- write_canonical(-5 + 3 - (2 * 4) // 8).
|
||||
-(+(-(5), 3), //(*(2, 4), 8))
|
||||
?- write_canonical(-5 + 3 - (2 * 4) // 8), nl.
|
||||
-(+(-5,3),//(*(2,4),8))
|
||||
true.
|
||||
```
|
||||
|
||||
New operators can be defined using the `op` declaration.
|
||||
|
||||
### Partial strings
|
||||
### Strings and partial strings
|
||||
|
||||
Scryer has three specialized non-ISO predicates for handling so-called
|
||||
"partial strings." Partial strings imitate difference lists of
|
||||
characters, but their characters are packed in UTF-8 format, a much
|
||||
more efficient alternative to how lists of characters are represented
|
||||
in many other Prologs.
|
||||
In Scryer Prolog, the default value of the Prolog flag `double_quotes`
|
||||
is `chars`, which is also the recommended setting. This means that
|
||||
double-quoted strings are interpreted as lists of *characters*, in the
|
||||
tradition of Marseille Prolog.
|
||||
|
||||
To use partial strings, the `non_iso` library must be loaded:
|
||||
For example, the following query succeeds:
|
||||
|
||||
`?- use_module(library(non_iso)).`
|
||||
```
|
||||
?- "abc" = [a,b,c].
|
||||
true.
|
||||
```
|
||||
|
||||
If `X` is a free variable, the query
|
||||
Internally, strings are represented very compactly in packed
|
||||
UTF-8 encoding. A naive representation of strings as lists of
|
||||
characters would use one memory cell per character, one
|
||||
memory cell per list constructor, and one memory cell for
|
||||
each tail that occurs in the list. Since one memory cell takes
|
||||
8 bytes on 64-bit machines, the packed representation used by
|
||||
Scryer Prolog yields an up to **24-fold reduction** of
|
||||
memory usage, and corresponding reduction of memory accesses when
|
||||
creating and processing strings.
|
||||
|
||||
`?- partial_string("abc", X, _), X = [a, b, c | Y], partial_string(X),
|
||||
partial_string_tail(X, Tail), Tail == Y.`
|
||||
Scryer Prolog uses the same efficient encoding for *partial* strings,
|
||||
which appear to Prolog code as partial lists of characters. The
|
||||
predicate `partial_string/3` from `library(iso_ext)` lets you
|
||||
construct partial strings explicitly. For example:
|
||||
|
||||
will succeed, posting:
|
||||
```
|
||||
?- partial_string("abc", Ls0, Ls).
|
||||
Ls0 = [a,b,c|Ls].
|
||||
```
|
||||
|
||||
`Tail = Y, X = [a,b,c|Y].`
|
||||
In this case, and as the answer illustrates, `Ls0` is
|
||||
indistinguishable from a partial list with tail `Ls`, while
|
||||
the efficient packed representation is used internally.
|
||||
|
||||
By all appearances, partial strings are plain Prolog lists.
|
||||
An important design goal of Scryer Prolog is to *automatically* use
|
||||
the efficient string representation whenever possible. Therefore, it
|
||||
is only very rarely necessary to use `partial_string/3` explicitly. In
|
||||
the above example, posting <tt>Ls0 = [a,b,c|Ls]</tt> yields
|
||||
the exact same internal representation, and has the advantage that
|
||||
only the standard predicate `(=)/2` is used.
|
||||
|
||||
Definite clause grammars as provided by `library(dcgs)` are ideally
|
||||
suited for reasoning about strings.
|
||||
|
||||
### Modules
|
||||
|
||||
Scryer has a simple predicate-based module system. It provides a
|
||||
way to separate units of code into distinct namespaces, for both
|
||||
predicates and operators. See the files `src/prolog/lib/*.pl` for
|
||||
predicates and operators. See the files
|
||||
[`src/prolog/lib/*.pl`](src/prolog/lib) for
|
||||
examples.
|
||||
|
||||
At the time of this writing, several control and list processing
|
||||
operators and predicates are hidden in their own modules that have not
|
||||
been exported to the toplevel. To export them, write
|
||||
At the time of this writing, many predicates reside in their own
|
||||
modules that need to be imported before they can be used.
|
||||
The modules that ship with Scryer Prolog are also called
|
||||
*library* modules or *libraries*, and include:
|
||||
|
||||
* [`lists`](src/prolog/lib/lists.pl)
|
||||
providing `length/2`, `member/2`, `select/3`, `append/[2,3]`,
|
||||
`foldl/[4,5]`, `maplist/[2-9]`, `same_length/2`, `transpose/2` etc.
|
||||
* [`dcgs`](src/prolog/lib/dcgs.pl)
|
||||
Definite Clause Grammars (DCGs), a built-in grammar mechanism
|
||||
that uses the operator `(-->)/2` to define grammar rules,
|
||||
and the predicates `phrase/[2,3]` to invoke them.
|
||||
* [`dif`](src/prolog/lib/dif.pl)
|
||||
The predicate `dif/2` provides declarative disequality:
|
||||
It is true if and only if its arguments are different, and
|
||||
delays the test until a sound decision can be made.
|
||||
* [`reif`](src/prolog/lib/reif.pl)
|
||||
providing `if_/3`, `tfilter/3` and related predicates
|
||||
as described in *Indexing dif/2*.
|
||||
* [`clpz`](src/prolog/lib/clpz.pl)
|
||||
CLP(ℤ): Constraint Logic Programming over Integers,
|
||||
providing declarative integer arithmetic via `(#=)/2`, `(#\=)/2`,
|
||||
`(#>=)/2` etc., and various global constraints and
|
||||
enumeration predicates for solving combinatorial tasks.
|
||||
* [`pairs`](src/prolog/lib/pairs.pl)
|
||||
By convention, *pairs* are Prolog terms with
|
||||
principal functor `(-)/2`, written as `Key-Value`.
|
||||
This library provides `pairs_keys_values/3`,
|
||||
`pairs_keys/2`, and other predicates to reason about pairs.
|
||||
* [`si`](src/prolog/lib/si.pl)
|
||||
The predicates `atom_si/1`, `integer_si/1`, `atomic_si/1`
|
||||
and `list_si/1` implement sound type checks. They raise
|
||||
instantiation errors if no decision can be made.
|
||||
They are declarative replacements for logically flawed
|
||||
lower-level type tests. For instance, instead of `integer(X)`,
|
||||
write `integer_si(X)` to ensure soundness of your programs.
|
||||
"si" stands for *sufficiently instantiated*, and also for
|
||||
*sound inference*.
|
||||
* [`error`](src/prolog/lib/error.pl)
|
||||
`must_be/2` and `can_be/2` complement the type checks provided
|
||||
by `library(si)`, and are especially useful for Prolog library
|
||||
authors.
|
||||
* [`tabling`](src/prolog/lib/tabling.pl)
|
||||
The operator `(table)/1` is used in directives that prepare
|
||||
predicates for tabled execution (SLG resolution).
|
||||
* [`format`](src/prolog/lib/format.pl)
|
||||
The nonterminal `format_//2` is used to describe formatted output,
|
||||
arranging arguments according to a given format string.
|
||||
The predicate `format/2` is provided for impure output.
|
||||
* [`assoc`](src/prolog/lib/assoc.pl)
|
||||
providing `empty_assoc/1`, `get_assoc/3`, `put_assoc/4` etc.
|
||||
to manage elements in AVL trees which ensure
|
||||
*O*(log(*N*)) access.
|
||||
* [`clpb`](src/prolog/lib/clpb.pl)
|
||||
CLP(B): Constraint Logic Programming over Boolean variables,
|
||||
a BDD-based SAT solver provided via the predicates
|
||||
`sat/1`, `taut/2`, `labeling/1` etc.
|
||||
|
||||
To use predicates provided by the `lists` library, write:
|
||||
|
||||
```
|
||||
?- use_module(library(lists)).
|
||||
|
||||
6
build.rs
6
build.rs
@@ -52,5 +52,9 @@ fn main()
|
||||
}
|
||||
|
||||
libraries.write_all(b"\n\n m\n };
|
||||
}").unwrap();
|
||||
}\n").unwrap();
|
||||
|
||||
libraries.write_all(b"\npub static PROJECT_DIR: &'static str = \"").unwrap();
|
||||
libraries.write_all(env::var("CARGO_MANIFEST_DIR").unwrap().as_bytes()).unwrap();
|
||||
libraries.write_all(b"\";\n").unwrap();
|
||||
}
|
||||
|
||||
13
src/main.rs
13
src/main.rs
@@ -1,5 +1,7 @@
|
||||
extern crate crossterm;
|
||||
#[macro_use]
|
||||
extern crate downcast;
|
||||
extern crate git_version;
|
||||
extern crate indexmap;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
@@ -9,15 +11,17 @@ extern crate nix;
|
||||
extern crate prolog_parser;
|
||||
#[macro_use]
|
||||
extern crate ref_thread_local;
|
||||
extern crate termion;
|
||||
|
||||
use git_version::git_version;
|
||||
use nix::sys::signal;
|
||||
|
||||
mod prolog;
|
||||
|
||||
use crate::prolog::machine::*;
|
||||
use crate::prolog::machine::streams::*;
|
||||
use crate::prolog::read::*;
|
||||
|
||||
use std::env;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
extern fn handle_sigint(signal: libc::c_int) {
|
||||
@@ -31,6 +35,11 @@ fn main() {
|
||||
let handler = signal::SigHandler::Handler(handle_sigint);
|
||||
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
|
||||
|
||||
let mut wam = Machine::new(readline::input_stream());
|
||||
if env::args().skip(1).any(|a| a == "-v" || a == "--version") {
|
||||
println!("{:}", git_version!());
|
||||
return;
|
||||
}
|
||||
|
||||
let mut wam = Machine::new(readline::input_stream(), Stream::stdout());
|
||||
wam.run_top_level();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::prolog::forms::*;
|
||||
use crate::prolog::instructions::*;
|
||||
use crate::prolog::iterators::*;
|
||||
|
||||
use crate::prolog::machine::heap::*;
|
||||
use crate::prolog::machine::machine_errors::*;
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
|
||||
@@ -15,6 +16,7 @@ use crate::prolog::rug::{Assign, Integer, Rational};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cmp::{max, min, Ordering};
|
||||
use std::convert::TryFrom;
|
||||
use std::f64;
|
||||
use std::num::FpCategory;
|
||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
||||
@@ -262,6 +264,9 @@ impl<'a> ArithmeticEvaluator<'a> {
|
||||
|
||||
fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> {
|
||||
match c {
|
||||
&Constant::Fixnum(n) => self
|
||||
.interm
|
||||
.push(ArithmeticTerm::Number(Number::Fixnum(n))),
|
||||
&Constant::Integer(ref n) => self
|
||||
.interm
|
||||
.push(ArithmeticTerm::Number(Number::Integer(n.clone()))),
|
||||
@@ -316,18 +321,25 @@ impl<'a> ArithmeticEvaluator<'a> {
|
||||
}
|
||||
|
||||
// integer division rounding function -- 9.1.3.1.
|
||||
pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Integer> {
|
||||
pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> {
|
||||
match n {
|
||||
&Number::Integer(ref n) => RefOrOwned::Borrowed(n),
|
||||
&Number::Integer(_) => {
|
||||
RefOrOwned::Borrowed(n)
|
||||
}
|
||||
&Number::Float(OrderedFloat(f)) => {
|
||||
RefOrOwned::Owned(Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0)))
|
||||
RefOrOwned::Owned(Number::from(
|
||||
Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0))
|
||||
))
|
||||
}
|
||||
&Number::Fixnum(n) => {
|
||||
RefOrOwned::Owned(Number::from(n))
|
||||
}
|
||||
&Number::Rational(ref r) => {
|
||||
let r_ref = r.fract_floor_ref();
|
||||
let (mut fract, mut floor) = (Rational::new(), Integer::new());
|
||||
|
||||
(&mut fract, &mut floor).assign(r_ref);
|
||||
RefOrOwned::Owned(floor)
|
||||
|
||||
RefOrOwned::Owned(Number::from(floor))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -335,6 +347,7 @@ pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Integer> {
|
||||
// floating point rounding function -- 9.1.4.1.
|
||||
pub fn rnd_f(n: &Number) -> f64 {
|
||||
match n {
|
||||
&Number::Fixnum(n) => n as f64,
|
||||
&Number::Integer(ref n) => n.to_f64(),
|
||||
&Number::Float(OrderedFloat(f)) => f,
|
||||
&Number::Rational(ref r) => r.to_f64(),
|
||||
@@ -370,22 +383,32 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn float_fn_to_f(n: isize) -> Result<f64, EvalError> {
|
||||
classify_float(n as f64, rnd_f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
|
||||
classify_float(n.to_f64(), rnd_f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
|
||||
classify_float(r.to_f64(), rnd_f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||
Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||
Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||
if FpCategory::Zero == f2.classify() {
|
||||
Err(EvalError::ZeroDivisor)
|
||||
@@ -399,14 +422,35 @@ impl Add<Number> for Number {
|
||||
|
||||
fn add(self, rhs: Number) -> Self::Output {
|
||||
match (self, rhs) {
|
||||
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Integer(n1 + n2)), // add_i
|
||||
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
|
||||
Ok(if let Some(result) = n1.checked_add(n2) {
|
||||
Number::Fixnum(result)
|
||||
} else {
|
||||
Number::from(Integer::from(n1) + Integer::from(n2))
|
||||
})
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Integer(n2)) |
|
||||
(Number::Integer(n2), Number::Fixnum(n1)) => {
|
||||
Ok(Number::from(Integer::from(n1) + &*n2))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Rational(n2)) |
|
||||
(Number::Rational(n2), Number::Fixnum(n1)) => {
|
||||
Ok(Number::from(Rational::from(n1) + &*n2))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) |
|
||||
(Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
|
||||
Ok(Number::Float(add_f(float_fn_to_f(n1)?, n2)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||
Ok(Number::from(Integer::from(&*n1) + &*n2)) // add_i
|
||||
}
|
||||
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
|
||||
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
||||
Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Rational(n2))
|
||||
| (Number::Rational(n2), Number::Integer(n1)) => {
|
||||
Ok(Number::Rational(Rational::from(n1) + n2))
|
||||
Ok(Number::from(Rational::from(&*n1) + &*n2))
|
||||
}
|
||||
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
|
||||
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
|
||||
@@ -415,7 +459,9 @@ impl Add<Number> for Number {
|
||||
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
|
||||
Ok(Number::Float(add_f(f1, f2)?))
|
||||
}
|
||||
(Number::Rational(r1), Number::Rational(r2)) => Ok(Number::Rational(r1 + r2)),
|
||||
(Number::Rational(r1), Number::Rational(r2)) => {
|
||||
Ok(Number::from(Rational::from(&*r1) + &*r2))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -425,9 +471,10 @@ impl Neg for Number {
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
match self {
|
||||
Number::Integer(n) => Number::Integer(-n),
|
||||
Number::Fixnum(n) => Number::Fixnum(-n),
|
||||
Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))),
|
||||
Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
|
||||
Number::Rational(r) => Number::Rational(-r),
|
||||
Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -445,14 +492,35 @@ impl Mul<Number> for Number {
|
||||
|
||||
fn mul(self, rhs: Number) -> Self::Output {
|
||||
match (self, rhs) {
|
||||
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Integer(n1 * n2)), // mul_i
|
||||
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
|
||||
Ok(if let Some(result) = n1.checked_mul(n2) {
|
||||
Number::Fixnum(result)
|
||||
} else {
|
||||
Number::from(Integer::from(n1) * Integer::from(n2))
|
||||
})
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Integer(n2)) |
|
||||
(Number::Integer(n2), Number::Fixnum(n1)) => {
|
||||
Ok(Number::from(Integer::from(n1) * &*n2))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Rational(n2)) |
|
||||
(Number::Rational(n2), Number::Fixnum(n1)) => {
|
||||
Ok(Number::from(Rational::from(n1) * &*n2))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) |
|
||||
(Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
|
||||
Ok(Number::Float(mul_f(float_fn_to_f(n1)?, n2)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||
Ok(Number::Integer(Rc::new(Integer::from(&*n1) * &*n2))) // mul_i
|
||||
}
|
||||
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
|
||||
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
||||
Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Rational(n2))
|
||||
| (Number::Rational(n2), Number::Integer(n1)) => {
|
||||
Ok(Number::Rational(Rational::from(n1) * n2))
|
||||
Ok(Number::Rational(Rc::new(Rational::from(&*n1) * &*n2)))
|
||||
}
|
||||
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
|
||||
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
|
||||
@@ -461,7 +529,9 @@ impl Mul<Number> for Number {
|
||||
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
|
||||
Ok(Number::Float(mul_f(f1, f2)?))
|
||||
}
|
||||
(Number::Rational(r1), Number::Rational(r2)) => Ok(Number::Rational(r1 * r2)),
|
||||
(Number::Rational(r1), Number::Rational(r2)) => {
|
||||
Ok(Number::Rational(Rc::new(Rational::from(&*r1) * &*r2)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -471,24 +541,72 @@ impl Div<Number> for Number {
|
||||
|
||||
fn div(self, rhs: Number) -> Self::Output {
|
||||
match (self, rhs) {
|
||||
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
|
||||
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
|
||||
Ok(Number::Float(div_f(
|
||||
float_fn_to_f(n1)?,
|
||||
float_fn_to_f(n2)?,
|
||||
)?))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Integer(n2)) => {
|
||||
Ok(Number::Float(div_f(
|
||||
float_fn_to_f(n1)?,
|
||||
float_i_to_f(&n2)?,
|
||||
)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Fixnum(n2)) => {
|
||||
Ok(Number::Float(div_f(
|
||||
float_i_to_f(&n1)?,
|
||||
float_fn_to_f(n2)?,
|
||||
)?))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Rational(n2)) => {
|
||||
Ok(Number::Float(div_f(
|
||||
float_fn_to_f(n1)?,
|
||||
float_r_to_f(&n2)?,
|
||||
)?))
|
||||
}
|
||||
(Number::Rational(n1), Number::Fixnum(n2)) => {
|
||||
Ok(Number::Float(div_f(
|
||||
float_r_to_f(&n1)?,
|
||||
float_fn_to_f(n2)?,
|
||||
)?))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => {
|
||||
Ok(Number::Float(div_f(
|
||||
float_fn_to_f(n1)?,
|
||||
n2,
|
||||
)?))
|
||||
}
|
||||
(Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => {
|
||||
Ok(Number::Float(div_f(
|
||||
n1,
|
||||
float_fn_to_f(n2)?,
|
||||
)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||
Ok(Number::Float(div_f(
|
||||
float_i_to_f(&n1)?,
|
||||
float_i_to_f(&n2)?,
|
||||
)?)),
|
||||
)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Float(OrderedFloat(n2))) => {
|
||||
Ok(Number::Float(div_f(float_i_to_f(&n1)?, n2)?))
|
||||
}
|
||||
(Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
||||
Ok(Number::Float(div_f(n2, float_i_to_f(&n1)?)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Rational(n2)) => Ok(Number::Float(div_f(
|
||||
(Number::Integer(n1), Number::Rational(n2)) => {
|
||||
Ok(Number::Float(div_f(
|
||||
float_i_to_f(&n1)?,
|
||||
float_r_to_f(&n2)?,
|
||||
)?)),
|
||||
(Number::Rational(n2), Number::Integer(n1)) => Ok(Number::Float(div_f(
|
||||
)?))
|
||||
}
|
||||
(Number::Rational(n2), Number::Integer(n1)) => {
|
||||
Ok(Number::Float(div_f(
|
||||
float_r_to_f(&n2)?,
|
||||
float_i_to_f(&n1)?,
|
||||
)?)),
|
||||
)?))
|
||||
}
|
||||
(Number::Rational(n1), Number::Float(OrderedFloat(n2))) => {
|
||||
Ok(Number::Float(div_f(float_r_to_f(&n1)?, n2)?))
|
||||
}
|
||||
@@ -506,25 +624,47 @@ impl Div<Number> for Number {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Number {
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
match (self, rhs) {
|
||||
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2),
|
||||
(&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.eq(&**n2),
|
||||
(&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2),
|
||||
(&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.eq(&**n2),
|
||||
(&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2),
|
||||
(&Number::Fixnum(_), &Number::Float(OrderedFloat(_))) => false,
|
||||
(&Number::Float(OrderedFloat(_)), &Number::Fixnum(_)) => false,
|
||||
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.eq(n2),
|
||||
(&Number::Integer(_), Number::Float(_)) => false,
|
||||
(&Number::Float(_), &Number::Integer(_)) => false,
|
||||
(&Number::Integer(_), &Number::Rational(_)) => false,
|
||||
(&Number::Rational(_), &Number::Integer(_)) => false,
|
||||
(&Number::Rational(_), Number::Float(_)) => false,
|
||||
(&Number::Float(_), &Number::Rational(_)) => false,
|
||||
(&Number::Float(f1), &Number::Float(f2)) => f1.eq(&f2),
|
||||
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.eq(&r2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Number {}
|
||||
|
||||
impl PartialOrd for Number {
|
||||
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
|
||||
match (self, rhs) {
|
||||
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => Some(n1.cmp(n2)),
|
||||
(&Number::Integer(_), Number::Float(_)) => Some(Ordering::Greater),
|
||||
(&Number::Float(_), &Number::Integer(_)) => Some(Ordering::Less),
|
||||
(&Number::Integer(_), &Number::Rational(_)) => Some(Ordering::Greater),
|
||||
(&Number::Rational(_), &Number::Integer(_)) => Some(Ordering::Less),
|
||||
(&Number::Rational(_), Number::Float(_)) => Some(Ordering::Greater),
|
||||
(&Number::Float(_), &Number::Rational(_)) => Some(Ordering::Less),
|
||||
(&Number::Float(f1), &Number::Float(f2)) => Some(f1.cmp(&f2)),
|
||||
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => Some(r1.cmp(&r2)),
|
||||
}
|
||||
Some(self.cmp(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Number {
|
||||
fn cmp(&self, rhs: &Number) -> Ordering {
|
||||
match (self, rhs) {
|
||||
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.cmp(&n2),
|
||||
(&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1).cmp(&*n2),
|
||||
(Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2)),
|
||||
(&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1).cmp(&*n2),
|
||||
(Number::Rational(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Rational::from(n2)),
|
||||
(&Number::Fixnum(_), &Number::Float(OrderedFloat(_))) => Ordering::Greater,
|
||||
(&Number::Float(OrderedFloat(_)), &Number::Fixnum(_)) => Ordering::Less,
|
||||
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2),
|
||||
(&Number::Integer(_), Number::Float(_)) => Ordering::Greater,
|
||||
(&Number::Float(_), &Number::Integer(_)) => Ordering::Less,
|
||||
@@ -538,9 +678,81 @@ impl Ord for Number {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<(Addr, &'a Heap)> for Number {
|
||||
type Error = ();
|
||||
|
||||
fn try_from((addr, heap): (Addr, &'a Heap)) -> Result<Number, Self::Error> {
|
||||
match addr {
|
||||
Addr::CharCode(c) => {
|
||||
Ok(Number::from(c as isize))
|
||||
}
|
||||
Addr::Fixnum(n) => {
|
||||
Ok(Number::from(n))
|
||||
}
|
||||
Addr::Float(n) => {
|
||||
Ok(Number::Float(n))
|
||||
}
|
||||
Addr::Usize(n) => {
|
||||
if let Ok(n) = isize::try_from(n) {
|
||||
Ok(Number::from(n))
|
||||
} else {
|
||||
Ok(Number::from(Integer::from(n)))
|
||||
}
|
||||
}
|
||||
Addr::Con(h) => {
|
||||
Number::try_from(&heap[h])
|
||||
}
|
||||
_ => {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a HeapCellValue> for Number {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: &'a HeapCellValue) -> Result<Number, Self::Error> {
|
||||
match value {
|
||||
HeapCellValue::Addr(addr) => {
|
||||
match addr {
|
||||
&Addr::CharCode(c) => {
|
||||
Ok(Number::from(c as isize))
|
||||
}
|
||||
&Addr::Fixnum(n) => {
|
||||
Ok(Number::from(n))
|
||||
}
|
||||
&Addr::Float(n) => {
|
||||
Ok(Number::Float(n))
|
||||
}
|
||||
&Addr::Usize(n) => {
|
||||
if let Ok(n) = isize::try_from(n) {
|
||||
Ok(Number::from(n))
|
||||
} else {
|
||||
Ok(Number::from(Integer::from(n)))
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
HeapCellValue::Integer(n) => {
|
||||
Ok(Number::Integer(n.clone()))
|
||||
}
|
||||
HeapCellValue::Rational(n) => {
|
||||
Ok(Number::Rational(n.clone()))
|
||||
}
|
||||
_ => {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Computes n ^ power. Ignores the sign of power.
|
||||
pub fn binary_pow(mut n: Integer, power: Integer) -> Integer {
|
||||
let mut power = power.abs();
|
||||
pub fn binary_pow(mut n: Integer, power: &Integer) -> Integer {
|
||||
let mut power = Integer::from(power.abs_ref());
|
||||
|
||||
if power == 0 {
|
||||
return Integer::from(1);
|
||||
|
||||
@@ -75,7 +75,6 @@ pub enum InlinedClauseType {
|
||||
IsCompound(RegType),
|
||||
IsInteger(RegType),
|
||||
IsRational(RegType),
|
||||
IsString(RegType),
|
||||
IsFloat(RegType),
|
||||
IsNonVar(RegType),
|
||||
IsVar(RegType),
|
||||
@@ -105,7 +104,6 @@ ref_thread_local! {
|
||||
m.insert(("compound", 1), ClauseType::Inlined(InlinedClauseType::IsCompound(r1)));
|
||||
m.insert(("integer", 1), ClauseType::Inlined(InlinedClauseType::IsInteger(r1)));
|
||||
m.insert(("rational", 1), ClauseType::Inlined(InlinedClauseType::IsRational(r1)));
|
||||
m.insert(("string", 1), ClauseType::Inlined(InlinedClauseType::IsString(r1)));
|
||||
m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1)));
|
||||
m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1)));
|
||||
m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1)));
|
||||
@@ -117,7 +115,6 @@ ref_thread_local! {
|
||||
m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual)));
|
||||
m.insert(("@=<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual)));
|
||||
m.insert(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm));
|
||||
m.insert(("cyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::CyclicTerm));
|
||||
m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq));
|
||||
m.insert(("functor", 3), ClauseType::BuiltIn(BuiltInClauseType::Functor));
|
||||
m.insert(("ground", 1), ClauseType::BuiltIn(BuiltInClauseType::Ground));
|
||||
@@ -141,7 +138,6 @@ impl InlinedClauseType {
|
||||
&InlinedClauseType::IsCompound(..) => "compound",
|
||||
&InlinedClauseType::IsInteger(..) => "integer",
|
||||
&InlinedClauseType::IsRational(..) => "rational",
|
||||
&InlinedClauseType::IsString(..) => "string",
|
||||
&InlinedClauseType::IsFloat(..) => "float",
|
||||
&InlinedClauseType::IsNonVar(..) => "nonvar",
|
||||
&InlinedClauseType::IsVar(..) => "var",
|
||||
@@ -160,11 +156,9 @@ pub enum SystemClauseType {
|
||||
AtomCodes,
|
||||
AtomLength,
|
||||
BindFromRegister,
|
||||
CallAttributeGoals,
|
||||
CallContinuation,
|
||||
CharCode,
|
||||
CharsToNumber,
|
||||
ClearAttrVarBindings,
|
||||
ClearAttributeGoals,
|
||||
CloneAttributeGoals,
|
||||
CodesToNumber,
|
||||
@@ -172,6 +166,8 @@ pub enum SystemClauseType {
|
||||
CheckCutPoint,
|
||||
CopyToLiftedHeap,
|
||||
CreatePartialString,
|
||||
CurrentInput,
|
||||
CurrentOutput,
|
||||
DeleteAttribute,
|
||||
DeleteHeadAttribute,
|
||||
DynamicModuleResolution(usize),
|
||||
@@ -179,7 +175,6 @@ pub enum SystemClauseType {
|
||||
EnqueueAttributedVar,
|
||||
ExpandGoal,
|
||||
ExpandTerm,
|
||||
FetchAttributeGoals,
|
||||
FetchGlobalVar,
|
||||
FetchGlobalVarWithOffset,
|
||||
GetChar,
|
||||
@@ -231,6 +226,8 @@ pub enum SystemClauseType {
|
||||
RetractClause,
|
||||
RestoreCutPolicy,
|
||||
SetCutPoint(RegType),
|
||||
SetInput,
|
||||
SetOutput,
|
||||
StoreGlobalVar,
|
||||
StoreGlobalVarWithOffset,
|
||||
InferenceLevel,
|
||||
@@ -243,7 +240,9 @@ pub enum SystemClauseType {
|
||||
GetDoubleQuotes,
|
||||
InstallNewBlock,
|
||||
Maybe,
|
||||
QuotedToken,
|
||||
RawInputReadChar,
|
||||
ReadTermFromChars,
|
||||
ResetBlock,
|
||||
ReturnFromVerifyAttr,
|
||||
SetBall,
|
||||
@@ -260,6 +259,7 @@ pub enum SystemClauseType {
|
||||
Variant,
|
||||
WAMInstructions,
|
||||
WriteTerm,
|
||||
WriteTermToChars,
|
||||
}
|
||||
|
||||
impl SystemClauseType {
|
||||
@@ -274,7 +274,6 @@ impl SystemClauseType {
|
||||
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
|
||||
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
|
||||
&SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"),
|
||||
&SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"),
|
||||
&SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
|
||||
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
||||
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
||||
@@ -284,6 +283,8 @@ impl SystemClauseType {
|
||||
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
|
||||
&SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"),
|
||||
&SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"),
|
||||
&SystemClauseType::CurrentInput => clause_name!("$current_input"),
|
||||
&SystemClauseType::CurrentOutput => clause_name!("$current_output"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
|
||||
@@ -295,7 +296,6 @@ impl SystemClauseType {
|
||||
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
|
||||
clause_name!("$use_qualified_module_from_file")
|
||||
}
|
||||
&SystemClauseType::ClearAttrVarBindings => clause_name!("$clear_attr_var_bindings"),
|
||||
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
|
||||
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
|
||||
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
|
||||
@@ -304,7 +304,6 @@ impl SystemClauseType {
|
||||
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
|
||||
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
|
||||
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
|
||||
&SystemClauseType::FetchAttributeGoals => clause_name!("$fetch_attribute_goals"),
|
||||
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
|
||||
&SystemClauseType::FetchGlobalVarWithOffset => {
|
||||
clause_name!("$fetch_global_var_with_offset")
|
||||
@@ -362,12 +361,17 @@ impl SystemClauseType {
|
||||
&SystemClauseType::PointsToContinuationResetMarker => {
|
||||
clause_name!("$points_to_cont_reset_marker")
|
||||
}
|
||||
&SystemClauseType::QuotedToken => {
|
||||
clause_name!("$quoted_token")
|
||||
}
|
||||
&SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"),
|
||||
&SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"),
|
||||
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
||||
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
||||
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
|
||||
&SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"),
|
||||
&SystemClauseType::SetInput => clause_name!("$set_input"),
|
||||
&SystemClauseType::SetOutput => clause_name!("$set_output"),
|
||||
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
|
||||
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
|
||||
&SystemClauseType::StoreGlobalVarWithOffset => {
|
||||
@@ -385,6 +389,7 @@ impl SystemClauseType {
|
||||
&SystemClauseType::NextEP => clause_name!("$nextEP"),
|
||||
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
|
||||
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
|
||||
&SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"),
|
||||
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
|
||||
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
|
||||
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
|
||||
@@ -404,6 +409,7 @@ impl SystemClauseType {
|
||||
&SystemClauseType::Variant => clause_name!("$variant"),
|
||||
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
|
||||
&SystemClauseType::WriteTerm => clause_name!("$write_term"),
|
||||
&SystemClauseType::WriteTermToChars => clause_name!("$write_term_to_chars"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,11 +426,9 @@ impl SystemClauseType {
|
||||
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
|
||||
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
|
||||
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
||||
("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals),
|
||||
("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
|
||||
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
||||
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
||||
("$clear_attr_var_bindings", 0) => Some(SystemClauseType::ClearAttrVarBindings),
|
||||
("$clear_attribute_goals", 0) => Some(SystemClauseType::ClearAttributeGoals),
|
||||
("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals),
|
||||
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
|
||||
@@ -433,6 +437,8 @@ impl SystemClauseType {
|
||||
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
||||
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
|
||||
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
||||
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
|
||||
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
|
||||
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
|
||||
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
|
||||
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
|
||||
@@ -446,7 +452,6 @@ impl SystemClauseType {
|
||||
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
|
||||
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
|
||||
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
|
||||
("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals),
|
||||
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
||||
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
||||
("$get_char", 1) => Some(SystemClauseType::GetChar),
|
||||
@@ -487,6 +492,8 @@ impl SystemClauseType {
|
||||
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
|
||||
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
|
||||
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
|
||||
("$set_input", 1) => Some(SystemClauseType::SetInput),
|
||||
("$set_output", 1) => Some(SystemClauseType::SetOutput),
|
||||
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
|
||||
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
|
||||
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
|
||||
@@ -498,10 +505,12 @@ impl SystemClauseType {
|
||||
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
||||
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
||||
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
||||
("$quoted_token", 1) => Some(SystemClauseType::QuotedToken),
|
||||
("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar),
|
||||
("$nextEP", 3) => Some(SystemClauseType::NextEP),
|
||||
("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
|
||||
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
|
||||
("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars),
|
||||
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
||||
("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
|
||||
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
|
||||
@@ -528,8 +537,9 @@ impl SystemClauseType {
|
||||
("$use_qualified_module_from_file", 2) =>
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
|
||||
("$variant", 2) => Some(SystemClauseType::Variant),
|
||||
("$write_term", 5) => Some(SystemClauseType::WriteTerm),
|
||||
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
|
||||
("$write_term", 6) => Some(SystemClauseType::WriteTerm),
|
||||
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -541,7 +551,6 @@ pub enum BuiltInClauseType {
|
||||
Arg,
|
||||
Compare,
|
||||
CompareTerm(CompareTermQT),
|
||||
CyclicTerm,
|
||||
CopyTerm,
|
||||
Eq,
|
||||
Functor,
|
||||
@@ -572,7 +581,6 @@ impl BuiltInClauseType {
|
||||
&BuiltInClauseType::Arg => clause_name!("arg"),
|
||||
&BuiltInClauseType::Compare => clause_name!("compare"),
|
||||
&BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()),
|
||||
&BuiltInClauseType::CyclicTerm => clause_name!("cyclic_term"),
|
||||
&BuiltInClauseType::CopyTerm => clause_name!("copy_term"),
|
||||
&BuiltInClauseType::Eq => clause_name!("=="),
|
||||
&BuiltInClauseType::Functor => clause_name!("functor"),
|
||||
@@ -592,7 +600,6 @@ impl BuiltInClauseType {
|
||||
&BuiltInClauseType::Arg => 3,
|
||||
&BuiltInClauseType::Compare => 2,
|
||||
&BuiltInClauseType::CompareTerm(_) => 2,
|
||||
&BuiltInClauseType::CyclicTerm => 1,
|
||||
&BuiltInClauseType::CopyTerm => 2,
|
||||
&BuiltInClauseType::Eq => 2,
|
||||
&BuiltInClauseType::Functor => 3,
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::prolog::iterators::*;
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
use crate::prolog::targets::*;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
@@ -50,56 +50,45 @@ impl<'a> ConjunctInfo<'a> {
|
||||
self.has_deep_cut as usize
|
||||
}
|
||||
|
||||
fn mark_unsafe_vars<Alloc: Allocator<'a>>(
|
||||
fn mark_unsafe_vars(
|
||||
&self,
|
||||
mut unsafe_var_marker: UnsafeVarMarker,
|
||||
marker: &Alloc,
|
||||
code: &mut Code
|
||||
code: &mut Code,
|
||||
) {
|
||||
// target the last goal of the rule for handling unsafe variables.
|
||||
// we use this weird logic to find the last goal.
|
||||
let right_index = if let Some(Line::Control(_)) = code.last() {
|
||||
if code.len() >= 2 {
|
||||
code.len() - 2
|
||||
} else {
|
||||
if code.is_empty() {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if code.len() >= 1 {
|
||||
code.len() - 1
|
||||
} else {
|
||||
return;
|
||||
|
||||
let mut code_index = 0;
|
||||
|
||||
for phase in 0 .. {
|
||||
while let Line::Query(ref query_instr) = &code[code_index] {
|
||||
if !unsafe_var_marker.mark_safe_vars(query_instr) {
|
||||
unsafe_var_marker.mark_phase(query_instr, phase);
|
||||
}
|
||||
};
|
||||
|
||||
let mut index = right_index;
|
||||
code_index += 1;
|
||||
}
|
||||
|
||||
if let Line::Query(_) = &code[right_index] {
|
||||
while let Line::Query(_) = &code[index] {
|
||||
if index == 0 {
|
||||
if code_index + 1 < code.len() {
|
||||
code_index += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
code_index = 0;
|
||||
|
||||
for phase in 0 .. {
|
||||
while let Line::Query(ref mut query_instr) = &mut code[code_index] {
|
||||
unsafe_var_marker.mark_unsafe_vars(query_instr, phase);
|
||||
code_index += 1;
|
||||
}
|
||||
|
||||
if code_index + 1 < code.len() {
|
||||
code_index += 1;
|
||||
} else {
|
||||
index -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if let Line::Query(_) = &code[index] {
|
||||
} else {
|
||||
index += 1;
|
||||
}
|
||||
|
||||
unsafe_var_marker.record_unsafe_vars(&self.perm_vs, marker);
|
||||
|
||||
for line in code.iter() {
|
||||
if let Line::Query(ref query_instr) = line {
|
||||
unsafe_var_marker.mark_safe_vars(query_instr);
|
||||
}
|
||||
}
|
||||
|
||||
for index in index..right_index + 1 {
|
||||
if let &mut Line::Query(ref mut query_instr) = &mut code[index] {
|
||||
unsafe_var_marker.mark_unsafe_vars(query_instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,35 +163,44 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
target.push(Target::to_void(1));
|
||||
}
|
||||
|
||||
fn subterm_to_instr<Target>(
|
||||
fn deep_var_instr<Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
cell: &'a Cell<VarReg>,
|
||||
var: &'a Rc<Var>,
|
||||
term_loc: GenContext,
|
||||
is_exposed: bool,
|
||||
target: &mut Vec<Target>,
|
||||
) {
|
||||
if is_exposed || self.get_var_count(var.as_ref()) > 1 {
|
||||
self.marker.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
|
||||
} else {
|
||||
Self::add_or_increment_void_instr(target);
|
||||
}
|
||||
}
|
||||
|
||||
fn subterm_to_instr<Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
subterm: &'a Term,
|
||||
term_loc: GenContext,
|
||||
is_exposed: bool,
|
||||
target: &mut Vec<Target>,
|
||||
) where
|
||||
Target: CompilationTarget<'a>,
|
||||
{
|
||||
) {
|
||||
match subterm {
|
||||
&Term::AnonVar if is_exposed => {
|
||||
self.marker.mark_anon_var(Level::Deep, term_loc, target)
|
||||
self.marker.mark_anon_var(Level::Deep, term_loc, target);
|
||||
}
|
||||
&Term::AnonVar => {
|
||||
Self::add_or_increment_void_instr(target);
|
||||
}
|
||||
&Term::AnonVar => Self::add_or_increment_void_instr(target),
|
||||
&Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => {
|
||||
self.marker
|
||||
.mark_non_var(Level::Deep, term_loc, cell, target);
|
||||
self.marker.mark_non_var(Level::Deep, term_loc, cell, target);
|
||||
target.push(Target::clause_arg_to_instr(cell.get()));
|
||||
}
|
||||
&Term::Constant(_, ref constant) => {
|
||||
target.push(Target::constant_subterm(constant.clone()))
|
||||
target.push(Target::constant_subterm(constant.clone()));
|
||||
}
|
||||
&Term::Var(ref cell, ref var) => {
|
||||
if is_exposed || self.get_var_count(var) > 1 {
|
||||
self.marker
|
||||
.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
|
||||
} else {
|
||||
Self::add_or_increment_void_instr(target);
|
||||
}
|
||||
self.deep_var_instr(cell, var, term_loc, is_exposed, target);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -221,6 +219,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
|
||||
for term in iter {
|
||||
match term {
|
||||
TermRef::AnonVar(lvl @ Level::Shallow) => {
|
||||
if let GenContext::Head = term_loc {
|
||||
self.marker.advance_arg();
|
||||
} else {
|
||||
self.marker.mark_anon_var(lvl, term_loc, &mut target);
|
||||
}
|
||||
}
|
||||
TermRef::Clause(lvl, cell, ct, terms) => {
|
||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||
target.push(Target::to_structure(ct, terms.len(), cell.get()));
|
||||
@@ -236,15 +241,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
self.subterm_to_instr(head, term_loc, is_exposed, &mut target);
|
||||
self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
|
||||
}
|
||||
TermRef::Constant(lvl @ Level::Shallow, cell, Constant::String(ref string)) => {
|
||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||
target.push(Target::to_pstr(lvl, string.to_string(), cell.get(), false));
|
||||
}
|
||||
TermRef::Constant(lvl @ Level::Shallow, cell, constant) => {
|
||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||
target.push(Target::to_constant(lvl, constant.clone(), cell.get()));
|
||||
}
|
||||
TermRef::AnonVar(lvl @ Level::Shallow) => {
|
||||
if let GenContext::Head = term_loc {
|
||||
self.marker.advance_arg();
|
||||
TermRef::PartialString(lvl, cell, string, tail) => {
|
||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||
|
||||
if let Some(tail) = tail {
|
||||
target.push(Target::to_pstr(lvl, string, cell.get(), true));
|
||||
self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
|
||||
} else {
|
||||
self.marker.mark_anon_var(lvl, term_loc, &mut target);
|
||||
target.push(Target::to_pstr(lvl, string, cell.get(), false));
|
||||
}
|
||||
}
|
||||
TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => {
|
||||
@@ -263,14 +275,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
}
|
||||
}
|
||||
|
||||
self.marker
|
||||
.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
|
||||
self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
|
||||
}
|
||||
TermRef::Var(lvl @ Level::Shallow, cell, var) => {
|
||||
self.marker
|
||||
.mark_var(var.clone(), lvl, cell, term_loc, &mut target)
|
||||
self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -432,18 +443,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsString(..) => match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::String(..)) => {
|
||||
code.push(succeed!());
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
||||
code.push(is_string!(r));
|
||||
}
|
||||
_ => {
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsNonVar(..) => match terms[0].as_ref() {
|
||||
&Term::AnonVar => {
|
||||
code.push(fail!());
|
||||
@@ -457,7 +456,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsInteger(..) => match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::Integer(_)) => {
|
||||
&Term::Constant(_, Constant::Integer(_)) |
|
||||
&Term::Constant(_, Constant::Fixnum(_)) => {
|
||||
code.push(succeed!());
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
@@ -522,7 +522,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))))
|
||||
}
|
||||
}
|
||||
&Term::Constant(_, ref c @ Constant::Integer(_)) => {
|
||||
&Term::Constant(_, ref c @ Constant::Integer(_)) |
|
||||
&Term::Constant(_, ref c @ Constant::Fixnum(_)) => {
|
||||
code.push(Line::Query(put_constant!(
|
||||
Level::Shallow,
|
||||
c.clone(),
|
||||
@@ -684,6 +685,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
head: (_, ref args, ref p1),
|
||||
ref clauses,
|
||||
} = rule;
|
||||
|
||||
let mut code = Vec::new();
|
||||
|
||||
self.marker.reset_at_head(args);
|
||||
@@ -705,39 +707,31 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
let iter = ChunkedIterator::from_rule_body(p1, clauses);
|
||||
self.compile_seq(iter, &conjunct_info, &mut code, false)?;
|
||||
|
||||
conjunct_info.mark_unsafe_vars(unsafe_var_marker, &self.marker, &mut code);
|
||||
conjunct_info.mark_unsafe_vars(unsafe_var_marker, &mut code);
|
||||
|
||||
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
|
||||
Ok(code)
|
||||
}
|
||||
|
||||
fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker {
|
||||
let mut unsafe_vars = IndexMap::new();
|
||||
|
||||
for var_status in self.marker.bindings().values() {
|
||||
unsafe_vars.insert(var_status.as_reg_type(), false);
|
||||
}
|
||||
let mut safe_vars = IndexSet::new();
|
||||
|
||||
for fact_instr in fact.iter_mut() {
|
||||
match fact_instr {
|
||||
&mut FactInstruction::UnifyValue(reg) => {
|
||||
if let Some(found) = unsafe_vars.get_mut(®) {
|
||||
if !*found {
|
||||
*found = true;
|
||||
*fact_instr = FactInstruction::UnifyLocalValue(reg);
|
||||
&mut FactInstruction::UnifyValue(r) => {
|
||||
if !safe_vars.contains(&r) {
|
||||
*fact_instr = FactInstruction::UnifyLocalValue(r);
|
||||
safe_vars.insert(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
&mut FactInstruction::UnifyVariable(reg) => {
|
||||
if let Some(found) = unsafe_vars.get_mut(®) {
|
||||
*found = true;
|
||||
}
|
||||
&mut FactInstruction::UnifyVariable(r) => {
|
||||
safe_vars.insert(r);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
UnsafeVarMarker { unsafe_vars }
|
||||
UnsafeVarMarker::from_safe_vars(safe_vars)
|
||||
}
|
||||
|
||||
pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code {
|
||||
@@ -802,7 +796,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||
let iter = ChunkedIterator::from_term_sequence(query);
|
||||
self.compile_seq(iter, &conjunct_info, &mut code, true)?;
|
||||
|
||||
conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &self.marker, &mut code);
|
||||
conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &mut code);
|
||||
|
||||
if let Some(query_term) = query.last() {
|
||||
Self::compile_cleanup(&mut code, &conjunct_info, query_term);
|
||||
|
||||
1202
src/prolog/examples/bimetatrans_ruleml.pl
Normal file
1202
src/prolog/examples/bimetatrans_ruleml.pl
Normal file
File diff suppressed because it is too large
Load Diff
64
src/prolog/examples/least_time.pl
Normal file
64
src/prolog/examples/least_time.pl
Normal file
@@ -0,0 +1,64 @@
|
||||
/* least_time.pl
|
||||
*
|
||||
* By Mark Thom, 2020
|
||||
*
|
||||
* find_min_time/2 solves a problem sometimes posed in the first round
|
||||
* of Google interviews: given a time of day in 24 H format, what is the
|
||||
* lexicographically least permutation of the time that is itself a
|
||||
* valid time in 24 H format?
|
||||
*
|
||||
* Full generality is achieved using the reif library.
|
||||
*/
|
||||
|
||||
:- module(least_time, [find_min_time/2,
|
||||
write_time_nl/1]).
|
||||
|
||||
|
||||
:- use_module(library(dcgs)).
|
||||
:- use_module(library(format)).
|
||||
:- use_module(library(reif)).
|
||||
|
||||
|
||||
permutation([], []).
|
||||
permutation([X|Xs], Ys) :-
|
||||
permutation(Xs, Yss),
|
||||
select(X, Ys, Yss).
|
||||
|
||||
|
||||
valid_time([H1,H2,M1,M2], T) :-
|
||||
memberd_t(H1, [0,1,2], TH1),
|
||||
memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2),
|
||||
memberd_t(M1, [0,1,2,3,4,5], TM1),
|
||||
memberd_t(M2, [0,1,2,3,4,5,6,7,8,9], TM2),
|
||||
( maplist(=(true), [TH1, TH2, TM1, TM2]) ->
|
||||
( H1 =:= 2 ->
|
||||
( H2 =< 3 ->
|
||||
T = true
|
||||
; T = false
|
||||
)
|
||||
; T = true
|
||||
)
|
||||
; T = false
|
||||
).
|
||||
|
||||
|
||||
permuted_times(Time, PermutedTimes) :-
|
||||
setof(P, permutation(Time, P), PermutedTimes0),
|
||||
tfilter(valid_time, PermutedTimes0, PermutedTimes).
|
||||
|
||||
|
||||
find_min_time(Time, Min) :-
|
||||
valid_time(Time, true),
|
||||
permuted_times(Time, PermutedTimes),
|
||||
find_min_time_(PermutedTimes, Time, Min).
|
||||
|
||||
find_min_time_([], Min, Min).
|
||||
find_min_time_([Time|Times], MinSoFar, Min) :-
|
||||
( Time @< MinSoFar ->
|
||||
find_min_time_(Times, Time, Min)
|
||||
; find_min_time_(Times, MinSoFar, Min)
|
||||
).
|
||||
|
||||
|
||||
write_time_nl(Time) :-
|
||||
format("\"~w~w:~w~w\"~n", Time).
|
||||
@@ -1,6 +1,5 @@
|
||||
use prolog_parser::ast::*;
|
||||
|
||||
use crate::prolog::allocator::*;
|
||||
use crate::prolog::forms::*;
|
||||
use crate::prolog::instructions::*;
|
||||
use crate::prolog::iterators::*;
|
||||
@@ -250,67 +249,67 @@ impl<'a> VariableFixtures<'a> {
|
||||
}
|
||||
|
||||
pub struct UnsafeVarMarker {
|
||||
pub unsafe_vars: IndexMap<RegType, bool>,
|
||||
pub unsafe_vars: IndexMap<RegType, usize>,
|
||||
pub safe_vars: IndexSet<RegType>,
|
||||
}
|
||||
|
||||
impl UnsafeVarMarker {
|
||||
pub fn new() -> Self {
|
||||
UnsafeVarMarker {
|
||||
unsafe_vars: IndexMap::new(),
|
||||
safe_vars: IndexSet::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn record_unsafe_vars<'a, Alloc: Allocator<'a>>(
|
||||
&mut self,
|
||||
fixtures: &VariableFixtures,
|
||||
marker: &Alloc
|
||||
) {
|
||||
for &(_, ref cb) in fixtures.values() {
|
||||
if let Some(index) = cb.first() {
|
||||
if !self.unsafe_vars.contains_key(&index.get().norm()) {
|
||||
self.unsafe_vars.insert(index.get().norm(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for var in fixtures.last_chunk_temp_vars.iter().cloned() {
|
||||
let r = marker.get(var);
|
||||
self.unsafe_vars.insert(r, false);
|
||||
pub fn from_safe_vars(safe_vars: IndexSet<RegType>) -> Self {
|
||||
UnsafeVarMarker {
|
||||
unsafe_vars: IndexMap::new(),
|
||||
safe_vars
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) {
|
||||
pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool {
|
||||
match query_instr {
|
||||
QueryInstruction::PutVariable(RegType::Temp(r), _) => {
|
||||
if let Some(found) = self.unsafe_vars.get_mut(&RegType::Temp(*r)) {
|
||||
*found = true;
|
||||
&QueryInstruction::PutVariable(r @ RegType::Temp(_), _)
|
||||
| &QueryInstruction::SetVariable(r) => {
|
||||
self.safe_vars.insert(r);
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
QueryInstruction::SetVariable(reg) => {
|
||||
if let Some(found) = self.unsafe_vars.get_mut(reg) {
|
||||
*found = true;
|
||||
}
|
||||
|
||||
pub fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) {
|
||||
match query_instr {
|
||||
&QueryInstruction::PutValue(r @ RegType::Perm(_), _)
|
||||
| &QueryInstruction::SetValue(r) => {
|
||||
let p = self.unsafe_vars.entry(r).or_insert(0);
|
||||
*p = phase;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction) {
|
||||
pub fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) {
|
||||
match query_instr {
|
||||
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) => {
|
||||
if let Some(found) = self.unsafe_vars.get_mut(&RegType::Perm(i)) {
|
||||
if !*found {
|
||||
*found = true;
|
||||
if let Some(p) = self.unsafe_vars.swap_remove(&RegType::Perm(i)) {
|
||||
if p == phase {
|
||||
*query_instr = QueryInstruction::PutUnsafeValue(i, arg);
|
||||
self.safe_vars.insert(RegType::Perm(i));
|
||||
} else {
|
||||
self.unsafe_vars.insert(RegType::Perm(i), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
&mut QueryInstruction::SetValue(reg) => {
|
||||
if let Some(found) = self.unsafe_vars.get_mut(®) {
|
||||
if !*found {
|
||||
*found = true;
|
||||
*query_instr = QueryInstruction::SetLocalValue(reg);
|
||||
}
|
||||
&mut QueryInstruction::SetValue(r) => {
|
||||
if !self.safe_vars.contains(&r) {
|
||||
*query_instr = QueryInstruction::SetLocalValue(r);
|
||||
|
||||
self.safe_vars.insert(r);
|
||||
self.unsafe_vars.remove(&r);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -12,6 +12,7 @@ use indexmap::IndexMap;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -376,6 +377,19 @@ pub enum ModuleSource {
|
||||
File(ClauseName),
|
||||
}
|
||||
|
||||
impl ModuleSource {
|
||||
pub fn as_functor_stub(&self) -> MachineStub {
|
||||
match self {
|
||||
ModuleSource::Library(ref name) => {
|
||||
functor!("library", [clause_name(name.clone())])
|
||||
}
|
||||
ModuleSource::File(ref name) => {
|
||||
functor!(clause_name(name.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -394,6 +408,7 @@ pub enum Declaration {
|
||||
MultiFile(MultiFileIndicator),
|
||||
NonCountedBacktracking(ClauseName, usize), // name, arity
|
||||
Op(OpDecl),
|
||||
SetPrologFlag(DoubleQuotes),
|
||||
UseModule(ModuleSource),
|
||||
UseQualifiedModule(ModuleSource, Vec<ModuleExport>),
|
||||
}
|
||||
@@ -572,11 +587,33 @@ pub struct Module {
|
||||
pub listing_src: ListingSource,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(Clone)]
|
||||
pub enum Number {
|
||||
Float(OrderedFloat<f64>),
|
||||
Integer(Integer),
|
||||
Rational(Rational),
|
||||
Integer(Rc<Integer>),
|
||||
Rational(Rc<Rational>),
|
||||
Fixnum(isize),
|
||||
}
|
||||
|
||||
impl From<Integer> for Number {
|
||||
#[inline]
|
||||
fn from(n: Integer) -> Self {
|
||||
Number::Integer(Rc::new(n))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rational> for Number {
|
||||
#[inline]
|
||||
fn from(n: Rational) -> Self {
|
||||
Number::Rational(Rc::new(n))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<isize> for Number {
|
||||
#[inline]
|
||||
fn from(n: isize) -> Self {
|
||||
Number::Fixnum(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Number {
|
||||
@@ -585,48 +622,89 @@ impl Default for Number {
|
||||
}
|
||||
}
|
||||
|
||||
impl Number {
|
||||
pub fn to_constant(self) -> Constant {
|
||||
impl Into<Constant> for Number {
|
||||
#[inline]
|
||||
fn into(self) -> Constant {
|
||||
match self {
|
||||
Number::Fixnum(n) => Constant::Fixnum(n),
|
||||
Number::Integer(n) => Constant::Integer(n),
|
||||
Number::Float(f) => Constant::Float(f),
|
||||
Number::Rational(r) => Constant::Rational(r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<HeapCellValue> for Number {
|
||||
#[inline]
|
||||
fn into(self) -> HeapCellValue {
|
||||
match self {
|
||||
Number::Fixnum(n) => HeapCellValue::Addr(Addr::Fixnum(n)),
|
||||
Number::Integer(n) => HeapCellValue::Integer(n),
|
||||
Number::Float(f) => HeapCellValue::Addr(Addr::Float(f)),
|
||||
Number::Rational(r) => HeapCellValue::Rational(r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Number {
|
||||
#[inline]
|
||||
pub fn to_u32(&self) -> Option<u32> {
|
||||
match self {
|
||||
&Number::Fixnum(n) => u32::try_from(n).ok(),
|
||||
&Number::Integer(ref n) => n.to_u32(),
|
||||
&Number::Float(_) => None,
|
||||
&Number::Rational(ref r) =>
|
||||
if r.denom() == &1 {
|
||||
r.numer().to_u32()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_positive(&self) -> bool {
|
||||
match self {
|
||||
&Number::Integer(ref n) => n > &0,
|
||||
&Number::Fixnum(n) => n > 0,
|
||||
&Number::Integer(ref n) => &**n > &0,
|
||||
&Number::Float(OrderedFloat(f)) => f.is_sign_positive(),
|
||||
&Number::Rational(ref r) => r > &0,
|
||||
&Number::Rational(ref r) => &**r > &0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_negative(&self) -> bool {
|
||||
match self {
|
||||
&Number::Integer(ref n) => n < &0,
|
||||
&Number::Fixnum(n) => n < 0,
|
||||
&Number::Integer(ref n) => &**n < &0,
|
||||
&Number::Float(OrderedFloat(f)) => f.is_sign_negative(),
|
||||
&Number::Rational(ref r) => r < &0,
|
||||
&Number::Rational(ref r) => &**r < &0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_zero(&self) -> bool {
|
||||
match self {
|
||||
&Number::Integer(ref n) => n == &0,
|
||||
&Number::Fixnum(n) => n == 0,
|
||||
&Number::Integer(ref n) => &**n == &0,
|
||||
&Number::Float(f) => f == OrderedFloat(0f64),
|
||||
&Number::Rational(ref r) => r == &0,
|
||||
&Number::Rational(ref r) => &**r == &0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn abs(self) -> Self {
|
||||
match self {
|
||||
Number::Integer(n) => Number::Integer(n.abs()),
|
||||
Number::Fixnum(n) =>
|
||||
if let Some(n) = n.checked_abs() {
|
||||
Number::from(n)
|
||||
} else {
|
||||
Number::from(Integer::from(n).abs())
|
||||
}
|
||||
Number::Integer(n) => Number::from(Integer::from(n.abs_ref())),
|
||||
Number::Float(f) => Number::Float(OrderedFloat(f.abs())),
|
||||
Number::Rational(r) => Number::Rational(r.abs()),
|
||||
Number::Rational(r) => Number::from(Rational::from(r.abs_ref())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use prolog_parser::ast::*;
|
||||
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
use crate::prolog::machine::machine_state::*;
|
||||
|
||||
@@ -22,25 +20,33 @@ impl<'a> HCPreOrderIterator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn machine_st(&self) -> &MachineState {
|
||||
&self.machine_st
|
||||
}
|
||||
|
||||
fn follow_heap(&mut self, h: usize) -> Addr {
|
||||
match &self.machine_st.heap[h] {
|
||||
HeapCellValue::NamedStr(arity, _, _) => {
|
||||
for idx in (1..arity + 1).rev() {
|
||||
&HeapCellValue::NamedStr(arity, _, _) => {
|
||||
for idx in (1 .. arity + 1).rev() {
|
||||
self.state_stack.push(Addr::HeapCell(h + idx));
|
||||
}
|
||||
|
||||
Addr::Str(h)
|
||||
}
|
||||
HeapCellValue::Addr(ref a) => {
|
||||
self.follow(a.clone())
|
||||
&HeapCellValue::Addr(a) => {
|
||||
self.follow(a)
|
||||
}
|
||||
HeapCellValue::PartialString(_) => {
|
||||
HeapCellValue::PartialString(..) => {
|
||||
self.follow(Addr::PStrLocation(h, 0))
|
||||
}
|
||||
HeapCellValue::Atom(..) | HeapCellValue::DBRef(_)
|
||||
| HeapCellValue::Integer(_) | HeapCellValue::Rational(_) => {
|
||||
Addr::Con(h)
|
||||
}
|
||||
HeapCellValue::Stream(_) => {
|
||||
Addr::Stream(h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,30 +57,6 @@ impl<'a> HCPreOrderIterator<'a> {
|
||||
let da = self.machine_st.store(self.machine_st.deref(addr));
|
||||
|
||||
match da {
|
||||
Addr::Con(Constant::String(n, s)) => {
|
||||
if !self.machine_st.machine_flags().double_quotes.is_atom() {
|
||||
if s.len() > n {
|
||||
if let Some(c) = s[n ..].chars().next() {
|
||||
let o = c.len_utf8();
|
||||
|
||||
self.state_stack.push(Addr::Con(Constant::String(n+o, s.clone())));
|
||||
|
||||
if self.machine_st.machine_flags().double_quotes.is_codes() {
|
||||
self.state_stack.push(Addr::Con(Constant::CharCode(c as u32)));
|
||||
} else {
|
||||
self.state_stack.push(Addr::Con(Constant::Char(c)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Addr::Con(Constant::EmptyList);
|
||||
}
|
||||
}
|
||||
|
||||
Addr::Con(Constant::String(n, s))
|
||||
}
|
||||
Addr::Con(_) | Addr::DBRef(_) => {
|
||||
da
|
||||
}
|
||||
Addr::Lis(a) => {
|
||||
self.state_stack.push(Addr::HeapCell(a + 1));
|
||||
self.state_stack.push(Addr::HeapCell(a));
|
||||
@@ -82,19 +64,19 @@ impl<'a> HCPreOrderIterator<'a> {
|
||||
da
|
||||
}
|
||||
Addr::PStrLocation(h, n) => {
|
||||
if let HeapCellValue::PartialString(ref pstr) = &self.machine_st.heap[h] {
|
||||
let s = pstr.block_as_str();
|
||||
|
||||
if let Some(c) = s[n ..].chars().next() {
|
||||
if pstr.len() > n + c.len_utf8() {
|
||||
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] {
|
||||
if let Some(c) = pstr.range_from(n ..).next() {
|
||||
if !pstr.at_end(n + c.len_utf8()) {
|
||||
self.state_stack.push(Addr::PStrLocation(h, n + c.len_utf8()));
|
||||
} else if has_tail {
|
||||
self.state_stack.push(Addr::HeapCell(h + 1));
|
||||
} else {
|
||||
self.state_stack.push(Addr::PStrTail(h, n + c.len_utf8()));
|
||||
self.state_stack.push(Addr::EmptyList);
|
||||
}
|
||||
|
||||
self.state_stack.push(Addr::Con(Constant::Char(c)));
|
||||
} else {
|
||||
unreachable!()
|
||||
self.state_stack.push(Addr::Char(c));
|
||||
} else if has_tail {
|
||||
return self.follow(Addr::HeapCell(h + 1));
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
@@ -102,80 +84,63 @@ impl<'a> HCPreOrderIterator<'a> {
|
||||
|
||||
Addr::PStrLocation(h, n)
|
||||
}
|
||||
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::PStrTail(..) => {
|
||||
da
|
||||
}
|
||||
Addr::Str(s) => {
|
||||
self.follow_heap(s) // record terms of structure.
|
||||
}
|
||||
Addr::Con(h) => {
|
||||
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] {
|
||||
if !self.machine_st.flags.double_quotes.is_atom() {
|
||||
return if let Some(c) = pstr.range_from(0 ..).next() {
|
||||
self.state_stack.push(Addr::PStrLocation(h, c.len_utf8()));
|
||||
self.state_stack.push(Addr::Char(c));
|
||||
|
||||
Addr::PStrLocation(h, 0)
|
||||
} else if has_tail {
|
||||
self.follow(Addr::HeapCell(h + 1))
|
||||
} else {
|
||||
Addr::EmptyList
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Addr::Con(h)
|
||||
}
|
||||
da => {
|
||||
da
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for HCPreOrderIterator<'a> {
|
||||
type Item = HeapCellValue;
|
||||
type Item = Addr;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.state_stack.pop().map(|a| match self.follow(a) {
|
||||
Addr::HeapCell(h) => {
|
||||
HeapCellValue::Addr(self.machine_st.heap[h].as_addr(h))
|
||||
}
|
||||
Addr::Str(s) => {
|
||||
match &self.machine_st.heap[s] {
|
||||
val @ HeapCellValue::NamedStr(..) => {
|
||||
val.clone()
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Addr::PStrTail(h, n) => {
|
||||
match &self.machine_st.heap[h] {
|
||||
HeapCellValue::PartialString(ref pstr) => {
|
||||
if pstr.len() > n {
|
||||
HeapCellValue::Addr(Addr::PStrLocation(h, n))
|
||||
} else {
|
||||
HeapCellValue::Addr(pstr.tail_addr().clone())
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Addr::StackCell(fr, sc) => {
|
||||
HeapCellValue::Addr(self.machine_st.stack.index_and_frame(fr)[sc].clone())
|
||||
}
|
||||
da => {
|
||||
HeapCellValue::Addr(da)
|
||||
}
|
||||
})
|
||||
self.state_stack.pop().map(|a| self.follow(a))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MutStackHCIterator
|
||||
where
|
||||
Self: Iterator<Item = HeapCellValue>,
|
||||
where Self: Iterator<Item = Addr>
|
||||
{
|
||||
fn stack(&mut self) -> &mut Vec<Addr>;
|
||||
}
|
||||
|
||||
pub struct HCPostOrderIterator<HCIter> {
|
||||
base_iter: HCIter,
|
||||
parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node.
|
||||
pub struct HCPostOrderIterator<'a> {
|
||||
base_iter: HCPreOrderIterator<'a>,
|
||||
parent_stack: Vec<(usize, Addr)>, // number of children, parent node.
|
||||
}
|
||||
|
||||
impl<HCIter> Deref for HCPostOrderIterator<HCIter> {
|
||||
type Target = HCIter;
|
||||
impl<'a> Deref for HCPostOrderIterator<'a> {
|
||||
type Target = HCPreOrderIterator<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.base_iter
|
||||
}
|
||||
}
|
||||
|
||||
impl<HCIter: Iterator<Item = HeapCellValue>> HCPostOrderIterator<HCIter> {
|
||||
pub fn new(base_iter: HCIter) -> Self {
|
||||
impl<'a> HCPostOrderIterator<'a> {
|
||||
pub fn new(base_iter: HCPreOrderIterator<'a>) -> Self {
|
||||
HCPostOrderIterator {
|
||||
base_iter,
|
||||
parent_stack: vec![],
|
||||
@@ -183,8 +148,8 @@ impl<HCIter: Iterator<Item = HeapCellValue>> HCPostOrderIterator<HCIter> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<HCIter: Iterator<Item = HeapCellValue>> Iterator for HCPostOrderIterator<HCIter> {
|
||||
type Item = HeapCellValue;
|
||||
impl<'a> Iterator for HCPostOrderIterator<'a> {
|
||||
type Item = Addr;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
@@ -197,15 +162,30 @@ impl<HCIter: Iterator<Item = HeapCellValue>> Iterator for HCPostOrderIterator<HC
|
||||
}
|
||||
|
||||
if let Some(item) = self.base_iter.next() {
|
||||
match item {
|
||||
HeapCellValue::NamedStr(arity, name, fix) => self
|
||||
.parent_stack
|
||||
.push((arity, HeapCellValue::NamedStr(arity, name, fix))),
|
||||
HeapCellValue::Addr(Addr::Lis(a)) => self
|
||||
.parent_stack
|
||||
.push((2, HeapCellValue::Addr(Addr::Lis(a)))),
|
||||
child_node => {
|
||||
return Some(child_node);
|
||||
match self.base_iter.machine_st.heap.index_addr(&item).as_ref() {
|
||||
&HeapCellValue::NamedStr(arity, ..) => {
|
||||
self.parent_stack.push((arity, item));
|
||||
}
|
||||
&HeapCellValue::Addr(Addr::Lis(a)) => {
|
||||
self.parent_stack.push((2, Addr::Lis(a)));
|
||||
}
|
||||
&HeapCellValue::Addr(Addr::PStrLocation(h, n)) => {
|
||||
match &self.machine_st.heap[h] {
|
||||
&HeapCellValue::PartialString(ref pstr, _) => {
|
||||
let c = pstr.range_from(n ..).next().unwrap();
|
||||
let next_n = n + c.len_utf8();
|
||||
|
||||
if !pstr.at_end(next_n) {
|
||||
self.parent_stack.push((2, Addr::PStrLocation(h, next_n)));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Some(item);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -215,21 +195,16 @@ impl<HCIter: Iterator<Item = HeapCellValue>> Iterator for HCPostOrderIterator<HC
|
||||
}
|
||||
}
|
||||
|
||||
pub type HCProperPostOrderIterator<'a> = HCPostOrderIterator<HCPreOrderIterator<'a>>;
|
||||
|
||||
impl MachineState {
|
||||
pub fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'a> {
|
||||
HCPreOrderIterator::new(self, a)
|
||||
}
|
||||
|
||||
pub fn post_order_iter<'a>(&'a self, a: Addr) -> HCProperPostOrderIterator<'a> {
|
||||
pub fn post_order_iter<'a>(&'a self, a: Addr) -> HCPostOrderIterator<'a> {
|
||||
HCPostOrderIterator::new(HCPreOrderIterator::new(self, a))
|
||||
}
|
||||
|
||||
pub fn acyclic_pre_order_iter<'a>(
|
||||
&'a self,
|
||||
a: Addr,
|
||||
) -> HCAcyclicIterator<HCPreOrderIterator<'a>> {
|
||||
pub fn acyclic_pre_order_iter<'a>(&'a self, a: Addr,) -> HCAcyclicIterator<'a> {
|
||||
HCAcyclicIterator::new(HCPreOrderIterator::new(self, a))
|
||||
}
|
||||
|
||||
@@ -237,7 +212,7 @@ impl MachineState {
|
||||
&'a self,
|
||||
a1: Addr,
|
||||
a2: Addr,
|
||||
) -> HCZippedAcyclicIterator<HCPreOrderIterator<'a>> {
|
||||
) -> HCZippedAcyclicIterator<'a> {
|
||||
HCZippedAcyclicIterator::new(
|
||||
HCPreOrderIterator::new(self, a1),
|
||||
HCPreOrderIterator::new(self, a2),
|
||||
@@ -251,13 +226,13 @@ impl<'a> MutStackHCIterator for HCPreOrderIterator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HCAcyclicIterator<HCIter> {
|
||||
iter: HCIter,
|
||||
pub struct HCAcyclicIterator<'a> {
|
||||
iter: HCPreOrderIterator<'a>,
|
||||
seen: IndexSet<Addr>,
|
||||
}
|
||||
|
||||
impl<HCIter: MutStackHCIterator> HCAcyclicIterator<HCIter> {
|
||||
pub fn new(iter: HCIter) -> Self {
|
||||
impl<'a> HCAcyclicIterator<'a> {
|
||||
pub fn new(iter: HCPreOrderIterator<'a>) -> Self {
|
||||
HCAcyclicIterator {
|
||||
iter,
|
||||
seen: IndexSet::new(),
|
||||
@@ -265,19 +240,17 @@ impl<HCIter: MutStackHCIterator> HCAcyclicIterator<HCIter> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<HCIter> Deref for HCAcyclicIterator<HCIter> {
|
||||
type Target = HCIter;
|
||||
impl<'a> Deref for HCAcyclicIterator<'a> {
|
||||
type Target = HCPreOrderIterator<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.iter
|
||||
}
|
||||
}
|
||||
|
||||
impl<HCIter> Iterator for HCAcyclicIterator<HCIter>
|
||||
where
|
||||
HCIter: Iterator<Item = HeapCellValue> + MutStackHCIterator,
|
||||
impl<'a> Iterator for HCAcyclicIterator<'a>
|
||||
{
|
||||
type Item = HeapCellValue;
|
||||
type Item = Addr;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(addr) = self.iter.stack().pop() {
|
||||
@@ -293,15 +266,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HCZippedAcyclicIterator<HCIter> {
|
||||
i1: HCIter,
|
||||
i2: HCIter,
|
||||
pub struct HCZippedAcyclicIterator<'a> {
|
||||
i1: HCPreOrderIterator<'a>,
|
||||
i2: HCPreOrderIterator<'a>,
|
||||
seen: IndexSet<(Addr, Addr)>,
|
||||
pub first_to_expire: Ordering,
|
||||
}
|
||||
|
||||
impl<HCIter: MutStackHCIterator> HCZippedAcyclicIterator<HCIter> {
|
||||
pub fn new(i1: HCIter, i2: HCIter) -> Self {
|
||||
impl<'a> HCZippedAcyclicIterator<'a> {
|
||||
pub fn new(i1: HCPreOrderIterator<'a>, i2: HCPreOrderIterator<'a>) -> Self {
|
||||
HCZippedAcyclicIterator {
|
||||
i1,
|
||||
i2,
|
||||
@@ -311,11 +284,9 @@ impl<HCIter: MutStackHCIterator> HCZippedAcyclicIterator<HCIter> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<HCIter> Iterator for HCZippedAcyclicIterator<HCIter>
|
||||
where
|
||||
HCIter: Iterator<Item = HeapCellValue> + MutStackHCIterator,
|
||||
impl<'a> Iterator for HCZippedAcyclicIterator<'a>
|
||||
{
|
||||
type Item = (HeapCellValue, HeapCellValue);
|
||||
type Item = (Addr, Addr);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let (Some(a1), Some(a2)) = (self.i1.stack().pop(), self.i2.stack().pop()) {
|
||||
@@ -338,7 +309,9 @@ where
|
||||
self.first_to_expire = Ordering::Less;
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,13 @@
|
||||
use prolog_parser::ast::*;
|
||||
|
||||
use crate::prolog::instructions::*;
|
||||
use crate::prolog::rug::Integer;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum IntIndex {
|
||||
@@ -48,6 +50,41 @@ impl CodeOffsets {
|
||||
}
|
||||
}
|
||||
|
||||
fn intercept_constant(&mut self, constant: &Constant, index: usize) {
|
||||
match constant {
|
||||
&Constant::Atom(ref name, _) if name.is_char() => {
|
||||
let c = name.as_str().chars().next().unwrap();
|
||||
let code = self.constants
|
||||
.entry(Constant::Char(c))
|
||||
.or_insert(vec![]);
|
||||
|
||||
code.push(Self::add_index(code.is_empty(), index));
|
||||
}
|
||||
&Constant::Fixnum(n) => {
|
||||
let code = self.constants
|
||||
.entry(Constant::Integer(Rc::new(Integer::from(n))))
|
||||
.or_insert(vec![]);
|
||||
|
||||
code.push(Self::add_index(code.is_empty(), index));
|
||||
}
|
||||
&Constant::Integer(ref n) => {
|
||||
if let Some(n) = n.to_isize() {
|
||||
let code = self.constants
|
||||
.entry(Constant::Fixnum(n))
|
||||
.or_insert(vec![]);
|
||||
|
||||
code.push(Self::add_index(code.is_empty(), index));
|
||||
}
|
||||
}
|
||||
&Constant::String(_) => {
|
||||
let is_initial_index = self.lists.is_empty();
|
||||
self.lists.push(Self::add_index(is_initial_index, index));
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn index_term(&mut self, first_arg: &Term, index: usize) {
|
||||
match first_arg {
|
||||
&Term::Clause(_, ref name, ref terms, _) => {
|
||||
@@ -63,18 +100,12 @@ impl CodeOffsets {
|
||||
let is_initial_index = self.lists.is_empty();
|
||||
self.lists.push(Self::add_index(is_initial_index, index));
|
||||
}
|
||||
&Term::Constant(_, Constant::String(n, ref s)) => {
|
||||
let is_initial_index = self.lists.is_empty();
|
||||
self.lists.push(Self::add_index(is_initial_index, index));
|
||||
|
||||
let constant = Constant::String(n, s.clone());
|
||||
let code = self.constants.entry(constant).or_insert(Vec::new());
|
||||
|
||||
let is_initial_index = code.is_empty();
|
||||
code.push(Self::add_index(is_initial_index, index));
|
||||
}
|
||||
&Term::Constant(_, ref constant) => {
|
||||
let code = self.constants.entry(constant.clone()).or_insert(Vec::new());
|
||||
self.intercept_constant(constant, index);
|
||||
|
||||
let code = self.constants
|
||||
.entry(constant.clone())
|
||||
.or_insert(vec![]);
|
||||
|
||||
let is_initial_index = code.is_empty();
|
||||
code.push(Self::add_index(is_initial_index, index));
|
||||
@@ -227,12 +258,11 @@ impl CodeOffsets {
|
||||
fn switch_on_lst_offset_from(
|
||||
lst_loc: IntIndex,
|
||||
prelude_len: usize,
|
||||
lst_offset: usize,
|
||||
) -> usize {
|
||||
match lst_loc {
|
||||
IntIndex::External(o) => o + prelude_len + 1,
|
||||
IntIndex::Fail => 0,
|
||||
IntIndex::Internal(_) => prelude_len - lst_offset + 1,
|
||||
IntIndex::Internal(_) => 1, // this internal is always 0.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,8 +275,6 @@ impl CodeOffsets {
|
||||
let mut prelude = VecDeque::new();
|
||||
|
||||
let lst_loc = Self::switch_on_list(self.lists, &mut prelude);
|
||||
let lst_offset = prelude.len();
|
||||
|
||||
let str_loc = Self::switch_on_structure(self.structures, &mut prelude);
|
||||
let con_loc = Self::switch_on_constant(self.constants, &mut prelude);
|
||||
|
||||
@@ -254,18 +282,19 @@ impl CodeOffsets {
|
||||
|
||||
for (index, line) in prelude.iter_mut().enumerate() {
|
||||
match line {
|
||||
&mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i))
|
||||
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i))
|
||||
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => {
|
||||
*i += prelude_length - index
|
||||
&mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i)) |
|
||||
&mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i)) |
|
||||
&mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => {
|
||||
*i += prelude_length - index;
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let str_loc = Self::switch_on_str_offset_from(str_loc, prelude.len(), con_loc);
|
||||
let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len());
|
||||
let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len(), lst_offset);
|
||||
let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len());
|
||||
|
||||
let switch_instr =
|
||||
IndexingInstruction::SwitchOnTerm(prelude.len() + 1, con_loc, lst_loc, str_loc);
|
||||
|
||||
@@ -2,28 +2,29 @@ use prolog_parser::ast::*;
|
||||
|
||||
use crate::prolog::clause_types::*;
|
||||
use crate::prolog::forms::*;
|
||||
use crate::prolog::machine::heap::*;
|
||||
use crate::prolog::machine::machine_errors::MachineStub;
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
|
||||
use crate::prolog::rug::Integer;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
fn reg_type_into_functor(r: RegType) -> MachineStub {
|
||||
match r {
|
||||
RegType::Temp(r) => functor!("x", 1, [heap_integer!(Integer::from(r))]),
|
||||
RegType::Perm(r) => functor!("y", 1, [heap_integer!(Integer::from(r))]),
|
||||
RegType::Temp(r) => functor!("x", [integer(r)]),
|
||||
RegType::Perm(r) => functor!("y", [integer(r)]),
|
||||
}
|
||||
}
|
||||
|
||||
impl Level {
|
||||
fn into_functor(self) -> MachineStub {
|
||||
match self {
|
||||
Level::Root => functor!("level", 1, [heap_atom!("root")]),
|
||||
Level::Shallow => functor!("level", 1, [heap_atom!("shallow")]),
|
||||
Level::Deep => functor!("level", 1, [heap_atom!("deep")]),
|
||||
Level::Root => functor!("level", [atom("root")]),
|
||||
Level::Shallow => functor!("level", [atom("shallow")]),
|
||||
Level::Deep => functor!("level", [atom("deep")]),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,11 +32,15 @@ impl Level {
|
||||
impl ArithmeticTerm {
|
||||
fn into_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
&ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
|
||||
&ArithmeticTerm::Interm(i) => {
|
||||
functor!("intermediate", 1, [heap_integer!(Integer::from(i))])
|
||||
&ArithmeticTerm::Reg(r) => {
|
||||
reg_type_into_functor(r)
|
||||
}
|
||||
&ArithmeticTerm::Interm(i) => {
|
||||
functor!("intermediate", [integer(i)])
|
||||
}
|
||||
&ArithmeticTerm::Number(ref n) => {
|
||||
vec![n.clone().into()]
|
||||
}
|
||||
&ArithmeticTerm::Number(ref n) => vec![heap_con!(n.clone().to_constant())],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,18 +57,20 @@ impl ChoiceInstruction {
|
||||
pub fn to_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
&ChoiceInstruction::TryMeElse(offset) => {
|
||||
functor!("try_me_else", 1, [heap_integer!(Integer::from(offset))])
|
||||
functor!("try_me_else", [integer(offset)])
|
||||
}
|
||||
&ChoiceInstruction::RetryMeElse(offset) => {
|
||||
functor!("retry_me_else", 1, [heap_integer!(Integer::from(offset))])
|
||||
functor!("retry_me_else", [integer(offset)])
|
||||
}
|
||||
&ChoiceInstruction::TrustMe => {
|
||||
functor!("trust_me")
|
||||
}
|
||||
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
|
||||
functor!("default_retry_me_else", [integer(offset)])
|
||||
}
|
||||
&ChoiceInstruction::DefaultTrustMe => {
|
||||
functor!("default_trust_me")
|
||||
}
|
||||
&ChoiceInstruction::TrustMe => vec![heap_atom!("trust_me")],
|
||||
&ChoiceInstruction::DefaultRetryMeElse(offset) => functor!(
|
||||
"default_retry_me_else",
|
||||
1,
|
||||
[heap_integer!(Integer::from(offset))]
|
||||
),
|
||||
&ChoiceInstruction::DefaultTrustMe => vec![heap_atom!("default_trust_me")],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,21 +86,20 @@ impl CutInstruction {
|
||||
pub fn to_functor(&self, h: usize) -> MachineStub {
|
||||
match self {
|
||||
&CutInstruction::Cut(r) => {
|
||||
let mut stub = functor!("cut", 1, [heap_str!(h + 2)]);
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
stub
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
functor!("cut", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&CutInstruction::GetLevel(r) => {
|
||||
let mut stub = functor!("get_level", 1, [heap_str!(h + 2)]);
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
stub
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
functor!("get_level", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&CutInstruction::GetLevelAndUnify(r) => {
|
||||
let mut stub = functor!("get_level_and_unify", 1, [heap_str!(h + 2)]);
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
stub
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
functor!("get_level_and_unify", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&CutInstruction::NeckCut => {
|
||||
functor!("neck_cut")
|
||||
}
|
||||
&CutInstruction::NeckCut => vec![heap_atom!("neck_cut")],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,13 +128,13 @@ impl IndexedChoiceInstruction {
|
||||
pub fn to_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
&IndexedChoiceInstruction::Try(offset) => {
|
||||
functor!("try", 1, [heap_integer!(Integer::from(offset))])
|
||||
functor!("try", [integer(offset)])
|
||||
}
|
||||
&IndexedChoiceInstruction::Trust(offset) => {
|
||||
functor!("trust", 1, [heap_integer!(Integer::from(offset))])
|
||||
functor!("trust", [integer(offset)])
|
||||
}
|
||||
&IndexedChoiceInstruction::Retry(offset) => {
|
||||
functor!("retry", 1, [heap_integer!(Integer::from(offset))])
|
||||
functor!("retry", [integer(offset)])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,14 +226,11 @@ fn arith_instr_unary_functor(
|
||||
) -> MachineStub {
|
||||
let at_stub = at.into_functor();
|
||||
|
||||
let mut stub = functor!(
|
||||
functor!(
|
||||
name,
|
||||
2,
|
||||
[heap_cell!(h + 4), heap_integer!(Integer::from(t))]
|
||||
);
|
||||
|
||||
stub.extend(at_stub.into_iter());
|
||||
stub
|
||||
[aux(h, 0), integer(t)],
|
||||
[at_stub]
|
||||
)
|
||||
}
|
||||
|
||||
fn arith_instr_bin_functor(
|
||||
@@ -240,20 +243,11 @@ fn arith_instr_bin_functor(
|
||||
let at_1_stub = at_1.into_functor();
|
||||
let at_2_stub = at_2.into_functor();
|
||||
|
||||
let mut stub = functor!(
|
||||
functor!(
|
||||
name,
|
||||
3,
|
||||
[
|
||||
heap_cell!(h + 4),
|
||||
heap_cell!(h + 4 + at_1_stub.len()),
|
||||
heap_integer!(Integer::from(t))
|
||||
]
|
||||
);
|
||||
|
||||
stub.extend(at_1_stub.into_iter());
|
||||
stub.extend(at_2_stub.into_iter());
|
||||
|
||||
stub
|
||||
[aux(h, 0), aux(h, 1), integer(t)],
|
||||
[at_1_stub, at_2_stub]
|
||||
)
|
||||
}
|
||||
|
||||
impl ArithmeticInstruction {
|
||||
@@ -319,17 +313,39 @@ impl ArithmeticInstruction {
|
||||
&ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t),
|
||||
&ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t),
|
||||
&ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t),
|
||||
&ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t),
|
||||
&ArithmeticInstruction::Log(ref at, t) => arith_instr_unary_functor(h, "log", at, t),
|
||||
&ArithmeticInstruction::Exp(ref at, t) => arith_instr_unary_functor(h, "exp", at, t),
|
||||
&ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t),
|
||||
&ArithmeticInstruction::ASin(ref at, t) => arith_instr_unary_functor(h, "asin", at, t),
|
||||
&ArithmeticInstruction::ATan(ref at, t) => arith_instr_unary_functor(h, "atan", at, t),
|
||||
&ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t),
|
||||
&ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", at, t),
|
||||
&ArithmeticInstruction::Sign(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "sign", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Cos(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "cos", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Sin(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "sin", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Tan(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "tan", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Log(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "log", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Exp(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "exp", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::ACos(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "acos", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::ASin(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "asin", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::ATan(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "atan", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Sqrt(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "sqrt", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Abs(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "abs", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Float(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "float", at, t)
|
||||
}
|
||||
@@ -345,8 +361,12 @@ impl ArithmeticInstruction {
|
||||
&ArithmeticInstruction::Floor(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "floor", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t),
|
||||
&ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(h, "+", at, t),
|
||||
&ArithmeticInstruction::Neg(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "-", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Plus(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "+", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::BitwiseComplement(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "\\", at, t)
|
||||
}
|
||||
@@ -378,29 +398,23 @@ impl ControlInstruction {
|
||||
pub fn to_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
&ControlInstruction::Allocate(num_frames) => {
|
||||
functor!("allocate", 1, [heap_integer!(Integer::from(num_frames))])
|
||||
functor!("allocate", [integer(num_frames)])
|
||||
}
|
||||
&ControlInstruction::CallClause(ref ct, arity, _, false, _) => {
|
||||
functor!("call", [clause_name(ct.name()), integer(arity)])
|
||||
}
|
||||
&ControlInstruction::CallClause(ref ct, arity, _, true, _) => {
|
||||
functor!("execute", [clause_name(ct.name()), integer(arity)])
|
||||
}
|
||||
&ControlInstruction::Deallocate => {
|
||||
functor!("deallocate")
|
||||
}
|
||||
&ControlInstruction::CallClause(ref ct, arity, _, false, _) => functor!(
|
||||
"call",
|
||||
2,
|
||||
[
|
||||
heap_con!(Constant::Atom(ct.name(), None)),
|
||||
heap_integer!(Integer::from(arity))
|
||||
]
|
||||
),
|
||||
&ControlInstruction::CallClause(ref ct, arity, _, true, _) => functor!(
|
||||
"execute",
|
||||
2,
|
||||
[
|
||||
heap_con!(Constant::Atom(ct.name(), None)),
|
||||
heap_integer!(Integer::from(arity))
|
||||
]
|
||||
),
|
||||
&ControlInstruction::Deallocate => vec![heap_atom!("deallocate")],
|
||||
&ControlInstruction::JmpBy(_, offset, ..) => {
|
||||
functor!("jmp_by", 1, [heap_integer!(Integer::from(offset))])
|
||||
functor!("jmp_by", [integer(offset)])
|
||||
}
|
||||
&ControlInstruction::Proceed => {
|
||||
functor!("proceed")
|
||||
}
|
||||
&ControlInstruction::Proceed => vec![heap_atom!("proceed")],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -420,26 +434,27 @@ impl From<IndexingInstruction> for Line {
|
||||
impl IndexingInstruction {
|
||||
pub fn to_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
&IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => functor!(
|
||||
&IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => {
|
||||
functor!(
|
||||
"switch_on_term",
|
||||
4,
|
||||
[
|
||||
heap_integer!(Integer::from(vars)),
|
||||
heap_integer!(Integer::from(constants)),
|
||||
heap_integer!(Integer::from(lists)),
|
||||
heap_integer!(Integer::from(structures))
|
||||
]
|
||||
),
|
||||
&IndexingInstruction::SwitchOnConstant(constants, _) => functor!(
|
||||
[integer(vars),
|
||||
integer(constants),
|
||||
integer(lists),
|
||||
integer(structures)]
|
||||
)
|
||||
}
|
||||
&IndexingInstruction::SwitchOnConstant(constants, _) => {
|
||||
functor!(
|
||||
"switch_on_constant",
|
||||
1,
|
||||
[heap_integer!(Integer::from(constants))]
|
||||
),
|
||||
&IndexingInstruction::SwitchOnStructure(structures, _) => functor!(
|
||||
[integer(constants)]
|
||||
)
|
||||
}
|
||||
&IndexingInstruction::SwitchOnStructure(structures, _) => {
|
||||
functor!(
|
||||
"switch_on_structure",
|
||||
1,
|
||||
[heap_integer!(Integer::from(structures))]
|
||||
),
|
||||
[integer(structures)]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -448,6 +463,7 @@ impl IndexingInstruction {
|
||||
pub enum FactInstruction {
|
||||
GetConstant(Level, Constant, RegType),
|
||||
GetList(Level, RegType),
|
||||
GetPartialString(Level, String, RegType, bool),
|
||||
GetStructure(ClauseType, usize, RegType),
|
||||
GetValue(RegType, usize),
|
||||
GetVariable(RegType, usize),
|
||||
@@ -461,86 +477,95 @@ pub enum FactInstruction {
|
||||
impl FactInstruction {
|
||||
pub fn to_functor(&self, h: usize) -> MachineStub {
|
||||
match self {
|
||||
&FactInstruction::GetConstant(lvl, ref constant, r) => {
|
||||
let mut stub = functor!(
|
||||
&FactInstruction::GetConstant(lvl, ref c, r) => {
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"get_constant",
|
||||
3,
|
||||
[
|
||||
heap_str!(h + 4),
|
||||
heap_con!(constant.clone()),
|
||||
heap_str!(h + 6)
|
||||
]
|
||||
);
|
||||
|
||||
stub.append(&mut lvl.into_functor());
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
|
||||
stub
|
||||
[aux(h, 0), constant(h, c), aux(h, 1)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::GetList(lvl, r) => {
|
||||
let mut stub = functor!("get_list", 2, [heap_str!(h + 3), heap_str!(h + 5)]);
|
||||
stub.append(&mut lvl.into_functor());
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub
|
||||
functor!(
|
||||
"get_list",
|
||||
[aux(h, 0), aux(h, 1)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"get_partial_string",
|
||||
[aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::GetStructure(ref ct, arity, r) => {
|
||||
let mut stub = functor!(
|
||||
"get_structure",
|
||||
3,
|
||||
[
|
||||
heap_con!(Constant::Atom(ct.name(), None)),
|
||||
heap_integer!(Integer::from(arity)),
|
||||
heap_str!(h + 4)
|
||||
]
|
||||
);
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub
|
||||
functor!(
|
||||
"get_structure",
|
||||
[clause_name(ct.name()), integer(arity), aux(h, 0)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::GetValue(r, arg) => {
|
||||
let mut stub = functor!(
|
||||
"get_value",
|
||||
2,
|
||||
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
|
||||
);
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub
|
||||
functor!(
|
||||
"get_value",
|
||||
[aux(h, 0), integer(arg)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::GetVariable(r, arg) => {
|
||||
let mut stub = functor!(
|
||||
"get_variable",
|
||||
2,
|
||||
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
|
||||
);
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub
|
||||
functor!(
|
||||
"get_variable",
|
||||
[aux(h, 0), integer(arg)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::UnifyConstant(ref constant) => {
|
||||
functor!("unify_constant", 1, [heap_con!(constant.clone())])
|
||||
&FactInstruction::UnifyConstant(ref c) => {
|
||||
functor!("unify_constant", [constant(h, c)], [])
|
||||
}
|
||||
&FactInstruction::UnifyLocalValue(r) => {
|
||||
let mut stub = functor!("unify_local_value", 1, [heap_str!(h + 2)]);
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub
|
||||
functor!(
|
||||
"unify_local_value",
|
||||
[aux(h, 0)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::UnifyVariable(r) => {
|
||||
let mut stub = functor!("unify_variable", 1, [heap_str!(h + 2)]);
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub
|
||||
functor!(
|
||||
"unify_variable",
|
||||
[aux(h, 0)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::UnifyValue(r) => {
|
||||
let mut stub = functor!("unify_value", 1, [heap_str!(h + 2)]);
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub
|
||||
functor!(
|
||||
"unify_value",
|
||||
[aux(h, 0)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::UnifyVoid(vars) => {
|
||||
functor!("unify_void", 1, [heap_integer!(Integer::from(vars))])
|
||||
functor!("unify_void", [integer(vars)])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -551,6 +576,7 @@ pub enum QueryInstruction {
|
||||
GetVariable(RegType, usize),
|
||||
PutConstant(Level, Constant, RegType),
|
||||
PutList(Level, RegType),
|
||||
PutPartialString(Level, String, RegType, bool),
|
||||
PutStructure(ClauseType, usize, RegType),
|
||||
PutUnsafeValue(usize, usize),
|
||||
PutValue(RegType, usize),
|
||||
@@ -567,103 +593,106 @@ impl QueryInstruction {
|
||||
match self {
|
||||
&QueryInstruction::PutUnsafeValue(norm, arg) => functor!(
|
||||
"put_unsafe_value",
|
||||
2,
|
||||
[
|
||||
heap_integer!(Integer::from(norm)),
|
||||
heap_integer!(Integer::from(arg))
|
||||
]
|
||||
[integer(norm), integer(arg)]
|
||||
),
|
||||
&QueryInstruction::PutConstant(lvl, ref constant, r) => {
|
||||
let mut stub = functor!(
|
||||
&QueryInstruction::PutConstant(lvl, ref c, r) => {
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"put_constant",
|
||||
3,
|
||||
[
|
||||
heap_str!(h + 4),
|
||||
heap_con!(constant.clone()),
|
||||
heap_str!(h + 6)
|
||||
]
|
||||
);
|
||||
|
||||
stub.append(&mut lvl.into_functor());
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
|
||||
stub
|
||||
[aux(h, 0), constant(h, c), aux(h, 1)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::PutList(lvl, r) => {
|
||||
let mut stub = functor!("put_list", 2, [heap_str!(h + 3), heap_str!(h + 5)]);
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub.append(&mut lvl.into_functor());
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
functor!(
|
||||
"put_list",
|
||||
[aux(h, 0), aux(h, 1)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub
|
||||
functor!(
|
||||
"put_partial_string",
|
||||
[aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::PutStructure(ref ct, arity, r) => {
|
||||
let mut stub = functor!(
|
||||
"put_structure",
|
||||
3,
|
||||
[
|
||||
heap_con!(Constant::Atom(ct.name(), None)),
|
||||
heap_integer!(Integer::from(arity)),
|
||||
heap_str!(h + 4)
|
||||
]
|
||||
);
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
stub
|
||||
functor!(
|
||||
"put_structure",
|
||||
[clause_name(ct.name()), integer(arity), aux(h, 0)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::PutValue(r, arg) => {
|
||||
let mut stub = functor!(
|
||||
"put_value",
|
||||
2,
|
||||
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
|
||||
);
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
stub
|
||||
functor!(
|
||||
"put_value",
|
||||
[aux(h, 0), integer(arg)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::GetVariable(r, arg) => {
|
||||
let mut stub = functor!(
|
||||
"get_variable",
|
||||
2,
|
||||
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
|
||||
);
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
stub
|
||||
functor!(
|
||||
"get_variable",
|
||||
[aux(h, 0), integer(arg)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::PutVariable(r, arg) => {
|
||||
let mut stub = functor!(
|
||||
"put_variable",
|
||||
2,
|
||||
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
|
||||
);
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
stub
|
||||
functor!(
|
||||
"put_variable",
|
||||
[aux(h, 0), integer(arg)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::SetConstant(ref constant) => {
|
||||
functor!("set_constant", 1, [heap_con!(constant.clone())])
|
||||
&QueryInstruction::SetConstant(ref c) => {
|
||||
functor!("set_constant", [constant(h, c)], [])
|
||||
}
|
||||
&QueryInstruction::SetLocalValue(r) => {
|
||||
let mut stub = functor!("set_local_value", 1, [heap_str!(h + 2)]);
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
stub
|
||||
functor!(
|
||||
"set_local_value",
|
||||
[aux(h, 0)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::SetVariable(r) => {
|
||||
let mut stub = functor!("set_variable", 1, [heap_str!(h + 2)]);
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
stub
|
||||
functor!(
|
||||
"set_variable",
|
||||
[aux(h, 0)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::SetValue(r) => {
|
||||
let mut stub = functor!("set_value", 1, [heap_str!(h + 2)]);
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
stub.append(&mut reg_type_into_functor(r));
|
||||
stub
|
||||
functor!(
|
||||
"set_value",
|
||||
[aux(h, 0)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::SetVoid(vars) => {
|
||||
functor!("set_void", 1, [heap_integer!(Integer::from(vars))])
|
||||
functor!("set_void", [integer(vars)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ pub enum TermRef<'a> {
|
||||
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
||||
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>),
|
||||
PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>),
|
||||
Var(Level, &'a Cell<VarReg>, Rc<Var>),
|
||||
}
|
||||
|
||||
@@ -27,6 +28,7 @@ impl<'a> TermRef<'a> {
|
||||
| TermRef::Constant(lvl, ..)
|
||||
| TermRef::Var(lvl, ..)
|
||||
| TermRef::Clause(lvl, ..) => lvl,
|
||||
| TermRef::PartialString(lvl, ..) => lvl,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,13 +45,63 @@ pub enum TermIterState<'a> {
|
||||
),
|
||||
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>),
|
||||
Var(Level, &'a Cell<VarReg>, Rc<Var>),
|
||||
}
|
||||
|
||||
fn is_partial_string<'a>(
|
||||
head: &'a Term,
|
||||
mut tail: &'a Term,
|
||||
) -> Option<(String, Option<&'a Term>)>
|
||||
{
|
||||
let mut string =
|
||||
match head {
|
||||
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
|
||||
atom.as_str().chars().next().unwrap().to_string()
|
||||
}
|
||||
&Term::Constant(_, Constant::Char(c)) => {
|
||||
c.to_string()
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
while let Term::Cons(_, ref head, ref succ) = tail {
|
||||
match head.as_ref() {
|
||||
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
|
||||
string.push(atom.as_str().chars().next().unwrap());
|
||||
}
|
||||
&Term::Constant(_, Constant::Char(c)) => {
|
||||
string.push(c);
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
tail = succ.as_ref();
|
||||
}
|
||||
|
||||
match tail {
|
||||
Term::AnonVar | Term::Var(..) => {
|
||||
return Some((string, Some(tail)));
|
||||
}
|
||||
Term::Constant(_, Constant::EmptyList) => {
|
||||
return Some((string, None));
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TermIterState<'a> {
|
||||
pub fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
|
||||
match term {
|
||||
&Term::AnonVar => TermIterState::AnonVar(lvl),
|
||||
&Term::AnonVar => {
|
||||
TermIterState::AnonVar(lvl)
|
||||
}
|
||||
&Term::Clause(ref cell, ref name, ref subterms, ref spec) => {
|
||||
let ct = if let Some(spec) = spec {
|
||||
ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default())
|
||||
@@ -62,8 +114,12 @@ impl<'a> TermIterState<'a> {
|
||||
&Term::Cons(ref cell, ref head, ref tail) => {
|
||||
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
|
||||
}
|
||||
&Term::Constant(ref cell, ref constant) => TermIterState::Constant(lvl, cell, constant),
|
||||
&Term::Var(ref cell, ref var) => TermIterState::Var(lvl, cell, var.clone()),
|
||||
&Term::Constant(ref cell, ref constant) => {
|
||||
TermIterState::Constant(lvl, cell, constant)
|
||||
}
|
||||
&Term::Var(ref cell, ref var) => {
|
||||
TermIterState::Var(lvl, cell, var.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,7 +225,9 @@ impl<'a> Iterator for QueryIterator<'a> {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(iter_state) = self.state_stack.pop() {
|
||||
match iter_state {
|
||||
TermIterState::AnonVar(lvl) => return Some(TermRef::AnonVar(lvl)),
|
||||
TermIterState::AnonVar(lvl) => {
|
||||
return Some(TermRef::AnonVar(lvl));
|
||||
}
|
||||
TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => {
|
||||
if child_num == child_terms.len() {
|
||||
match ct {
|
||||
@@ -182,7 +240,9 @@ impl<'a> Iterator for QueryIterator<'a> {
|
||||
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
|
||||
}
|
||||
}
|
||||
_ => return None,
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
self.state_stack.push(TermIterState::Clause(
|
||||
@@ -192,23 +252,41 @@ impl<'a> Iterator for QueryIterator<'a> {
|
||||
ct,
|
||||
child_terms,
|
||||
));
|
||||
|
||||
self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref());
|
||||
}
|
||||
}
|
||||
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||
self.state_stack
|
||||
.push(TermIterState::FinalCons(lvl, cell, head, tail));
|
||||
if let Some((string, tail)) = is_partial_string(head, tail) {
|
||||
self.state_stack.push(TermIterState::PartialString(
|
||||
lvl,
|
||||
cell,
|
||||
string,
|
||||
tail,
|
||||
));
|
||||
|
||||
if let Some(tail) = tail {
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
}
|
||||
} else {
|
||||
self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail));
|
||||
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
self.push_subterm(lvl.child_level(), head);
|
||||
}
|
||||
}
|
||||
TermIterState::PartialString(lvl, cell, string, tail) => {
|
||||
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
||||
}
|
||||
TermIterState::FinalCons(lvl, cell, head, tail) => {
|
||||
return Some(TermRef::Cons(lvl, cell, head, tail))
|
||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||
}
|
||||
TermIterState::Constant(lvl, cell, constant) => {
|
||||
return Some(TermRef::Constant(lvl, cell, constant))
|
||||
return Some(TermRef::Constant(lvl, cell, constant));
|
||||
}
|
||||
TermIterState::Var(lvl, cell, var) => {
|
||||
return Some(TermRef::Var(lvl, cell, var));
|
||||
}
|
||||
TermIterState::Var(lvl, cell, var) => return Some(TermRef::Var(lvl, cell, var)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -223,8 +301,7 @@ pub struct FactIterator<'a> {
|
||||
|
||||
impl<'a> FactIterator<'a> {
|
||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||
self.state_queue
|
||||
.push_back(TermIterState::subterm_to_state(lvl, term));
|
||||
self.state_queue.push_back(TermIterState::subterm_to_state(lvl, term));
|
||||
}
|
||||
|
||||
pub fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
|
||||
@@ -241,7 +318,9 @@ impl<'a> FactIterator<'a> {
|
||||
|
||||
fn new(term: &'a Term, iterable_root: bool) -> Self {
|
||||
let states = match term {
|
||||
&Term::AnonVar => vec![TermIterState::AnonVar(Level::Root)],
|
||||
&Term::AnonVar => {
|
||||
vec![TermIterState::AnonVar(Level::Root)]
|
||||
}
|
||||
&Term::Clause(ref cell, ref name, ref terms, ref fixity) => {
|
||||
let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone());
|
||||
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
|
||||
@@ -273,7 +352,9 @@ impl<'a> Iterator for FactIterator<'a> {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(state) = self.state_queue.pop_front() {
|
||||
match state {
|
||||
TermIterState::AnonVar(lvl) => return Some(TermRef::AnonVar(lvl)),
|
||||
TermIterState::AnonVar(lvl) => {
|
||||
return Some(TermRef::AnonVar(lvl));
|
||||
}
|
||||
TermIterState::Clause(lvl, _, cell, ct, child_terms) => {
|
||||
for child_term in child_terms {
|
||||
self.push_subterm(lvl.child_level(), child_term);
|
||||
@@ -285,16 +366,27 @@ impl<'a> Iterator for FactIterator<'a> {
|
||||
};
|
||||
}
|
||||
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||
if let Some((string, tail)) = is_partial_string(head, tail) {
|
||||
if let Some(tail) = tail {
|
||||
self.push_subterm(Level::Deep, tail);
|
||||
}
|
||||
|
||||
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
||||
} else {
|
||||
self.push_subterm(Level::Deep, head);
|
||||
self.push_subterm(Level::Deep, tail);
|
||||
|
||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||
}
|
||||
}
|
||||
TermIterState::Constant(lvl, cell, constant) => {
|
||||
return Some(TermRef::Constant(lvl, cell, constant))
|
||||
}
|
||||
TermIterState::Var(lvl, cell, var) => return Some(TermRef::Var(lvl, cell, var)),
|
||||
_ => {}
|
||||
TermIterState::Var(lvl, cell, var) => {
|
||||
return Some(TermRef::Var(lvl, cell, var));
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -158,4 +158,3 @@ call_residue_vars(Goal, Vars) :-
|
||||
'$get_attr_var_queue_delim'(B),
|
||||
call(Goal),
|
||||
'$get_attr_var_queue_beyond'(B, Vars).
|
||||
|
||||
|
||||
@@ -6,15 +6,10 @@
|
||||
:- use_module(library(error)).
|
||||
|
||||
between(Lower, Upper, X) :-
|
||||
( Upper == inf ->
|
||||
must_be(integer, Lower),
|
||||
can_be(integer, X),
|
||||
enumerate_nats(Lower, X)
|
||||
; must_be(integer, Lower),
|
||||
must_be(integer, Upper),
|
||||
can_be(integer, X),
|
||||
between_(Lower, Upper, X)
|
||||
).
|
||||
between_(Lower, Upper, X).
|
||||
|
||||
between_(Lower, Upper, Lower) :-
|
||||
Lower =< Upper.
|
||||
|
||||
@@ -44,15 +44,16 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
||||
abolish/1, asserta/1, assertz/1, atom_chars/2,
|
||||
atom_codes/2, atom_concat/3, atom_length/2,
|
||||
bagof/3, catch/3, char_code/2, clause/2,
|
||||
current_op/3, current_predicate/1,
|
||||
current_prolog_flag/2, expand_goal/2,
|
||||
expand_term/2, fail/0, false/0, findall/3,
|
||||
findall/4, get_char/1, halt/0, max_arity/1,
|
||||
number_chars/2, number_codes/2, once/1, op/3,
|
||||
read_term/2, repeat/0, retract/1,
|
||||
set_prolog_flag/2, setof/3, sub_atom/5,
|
||||
subsumes_term/2, term_variables/2, throw/1,
|
||||
true/0, unify_with_occurs_check/2, write/1,
|
||||
current_input/1, current_output/1, current_op/3,
|
||||
current_predicate/1, current_prolog_flag/2,
|
||||
expand_goal/2, expand_term/2, fail/0, false/0,
|
||||
findall/3, findall/4, get_char/1, halt/0,
|
||||
max_arity/1, number_chars/2, number_codes/2,
|
||||
once/1, op/3, read_term/2, repeat/0, retract/1,
|
||||
set_prolog_flag/2, set_input/1, set_output/1,
|
||||
setof/3, sub_atom/5, subsumes_term/2,
|
||||
term_variables/2, throw/1, true/0,
|
||||
unify_with_occurs_check/2, write/1,
|
||||
write_canonical/1, write_term/2, writeq/1]).
|
||||
|
||||
|
||||
@@ -261,8 +262,11 @@ univ_errors(Term, List, N) :-
|
||||
Term =.. List :- '$call_with_default_policy'(univ_errors(Term, List, N)),
|
||||
'$call_with_default_policy'(univ_worker(Term, List, N)).
|
||||
|
||||
|
||||
:- non_counted_backtracking univ_worker/3.
|
||||
univ_worker(Term, List, _) :- atomic(Term), !, '$call_with_default_policy'(List = [Term]).
|
||||
|
||||
univ_worker(Term, List, _) :-
|
||||
atomic(Term), !, '$call_with_default_policy'(List = [Term]).
|
||||
univ_worker(Term, [Name|Args], N) :-
|
||||
var(Term), !,
|
||||
'$call_with_default_policy'(Arity is N-1),
|
||||
@@ -273,7 +277,9 @@ univ_worker(Term, List, _) :-
|
||||
'$call_with_default_policy'(get_args(Args, Term, 1, Arity)),
|
||||
'$call_with_default_policy'(List = [Name|Args]).
|
||||
|
||||
|
||||
:- non_counted_backtracking get_args/4.
|
||||
|
||||
get_args(Args, _, _, 0) :-
|
||||
!, '$call_with_default_policy'(Args = []).
|
||||
get_args([Arg], Func, N, N) :-
|
||||
@@ -289,6 +295,7 @@ is_write_option(Functor) :-
|
||||
( Arg == true -> true
|
||||
; Arg == false -> true
|
||||
; Name == variable_names -> must_be_var_names_list(Arg)
|
||||
; Name == max_depth -> integer(Arg), Arg >= 0
|
||||
; var(Arg) -> throw(error(instantiation_error, write_term/2))
|
||||
; throw(error(domain_error(write_option, Functor), write_term/2))
|
||||
), % 8.14.2.3 e)
|
||||
@@ -296,6 +303,7 @@ is_write_option(Functor) :-
|
||||
; Name == quoted -> true
|
||||
; Name == numbervars -> true
|
||||
; Name == variable_names -> true
|
||||
; Name == max_depth -> true
|
||||
; throw(error(domain_error(write_option, Functor), write_term/2))
|
||||
). % 8.14.2.3 e)
|
||||
|
||||
@@ -338,7 +346,8 @@ write_term(Term, Options) :-
|
||||
inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
|
||||
inst_member_or(Options, quoted(Quoted), quoted(false)),
|
||||
inst_member_or(Options, variable_names(VarNames), variable_names([])),
|
||||
'$write_term'(Term, IgnoreOps, NumberVars, Quoted, VarNames).
|
||||
inst_member_or(Options, max_depth(MaxDepth), max_depth(0)),
|
||||
'$write_term'(Term, IgnoreOps, NumberVars, Quoted, VarNames, MaxDepth).
|
||||
|
||||
write(Term) :- write_term(Term, [numbervars(true)]).
|
||||
|
||||
@@ -448,7 +457,7 @@ set_difference([], _, []) :- !.
|
||||
set_difference(Xs, [], Xs).
|
||||
|
||||
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
|
||||
non_iso:variant(V1, V2), !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
|
||||
iso_ext:variant(V1, V2), !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
|
||||
group_by_variant(Pairs, _, [], Pairs).
|
||||
|
||||
group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
|
||||
@@ -456,7 +465,10 @@ group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
|
||||
group_by_variants(Pairs0, Solutions).
|
||||
group_by_variants([], []).
|
||||
|
||||
iterate_variants([V-Solution|GroupSolutions], V, Solution).
|
||||
iterate_variants([V-Solution|GroupSolutions], V, Solution) :-
|
||||
( GroupSolutions == [] -> !
|
||||
; true
|
||||
).
|
||||
iterate_variants([_|GroupSolutions], Ws, Solution) :-
|
||||
iterate_variants(GroupSolutions, Ws, Solution).
|
||||
|
||||
@@ -472,7 +484,9 @@ findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses)
|
||||
( nonvar(Goal), Goal = _ ^ _ ->
|
||||
rightmost_power(Goal, Goal1, ExistentialVars0),
|
||||
term_variables(ExistentialVars0, ExistentialVars),
|
||||
set_difference(Witnesses0, ExistentialVars, Witnesses),
|
||||
sort(Witnesses0, Witnesses1),
|
||||
sort(ExistentialVars, ExistentialVars1),
|
||||
set_difference(Witnesses1, ExistentialVars1, Witnesses),
|
||||
findall(Witnesses-Template, Goal1, PairedSolutions)
|
||||
; Witnesses = Witnesses0,
|
||||
findall(Witnesses-Template, Goal, PairedSolutions)
|
||||
@@ -491,7 +505,10 @@ bagof(Template, Goal, Solution) :-
|
||||
iterate_variants(GroupedSolutions, Witnesses, Solution).
|
||||
|
||||
iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :-
|
||||
sort(Solution0, Solution).
|
||||
sort(Solution0, Solution),
|
||||
( GroupSolutions == [] -> !
|
||||
; true
|
||||
).
|
||||
iterate_variants_and_sort([_|GroupSolutions], Ws, Solution) :-
|
||||
iterate_variants_and_sort(GroupSolutions, Ws, Solution).
|
||||
|
||||
@@ -1006,3 +1023,19 @@ subsumes_term(General, Specific) :-
|
||||
).
|
||||
|
||||
unify_with_occurs_check(X, Y) :- '$unify_with_occurs_check'(X, Y).
|
||||
|
||||
current_input(S) :- '$current_input'(S).
|
||||
|
||||
current_output(S) :- '$current_output'(S).
|
||||
|
||||
set_input(S) :-
|
||||
( var(S) ->
|
||||
throw(error(instantiation_error, set_input/1))
|
||||
; '$set_input'(S)
|
||||
).
|
||||
|
||||
set_output(S) :-
|
||||
( var(S) ->
|
||||
throw(error(instantiation_error, set_output/1))
|
||||
; '$set_output'(S)
|
||||
).
|
||||
|
||||
39
src/prolog/lib/charsio.pl
Normal file
39
src/prolog/lib/charsio.pl
Normal file
@@ -0,0 +1,39 @@
|
||||
:- module(charsio, [read_term_from_chars/2,
|
||||
write_term_to_chars/3]).
|
||||
|
||||
:- use_module(library(iso_ext)).
|
||||
|
||||
read_term_from_chars(Chars, Term) :-
|
||||
( var(Chars) ->
|
||||
throw(error(instantiation_error, read_term_from_chars/2))
|
||||
; nonvar(Term) ->
|
||||
throw(error(uninstantiation_error(Term), read_term_from_chars/2))
|
||||
; '$skip_max_list'(_, -1, Chars, Chars0),
|
||||
Chars0 == [],
|
||||
partial_string(Chars) ->
|
||||
true
|
||||
;
|
||||
throw(error(type_error(complete_string, Chars), read_term_from_chars/2))
|
||||
),
|
||||
'$read_term_from_chars'(Chars, Term).
|
||||
|
||||
|
||||
write_term_to_chars(_, Options, _) :-
|
||||
var(Options), throw(error(instantiation_error, write_term_to_chars/3)).
|
||||
write_term_to_chars(Term, Options, Chars) :-
|
||||
'$skip_max_list'(_, -1, Options, Options0),
|
||||
( var(Options0) ->
|
||||
throw(error(instantiation_error, write_term_to_chars/3))
|
||||
; nonvar(Chars) ->
|
||||
throw(error(uninstantiation_error(Chars), write_term_to_chars/3))
|
||||
; Options0 == [] ->
|
||||
true
|
||||
;
|
||||
throw(error(type_error(list, Options), write_term_to_chars/3))
|
||||
),
|
||||
builtins:inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)),
|
||||
builtins:inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
|
||||
builtins:inst_member_or(Options, quoted(Quoted), quoted(false)),
|
||||
builtins:inst_member_or(Options, variable_names(VarNames), variable_names([])),
|
||||
builtins:inst_member_or(Options, max_depth(MaxDepth), max_depth(0)),
|
||||
'$write_term_to_chars'(Term, IgnoreOps, NumberVars, Quoted, VarNames, MaxDepth, Chars).
|
||||
@@ -30,7 +30,8 @@
|
||||
:- use_module(library(between)).
|
||||
:- use_module(library(atts)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(non_iso)).
|
||||
:- use_module(library(iso_ext)).
|
||||
:- use_module(library(pairs)).
|
||||
:- use_module(library(dcgs)).
|
||||
:- use_module(library(error), []).
|
||||
|
||||
@@ -106,65 +107,10 @@ type_error(Expectation, Term) :-
|
||||
type_error(Expectation, Term, Goal-Arg) :-
|
||||
throw(error(type_error(Expectation, Term), type_error(Goal, Arg, Expectation, Term))).
|
||||
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
foldl/4
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
foldl(Goal_3, Ls, A0, A) :-
|
||||
foldl_(Ls, Goal_3, A0, A).
|
||||
|
||||
foldl_([], _, A, A).
|
||||
foldl_([L|Ls], G_3, A0, A) :-
|
||||
call(G_3, L, A0, A1),
|
||||
foldl_(Ls, G_3, A1, A).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
foldl/5
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
foldl(Goal_4, Xs, Ys, A0, A) :-
|
||||
foldl_(Xs, Ys, Goal_4, A0, A).
|
||||
|
||||
foldl_([], [], _, A, A).
|
||||
foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
|
||||
call(G_4, X, Y, A0, A1),
|
||||
foldl_(Xs, Ys, G_4, A1, A).
|
||||
|
||||
|
||||
partition(Pred, Ls0, As, Bs) :-
|
||||
include(Pred, Ls0, As),
|
||||
exclude(Pred, Ls0, Bs).
|
||||
|
||||
sum_list(Ls, S) :-
|
||||
foldl(sum_, Ls, 0, S).
|
||||
|
||||
sum_(L, S0, S) :- S is S0 + L.
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Pairs.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
pairs_keys_values([], [], []).
|
||||
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
|
||||
pairs_keys_values(ABs, As, Bs).
|
||||
|
||||
pairs_keys(Ps, Ks) :- pairs_keys_values(Ps, Ks, _).
|
||||
|
||||
pairs_values(Ps, Vs) :- pairs_keys_values(Ps, _, Vs).
|
||||
|
||||
map_list_to_pairs(Pred, Ls, Ps) :-
|
||||
map_list_to_pairs2(Ls, Pred, Ps).
|
||||
|
||||
map_list_to_pairs2([], _, []).
|
||||
map_list_to_pairs2([H|T0], Pred, [K-H|T]) :-
|
||||
call(Pred, H, K),
|
||||
map_list_to_pairs2(T0, Pred, T).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
goal_expansion(get_attr(Var, Module, Value), (var(Var),get_atts(Var, Access))) :-
|
||||
Access =.. [Module,Value].
|
||||
|
||||
@@ -728,10 +674,6 @@ existential(V, BDD, Node) :-
|
||||
Counter network for card(Is,Fs).
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
same_length([], []).
|
||||
same_length([_|As], [_|Bs]) :-
|
||||
same_length(As, Bs).
|
||||
|
||||
counter_network(Cs, Fs, Node) :-
|
||||
same_length([_|Fs], Indicators),
|
||||
fill_indicators(Indicators, 0, Cs),
|
||||
|
||||
7625
src/prolog/lib/clpz.pl
Normal file
7625
src/prolog/lib/clpz.pl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
||||
|
||||
:- module(cont, [reset/3, shift/1]).
|
||||
|
||||
reset(Goal, Ball, Cont) :-
|
||||
@@ -7,14 +6,14 @@ reset(Goal, Ball, Cont) :-
|
||||
'$bind_from_register'(Cont, 3),
|
||||
'$bind_from_register'(Ball, 4).
|
||||
|
||||
shift(Term) :-
|
||||
shift(Ball) :-
|
||||
'$nextEP'(first, E, P),
|
||||
get_chunks(E, P, L),
|
||||
( L == [] ->
|
||||
Cont = none
|
||||
; Cont = cont(call_continuation(L))
|
||||
),
|
||||
'$write_cont_and_term'(_, _, Cont, Term),
|
||||
'$write_cont_and_term'(_, _, Cont, Ball),
|
||||
'$unwind_environments'.
|
||||
|
||||
get_chunks(E, P, L) :-
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
% :- op(1105, xfy, ('|')).
|
||||
|
||||
:- module(dcgs, [op(1200, xfx, -->), phrase/2, phrase/3]).
|
||||
:- module(dcgs, [op(1200, xfx, -->),
|
||||
op(1105, xfy, '|'),
|
||||
phrase/2,
|
||||
phrase/3]).
|
||||
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(lists), [append/3]).
|
||||
|
||||
user:term_expansion(Term0, Term) :-
|
||||
@@ -31,8 +33,8 @@ phrase_((A -> B ; C), S0, S) :-
|
||||
).
|
||||
phrase_((A ; B), S0, S) :-
|
||||
( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
||||
%% phrase_((A | B), S0, S) :-
|
||||
%% ( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
||||
phrase_((A | B), S0, S) :-
|
||||
( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
||||
phrase_({G}, S0, S) :-
|
||||
( call(G), S0 = S ).
|
||||
phrase_(call(G), S0, S) :-
|
||||
@@ -95,7 +97,7 @@ dcg_constr([]). % 7.14.1
|
||||
dcg_constr([_|_]). % 7.14.2 - terminal sequence
|
||||
dcg_constr(( _, _ )). % 7.14.3 - concatenation
|
||||
dcg_constr(( _ ; _ )). % 7.14.4 - alternative
|
||||
%% dcg_constr(( _'|'_ )). % 7.14.6 - alternative
|
||||
dcg_constr(( _'|'_ )). % 7.14.6 - alternative
|
||||
dcg_constr({_}). % 7.14.7
|
||||
dcg_constr(call(_)). % 7.14.8
|
||||
dcg_constr(phrase(_)). % 7.14.9
|
||||
@@ -107,6 +109,7 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
|
||||
% the construct to be expanded.
|
||||
dcg_cbody([], S0, S, S0 = S).
|
||||
dcg_cbody([T|Ts], S0, S, Goal) :-
|
||||
must_be(list, [T|Ts]),
|
||||
dcg_terminals([T|Ts], S0, S, Goal).
|
||||
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
|
||||
dcg_body(GRFirst, S0, S1, First),
|
||||
@@ -119,9 +122,9 @@ dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
|
||||
subsumes_term(( _GRIf -> _GRThen ), GRCond),
|
||||
dcg_cbody(GRCond, S0, S, Cond),
|
||||
dcg_body(GRElse, S0, S, Else).
|
||||
%% dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
|
||||
%% dcg_body(GREither, S0, S, Either),
|
||||
%% dcg_body(GROr, S0, S, Or).
|
||||
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
|
||||
dcg_body(GREither, S0, S, Either),
|
||||
dcg_body(GROr, S0, S, Or).
|
||||
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
|
||||
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
|
||||
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
|
||||
|
||||
481
src/prolog/lib/format.pl
Normal file
481
src/prolog/lib/format.pl
Normal file
@@ -0,0 +1,481 @@
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Written March 2020 by Markus Triska (triska@metalevel.at)
|
||||
Part of Scryer Prolog.
|
||||
|
||||
This library provides the nonterminal format_//2 to describe
|
||||
formatted strings. format/2 is provided for impure output.
|
||||
|
||||
Usage:
|
||||
======
|
||||
|
||||
phrase(format_(FormatString, Arguments), Ls)
|
||||
|
||||
format_//2 describes a list of characters Ls that are formatted
|
||||
according to FormatString. FormatString is a string (i.e.,
|
||||
a list of characters) that specifies the layout of Ls.
|
||||
The characters in FormatString are used literally, except
|
||||
for the following tokens with special meaning:
|
||||
|
||||
~w use the next available argument from Arguments here
|
||||
~q use the next argument here, formatted as by writeq/1
|
||||
~a use the next argument here, which must be an atom
|
||||
~s use the next argument here, which must be a string
|
||||
~d use the next argument here, which must be an integer
|
||||
~f use the next argument here, a floating point number
|
||||
~Nf where N is an integer: format the float argument
|
||||
using N digits after the decimal point
|
||||
~Nd like ~d, placing the last N digits after a decimal point;
|
||||
if N is 0 or omitted, no decimal point is used.
|
||||
~ND like ~Nd, separating digits to the left of the decimal point
|
||||
in groups of three, using the character "," (comma)
|
||||
~N| where N is an integer: place a tab stop at text column N
|
||||
~N+ where N is an integer: place a tab stop N characters
|
||||
after the previous tab stop (or start of line)
|
||||
~t distribute spaces evenly between the two closest tab stops
|
||||
~`Ct like ~t, use character C instead of spaces to fill the space
|
||||
~n newline
|
||||
~Nn N newlines
|
||||
~i ignore the next argument
|
||||
~~ the literal ~
|
||||
|
||||
Instead of ~N, you can write ~* to use the next argument from Arguments
|
||||
as the numeric argument.
|
||||
|
||||
The predicate format/2 is like format_//2, except that it outputs
|
||||
the text on the terminal instead of describing it declaratively.
|
||||
|
||||
If at all possible, format_//2 should be used, to stress pure parts
|
||||
that enable easy testing etc. If necessary, you can emit the list Ls
|
||||
with maplist(write, Ls).
|
||||
|
||||
The entire library only works if the Prolog flag double_quotes
|
||||
is set to chars, the default value in Scryer Prolog. This should
|
||||
also stay that way, to encourage a sensible environment.
|
||||
|
||||
Example:
|
||||
|
||||
?- phrase(format_("~s~n~`.t~w!~12|", ["hello",there]), Cs).
|
||||
%@ Cs = [h,e,l,l,o,'\n','.','.','.','.','.','.',t,h,e,r,e,!]
|
||||
%@ ; false.
|
||||
|
||||
I place this code in the public domain. Use it in any way you want.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
:- module(format, [format_//2,
|
||||
format/2,
|
||||
portray_clause/1
|
||||
]).
|
||||
|
||||
:- use_module(library(dcgs)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(charsio)).
|
||||
|
||||
format_(Fs, Args) -->
|
||||
{ must_be(list, Fs),
|
||||
must_be(list, Args),
|
||||
phrase(cells(Fs,Args,0,[]), Cells) },
|
||||
format_cells(Cells).
|
||||
|
||||
format_cells([]) --> [].
|
||||
format_cells([Cell|Cells]) -->
|
||||
format_cell(Cell),
|
||||
format_cells(Cells).
|
||||
|
||||
format_cell(newline) --> "\n".
|
||||
format_cell(cell(From,To,Es)) -->
|
||||
% distribute the space between the glue elements
|
||||
{ phrase(elements_gluevars(Es, 0, Length), Vs),
|
||||
( Vs = [] -> true
|
||||
; Space is To - From - Length,
|
||||
( Space =< 0 -> maplist(=(0), Vs)
|
||||
; length(Vs, NumGlue),
|
||||
Distr is Space // NumGlue,
|
||||
Delta is Space - Distr*NumGlue,
|
||||
( Delta =:= 0 ->
|
||||
maplist(=(Distr), Vs)
|
||||
; BigGlue is Distr + Delta,
|
||||
reverse(Vs, [BigGlue|Rest]),
|
||||
maplist(=(Distr), Rest)
|
||||
)
|
||||
)
|
||||
) },
|
||||
format_elements(Es).
|
||||
|
||||
format_elements([]) --> [].
|
||||
format_elements([E|Es]) -->
|
||||
format_element(E),
|
||||
format_elements(Es).
|
||||
|
||||
format_element(chars(Cs)) --> list(Cs).
|
||||
format_element(glue(Fill,Num)) -->
|
||||
{ length(Ls, Num),
|
||||
maplist(=(Fill), Ls) },
|
||||
list(Ls).
|
||||
|
||||
list([]) --> [].
|
||||
list([L|Ls]) --> [L], list(Ls).
|
||||
|
||||
elements_gluevars([], N, N) --> [].
|
||||
elements_gluevars([E|Es], N0, N) -->
|
||||
element_gluevar(E, N0, N1),
|
||||
elements_gluevars(Es, N1, N).
|
||||
|
||||
element_gluevar(chars(Cs), N0, N) -->
|
||||
{ length(Cs, L),
|
||||
N is N0 + L }.
|
||||
element_gluevar(glue(_,V), N, N) --> [V].
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Our key datastructure is a list of cells and newlines.
|
||||
A cell has the shape from_to(From,To,Elements), where
|
||||
From and To denote the positions of surrounding tab stops.
|
||||
|
||||
Elements is a list of elements that occur in a cell,
|
||||
namely terms of the form chars(Cs) and glue(Char, Var).
|
||||
"glue" elements (TeX terminology) are evenly stretched
|
||||
to fill the remaining whitespace in the cell. For each
|
||||
glue element, the character Char is used for filling,
|
||||
and Var is a free variable that is used when the
|
||||
available space is distributed.
|
||||
|
||||
newline is used if ~n occurs in a format string.
|
||||
It is is used because a newline character does not
|
||||
consume whitespace in the sense of format strings.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
cells([], Args, Tab, Es) -->
|
||||
( { Args == [] } -> cell(Tab, Tab, Es)
|
||||
; { domain_error(no_remaining_arguments, Args) }
|
||||
).
|
||||
cells([~,~|Fs], Args, Tab, Es) --> !,
|
||||
cells(Fs, Args, Tab, [chars("~")|Es]).
|
||||
cells([~,w|Fs], [Arg|Args], Tab, Es) --> !,
|
||||
{ write_term_to_chars(Arg, [], Chars) },
|
||||
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
||||
cells([~,q|Fs], [Arg|Args], Tab, Es) --> !,
|
||||
{ write_term_to_chars(Arg, [quoted(true)], Chars) },
|
||||
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
||||
cells([~,a|Fs], [Arg|Args], Tab, Es) --> !,
|
||||
{ atom_chars(Arg, Chars) },
|
||||
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
||||
cells([~|Fs0], Args0, Tab, Es) -->
|
||||
{ numeric_argument(Fs0, Num, [d|Fs], Args0, [Arg|Args]) },
|
||||
!,
|
||||
{ number_chars(Arg, Cs0) },
|
||||
( { Num =:= 0 } -> { Cs = Cs0 }
|
||||
; { length(Cs0, L),
|
||||
( L =< Num ->
|
||||
Delta is Num - L,
|
||||
length(Zs, Delta),
|
||||
maplist(=('0'), Zs),
|
||||
phrase(("0.",list(Zs),list(Cs0)), Cs)
|
||||
; BeforeComma is L - Num,
|
||||
length(Bs, BeforeComma),
|
||||
append(Bs, Ds, Cs0),
|
||||
phrase((list(Bs),".",list(Ds)), Cs)
|
||||
) }
|
||||
),
|
||||
cells(Fs, Args, Tab, [chars(Cs)|Es]).
|
||||
cells([~|Fs0], Args0, Tab, Es) -->
|
||||
{ numeric_argument(Fs0, Num, ['D'|Fs], Args0, [Arg|Args]) },
|
||||
!,
|
||||
{ number_chars(Num, NCs),
|
||||
phrase(("~",list(NCs),"d"), FStr),
|
||||
phrase(format_(FStr, [Arg]), Cs0),
|
||||
phrase(upto_what(Bs0, .), Cs0, Ds),
|
||||
reverse(Bs0, Bs1),
|
||||
phrase(groups_of_three(Bs1), Bs2),
|
||||
reverse(Bs2, Bs),
|
||||
append(Bs, Ds, Cs) },
|
||||
cells(Fs, Args, Tab, [chars(Cs)|Es]).
|
||||
cells([~,i|Fs], [_|Args], Tab, Es) --> !,
|
||||
cells(Fs, Args, Tab, Es).
|
||||
cells([~,n|Fs], Args, Tab, Es) --> !,
|
||||
cell(Tab, Tab, Es),
|
||||
n_newlines(1),
|
||||
cells(Fs, Args, 0, []).
|
||||
cells([~|Fs0], Args0, Tab, Es) -->
|
||||
{ numeric_argument(Fs0, Num, [n|Fs], Args0, Args) },
|
||||
!,
|
||||
cell(Tab, Tab, Es),
|
||||
n_newlines(Num),
|
||||
cells(Fs, Args, 0, []).
|
||||
cells([~,s|Fs], [Arg|Args], Tab, Es) --> !,
|
||||
cells(Fs, Args, Tab, [chars(Arg)|Es]).
|
||||
cells([~,f|Fs], [Arg|Args], Tab, Es) --> !,
|
||||
{ number_chars(Arg, Chars) },
|
||||
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
||||
cells([~|Fs0], Args0, Tab, Es) -->
|
||||
{ numeric_argument(Fs0, Num, [f|Fs], Args0, [Arg|Args]) },
|
||||
!,
|
||||
{ number_chars(Arg, Cs0),
|
||||
phrase(upto_what(Bs, .), Cs0, Cs),
|
||||
( Num =:= 0 -> Chars = Bs
|
||||
; ( Cs = ['.'|Rest] ->
|
||||
length(Rest, L),
|
||||
( Num < L ->
|
||||
length(Ds, Num),
|
||||
append(Ds, _, Rest)
|
||||
; Num =:= L ->
|
||||
Ds = Rest
|
||||
; Num > L,
|
||||
Delta is Num - L,
|
||||
% we should look into the float with
|
||||
% greater accuracy here, and use the
|
||||
% actual digits instead of 0.
|
||||
length(Zs, Delta),
|
||||
maplist(=('0'), Zs),
|
||||
append(Rest, Zs, Ds)
|
||||
)
|
||||
; length(Ds, Num),
|
||||
maplist(=('0'), Ds)
|
||||
),
|
||||
append(Bs, ['.'|Ds], Chars)
|
||||
) },
|
||||
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
||||
cells([~,'`',Char,t|Fs], Args, Tab, Es) --> !,
|
||||
cells(Fs, Args, Tab, [glue(Char,_)|Es]).
|
||||
cells([~,t|Fs], Args, Tab, Es) --> !,
|
||||
cells(Fs, Args, Tab, [glue(' ',_)|Es]).
|
||||
cells([~|Fs0], Args0, Tab, Es) -->
|
||||
{ numeric_argument(Fs0, Num, ['|'|Fs], Args0, Args) },
|
||||
!,
|
||||
cell(Tab, Num, Es),
|
||||
cells(Fs, Args, Num, []).
|
||||
cells([~|Fs0], Args0, Tab0, Es) -->
|
||||
{ numeric_argument(Fs0, Num, [+|Fs], Args0, Args) },
|
||||
!,
|
||||
{ Tab is Tab0 + Num },
|
||||
cell(Tab0, Tab, Es),
|
||||
cells(Fs, Args, Tab, []).
|
||||
cells([~,C|_], _, _, _) -->
|
||||
{ atom_chars(A, [~,C]),
|
||||
domain_error(format_string, A) }.
|
||||
cells(Fs0, Args, Tab, Es) -->
|
||||
{ phrase(upto_what(Fs1, ~), Fs0, Fs),
|
||||
Fs1 = [_|_] },
|
||||
cells(Fs, Args, Tab, [chars(Fs1)|Es]).
|
||||
|
||||
domain_error(Type, Term) :-
|
||||
throw(error(domain_error(Type, Term), _)).
|
||||
|
||||
n_newlines(0) --> !.
|
||||
n_newlines(1) --> !, [newline].
|
||||
n_newlines(N0) --> { N0 > 1, N is N0 - 1 }, [newline], n_newlines(N).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
?- 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 = [].
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
upto_what([], W), [W] --> [W], !.
|
||||
upto_what([C|Cs], W) --> [C], !, upto_what(Cs, W).
|
||||
upto_what([], _) --> [].
|
||||
|
||||
groups_of_three([A,B,C,D|Rs]) --> !, [A,B,C], ",", groups_of_three([D|Rs]).
|
||||
groups_of_three(Ls) --> list(Ls).
|
||||
|
||||
cell(From, To, Es0) -->
|
||||
( { Es0 == [] } -> []
|
||||
; { reverse(Es0, Es) },
|
||||
[cell(From,To,Es)]
|
||||
).
|
||||
|
||||
%?- numeric_argument("2f", Num, ['f'|Fs], Args0, Args).
|
||||
|
||||
%?- numeric_argument("100b", Num, Rs, Args0, Args).
|
||||
|
||||
numeric_argument(Ds, Num, Rest, Args0, Args) :-
|
||||
( Ds = [*|Rest] ->
|
||||
Args0 = [Num|Args]
|
||||
; numeric_argument_(Ds, [], Ns, Rest),
|
||||
foldl(pow10, Ns, 0-0, Num-_),
|
||||
Args0 = Args
|
||||
).
|
||||
|
||||
numeric_argument_([D|Ds], Ns0, Ns, Rest) :-
|
||||
( member(D, "0123456789") ->
|
||||
number_chars(N, [D]),
|
||||
numeric_argument_(Ds, [N|Ns0], Ns, Rest)
|
||||
; Ns = Ns0,
|
||||
Rest = [D|Ds]
|
||||
).
|
||||
|
||||
|
||||
pow10(D, N0-Pow0, N-Pow) :-
|
||||
N is N0 + D*10^Pow0,
|
||||
Pow is Pow0 + 1.
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Impure I/O, implemented as a small wrapper over format_//2.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
format(Fs, Args) :-
|
||||
phrase(format_(Fs, Args), Cs),
|
||||
maplist(write, Cs).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
?- phrase(cells("hello", [], 0, []), Cs).
|
||||
|
||||
?- phrase(cells("hello~10|", [], 0, []), Cs).
|
||||
?- phrase(cells("~ta~t~10|", [], 0, []), Cs).
|
||||
|
||||
?- phrase(format_("~`at~50|", []), Ls).
|
||||
|
||||
?- phrase(cells("~`at~50|", [], 0, []), Cs),
|
||||
phrase(format_cells(Cs), Ls).
|
||||
?- phrase(cells("~ta~t~tb~tc~21|", [], 0, []), Cs).
|
||||
Cs = [cell(0,21,[glue(' ',_38),chars([a]),glue(' ',_62),glue(' ',_67),chars([b]),glue(' ',_91),chars([c])])].
|
||||
?- phrase(cells("~ta~t~4|", [], 0, []), Cs).
|
||||
Cs = [cell(0,4,[glue(' ',_38),chars([a]),glue(' ',_62)])].
|
||||
|
||||
?- phrase(format_cell(cell(0,1,[glue(a,_94)])), Ls).
|
||||
|
||||
?- phrase(format_cell(cell(0,50,[chars("hello")])), Ls).
|
||||
|
||||
?- phrase(format_("~`at~50|~n", []), Ls).
|
||||
?- phrase(format_("hello~n~tthere~6|", []), Ls).
|
||||
|
||||
?- format("~ta~t~4|", []).
|
||||
a true
|
||||
; false.
|
||||
|
||||
?- format("~ta~tb~tc~10|", []).
|
||||
a b ctrue
|
||||
; false.
|
||||
|
||||
?- format("~tabc~3|", []).
|
||||
|
||||
?- format("~ta~t~4|", []).
|
||||
|
||||
?- format("~ta~t~tb~tc~20|", []).
|
||||
a b ctrue
|
||||
; false.
|
||||
|
||||
?- format("~2f~n", [3]).
|
||||
3.00
|
||||
true
|
||||
|
||||
?- format("~20f", [0.1]).
|
||||
0.10000000000000000000true % this should use higher accuracy!
|
||||
; false.
|
||||
|
||||
?- X is atan(2), format("~7f~n", [X]).
|
||||
1.1071487
|
||||
X = 1.1071487177940906
|
||||
|
||||
?- format("~`at~50|~n", []).
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
true
|
||||
|
||||
?- format("~t~N", []).
|
||||
|
||||
?- format("~q", [.]).
|
||||
'.'true
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
We also provide a rudimentary version of portray_clause/1.
|
||||
|
||||
In the eventual library organization, portray_clause/1
|
||||
and related predicates (such as listing/1) may be placed
|
||||
in their own dedicated library.
|
||||
|
||||
portray_clause/1 is useful for printing solutions in such a way
|
||||
that they can be read back with read/1.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
portray_clause(Term) :-
|
||||
phrase(portray_clause_(Term), Ls),
|
||||
maplist(write, Ls).
|
||||
|
||||
portray_clause_(Term) -->
|
||||
portray_(Term), ".\n".
|
||||
|
||||
literal(Lit) --> format_("~q", [Lit]).
|
||||
|
||||
portray_(Var) --> { var(Var) }, !, literal(Var).
|
||||
portray_((Head :- Body)) --> !,
|
||||
literal(Head), " :-\n",
|
||||
body_(Body, 0, 8).
|
||||
portray_((Head --> Body)) --> !,
|
||||
literal(Head), " -->\n",
|
||||
body_(Body, 0, 8).
|
||||
portray_(Any) --> literal(Any).
|
||||
|
||||
|
||||
body_(Var, C, I) --> { var(Var) }, !,
|
||||
indent_to(C, I),
|
||||
literal(Var).
|
||||
body_((A,B), C, I) --> !,
|
||||
body_(A, C, I), ",\n",
|
||||
body_(B, 0, I).
|
||||
body_((A ; Else), C, I) --> % ( If -> Then ; Else )
|
||||
{ nonvar(A), A = (If -> Then) },
|
||||
!,
|
||||
indent_to(C, I),
|
||||
"( ",
|
||||
{ C1 is I + 3 },
|
||||
body_(If, C1, C1), " ->\n",
|
||||
body_(Then, 0, C1), "\n",
|
||||
else_branch(Else, C1, I).
|
||||
body_((A;B), C, I) --> !,
|
||||
indent_to(C, I),
|
||||
"( ",
|
||||
{ C1 is I + 3 },
|
||||
body_(A, C1, C1), "\n",
|
||||
else_branch(B, C1, I).
|
||||
body_(Goal, C, I) -->
|
||||
indent_to(C, I), literal(Goal).
|
||||
|
||||
|
||||
else_branch(Else, C, I) -->
|
||||
indent_to(0, I),
|
||||
";", " ", % (see #336)
|
||||
body_(Else, C, C), "\n",
|
||||
indent_to(0, I),
|
||||
")".
|
||||
|
||||
indent_to(CurrentColumn, Indent) -->
|
||||
{ Delta is Indent - CurrentColumn },
|
||||
format_("~t~*|", [Delta]).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
?- portray_clause(a), nl.
|
||||
a.
|
||||
|
||||
?- nl, portray_clause((a :- b)), nl.
|
||||
a :-
|
||||
b.
|
||||
|
||||
?- nl, portray_clause((a :- b, c, d)), nl.
|
||||
a :-
|
||||
b,
|
||||
c,
|
||||
d.
|
||||
|
||||
|
||||
?- nl, portray_clause([a,b,c,d]), nl.
|
||||
"abcd".
|
||||
|
||||
?- nl, portray_clause(X).
|
||||
?- nl, portray_clause((f(X) :- X)).
|
||||
|
||||
?- nl, portray_clause((h :- ( a -> b; c))).
|
||||
|
||||
?- nl, portray_clause((h :- ( (a -> x ; y) -> b; c))).
|
||||
|
||||
?- nl, portray_clause((h(X) :- ( (a(X) ; y(A,B)) -> b; c))).
|
||||
|
||||
?- nl, portray_clause((h :- (a,d;b,c) ; (b,e;d))).
|
||||
|
||||
?- nl, portray_clause((a :- b ; c ; d)).
|
||||
|
||||
?- nl, portray_clause((h :- L = '.')).
|
||||
|
||||
?- nl, portray_clause(-->(a, (b, {t}, d))).
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(non_iso)).
|
||||
:- use_module(library(iso_ext)).
|
||||
:- use_module(library(si)).
|
||||
|
||||
gensym_key(Base, BaseKey) :-
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
%% for builtins that are not part of the ISO standard.
|
||||
%% must be loaded at the REPL with
|
||||
|
||||
%% ?- use_module(library(non_iso)).
|
||||
%% ?- use_module(library(iso_ext)).
|
||||
|
||||
:- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
|
||||
:- module(iso_ext, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
|
||||
call_with_inference_limit/3, forall/2, maybe/0,
|
||||
partial_string/1, partial_string/3,
|
||||
partial_string_tail/2, set_random/1,
|
||||
@@ -157,13 +157,15 @@ set_random(Seed) :-
|
||||
; throw(error(instantiation_error, set_random/1))
|
||||
).
|
||||
|
||||
|
||||
partial_string(String, L, L0) :-
|
||||
( String == [] -> throw(error(type_error(list, []), partial_string/3))
|
||||
( String == [] ->
|
||||
L = L0
|
||||
; catch(atom_chars(Atom, String),
|
||||
error(E, _),
|
||||
throw(error(E, partial_string/3)))
|
||||
),
|
||||
'$create_partial_string'(Atom, L, L0).
|
||||
throw(error(E, partial_string/3))),
|
||||
'$create_partial_string'(Atom, L, L0)
|
||||
).
|
||||
|
||||
partial_string(String) :-
|
||||
'$is_partial_string'(String).
|
||||
@@ -1,8 +1,8 @@
|
||||
:- module(lists, [member/2, select/3, append/3, foldl/4, foldl/5,
|
||||
:- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5,
|
||||
memberchk/2, reverse/2, length/2, maplist/2,
|
||||
maplist/3, maplist/4, maplist/5, maplist/6,
|
||||
maplist/7, maplist/8, maplist/9, same_length/2,
|
||||
sumlist/2]).
|
||||
sum_list/2, transpose/2]).
|
||||
|
||||
|
||||
:- use_module(library(error)).
|
||||
@@ -44,6 +44,12 @@ select(X, [X|Xs], Xs).
|
||||
select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
|
||||
|
||||
|
||||
append([], []).
|
||||
append([L0|Ls0], Ls) :-
|
||||
append(L0, Rest, Ls),
|
||||
append(Ls0, Rest).
|
||||
|
||||
|
||||
append([], R, R).
|
||||
append([X|L], R, [X|S]) :- append(L, R, S).
|
||||
|
||||
@@ -102,14 +108,10 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7
|
||||
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s, E8s).
|
||||
|
||||
|
||||
sumlist_([], S, S).
|
||||
sumlist_([N|Ns], S, S0) :-
|
||||
S1 is S0 + N,
|
||||
sumlist_(Ns, S, S1).
|
||||
sum_list(Ls, S) :-
|
||||
foldl(sum_, Ls, 0, S).
|
||||
|
||||
sumlist(Ns, S) :-
|
||||
must_be(list, Ns),
|
||||
sumlist_(Ns, S, 0).
|
||||
sum_(L, S0, S) :- S is S0 + L.
|
||||
|
||||
|
||||
|
||||
@@ -134,3 +136,16 @@ foldl_([], [], _, A, A).
|
||||
foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
|
||||
call(G_4, X, Y, A0, A1),
|
||||
foldl_(Xs, Ys, G_4, A1, A).
|
||||
|
||||
transpose(Ls, Ts) :-
|
||||
lists_transpose(Ls, Ts).
|
||||
|
||||
lists_transpose([], []).
|
||||
lists_transpose([L|Ls], Ts) :-
|
||||
maplist(same_length(L), Ls),
|
||||
foldl(transpose_, L, Ts, [L|Ls], _).
|
||||
|
||||
transpose_(_, Fs, Lists0, Lists) :-
|
||||
maplist(list_first_rest, Lists0, Fs, Lists).
|
||||
|
||||
list_first_rest([L|Ls], L, Ls).
|
||||
|
||||
21
src/prolog/lib/pairs.pl
Normal file
21
src/prolog/lib/pairs.pl
Normal file
@@ -0,0 +1,21 @@
|
||||
:- module(pairs, [pairs_keys_values/3,
|
||||
pairs_keys/2,
|
||||
pairs_values/2,
|
||||
map_list_to_pairs/3]).
|
||||
|
||||
|
||||
pairs_keys_values([], [], []).
|
||||
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
|
||||
pairs_keys_values(ABs, As, Bs).
|
||||
|
||||
pairs_keys(Ps, Ks) :- pairs_keys_values(Ps, Ks, _).
|
||||
|
||||
pairs_values(Ps, Vs) :- pairs_keys_values(Ps, _, Vs).
|
||||
|
||||
map_list_to_pairs(Pred, Ls, Ps) :-
|
||||
map_list_to_pairs2(Ls, Pred, Ps).
|
||||
|
||||
map_list_to_pairs2([], _, []).
|
||||
map_list_to_pairs2([H|T0], Pred, [K-H|T]) :-
|
||||
call(Pred, H, K),
|
||||
map_list_to_pairs2(T0, Pred, T).
|
||||
@@ -18,7 +18,7 @@
|
||||
:- use_module(library(cont)).
|
||||
:- use_module(library(lists)).
|
||||
%:- use_module(library(debug)).
|
||||
:- use_module(library(non_iso)).
|
||||
:- use_module(library(iso_ext)).
|
||||
|
||||
%% :- meta_predicate
|
||||
%% start_tabling(+, 0).
|
||||
|
||||
@@ -208,4 +208,3 @@ dll_get_reverse_contents_(List, Contents) :-
|
||||
dll_get_pointer_to_previous(List, Prev),
|
||||
dll_get_reverse_contents_(Prev, Rest)
|
||||
).
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
]).
|
||||
|
||||
:- use_module(library(atts)).
|
||||
:- use_module(library(non_iso)).
|
||||
:- use_module(library(iso_ext)).
|
||||
|
||||
:- attribute table_global_worklist/1.
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
:- use_module(library(atts)).
|
||||
:- use_module(library(gensym)).
|
||||
:- use_module(library(non_iso)).
|
||||
:- use_module(library(iso_ext)).
|
||||
|
||||
:- attribute table_status/1, newly_created_table_identifiers/1.
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
:- use_module(library(atts)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(non_iso)).
|
||||
:- use_module(library(iso_ext)).
|
||||
:- use_module(library(terms)).
|
||||
|
||||
:- use_module(trie).
|
||||
|
||||
1211
src/prolog/machine/arithmetic_ops.rs
Normal file
1211
src/prolog/machine/arithmetic_ops.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
driver(Vars, Values) :-
|
||||
iterate(Vars, Values, ListOfListsOfGoalLists),
|
||||
'$clear_attr_var_bindings',
|
||||
!,
|
||||
call_goals(ListOfListsOfGoalLists),
|
||||
'$return_from_verify_attr'.
|
||||
@@ -17,13 +16,6 @@ gather_modules([Attr|Attrs], [Module|Modules]) :-
|
||||
'$module_of'(Module, Attr), % write the owning module of Attr to Module.
|
||||
gather_modules(Attrs, Modules).
|
||||
|
||||
verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
|
||||
catch(Module:verify_attributes(Var, Value, Goals),
|
||||
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
|
||||
Goals = []),
|
||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||
verify_attrs([], _, _, []).
|
||||
|
||||
call_verify_attributes(Attrs, _, _, []) :-
|
||||
var(Attrs), !.
|
||||
call_verify_attributes([], _, _, []).
|
||||
@@ -32,6 +24,13 @@ call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
|
||||
sort(Modules0, Modules),
|
||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||
|
||||
verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
|
||||
catch(Module:verify_attributes(Var, Value, Goals),
|
||||
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
|
||||
Goals = []),
|
||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||
verify_attrs([], _, _, []).
|
||||
|
||||
call_goals([ListOfGoalLists | ListsCubed]) :-
|
||||
call_goals_0(ListOfGoalLists),
|
||||
call_goals(ListsCubed).
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::prolog::machine::*;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::vec::IntoIter;
|
||||
|
||||
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
|
||||
@@ -18,7 +19,8 @@ pub(super) struct AttrVarInitializer {
|
||||
}
|
||||
|
||||
impl AttrVarInitializer {
|
||||
pub(super) fn new(verify_attrs_loc: usize, project_attrs_loc: usize) -> Self {
|
||||
pub(super)
|
||||
fn new(verify_attrs_loc: usize, project_attrs_loc: usize) -> Self {
|
||||
AttrVarInitializer {
|
||||
attribute_goals: vec![],
|
||||
attr_var_queue: vec![],
|
||||
@@ -31,21 +33,24 @@ impl AttrVarInitializer {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn reset(&mut self) {
|
||||
pub(super)
|
||||
fn reset(&mut self) {
|
||||
self.attribute_goals.clear();
|
||||
self.attr_var_queue.clear();
|
||||
self.bindings.clear();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn backtrack(&mut self, queue_b: usize, bindings_b: usize) {
|
||||
pub(super)
|
||||
fn backtrack(&mut self, queue_b: usize, bindings_b: usize) {
|
||||
self.attr_var_queue.truncate(queue_b);
|
||||
self.bindings.truncate(bindings_b);
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
|
||||
pub(super)
|
||||
fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
|
||||
if self.attr_var_init.bindings.is_empty() {
|
||||
self.attr_var_init.instigating_p = self.p.local();
|
||||
|
||||
@@ -66,18 +71,17 @@ impl MachineState {
|
||||
.attr_var_init
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|(ref h, _)| Addr::AttrVar(*h));
|
||||
.map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h)));
|
||||
|
||||
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||
|
||||
let iter = self
|
||||
.attr_var_init
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|(_, ref addr)| addr.clone());
|
||||
.drain(0 ..)
|
||||
.map(|(_, addr)| HeapCellValue::Addr(addr));
|
||||
|
||||
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||
|
||||
(var_list_addr, value_list_addr)
|
||||
}
|
||||
|
||||
@@ -92,7 +96,8 @@ impl MachineState {
|
||||
self[temp_v!(2)] = value_list_addr;
|
||||
}
|
||||
|
||||
pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
|
||||
pub(super)
|
||||
fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
|
||||
let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..]
|
||||
.iter()
|
||||
.filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) {
|
||||
@@ -101,13 +106,16 @@ impl MachineState {
|
||||
})
|
||||
.collect();
|
||||
|
||||
attr_vars.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2));
|
||||
attr_vars.sort_unstable_by(|a1, a2| {
|
||||
self.compare_term_test(a1, a2).unwrap_or(Ordering::Less)
|
||||
});
|
||||
|
||||
self.term_dedup(&mut attr_vars);
|
||||
attr_vars.into_iter()
|
||||
}
|
||||
|
||||
pub(super) fn verify_attr_interrupt(&mut self, p: usize) {
|
||||
pub(super)
|
||||
fn verify_attr_interrupt(&mut self, p: usize) {
|
||||
self.allocate(self.num_of_args + 2);
|
||||
|
||||
let e = self.e;
|
||||
@@ -118,9 +126,9 @@ impl MachineState {
|
||||
}
|
||||
|
||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
|
||||
Addr::Con(Constant::CutPoint(self.b0));
|
||||
Addr::CutPoint(self.b0);
|
||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
|
||||
Addr::Con(Constant::Usize(self.num_of_args));
|
||||
Addr::Usize(self.num_of_args);
|
||||
|
||||
self.verify_attributes();
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ use ref_thread_local::RefThreadLocal;
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::mem;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -60,9 +59,9 @@ fn fix_filename(
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn load_module<R: Read>(
|
||||
fn load_module(
|
||||
wam: &mut Machine,
|
||||
stream: ParsingStream<R>,
|
||||
stream: Stream,
|
||||
suppress_warnings: bool,
|
||||
listing_src: &ListingSource,
|
||||
) -> Result<ClauseName, SessionError> {
|
||||
@@ -78,7 +77,11 @@ fn load_module<R: Read>(
|
||||
listing_src.clone(),
|
||||
);
|
||||
|
||||
let results = compiler.gather_items(wam, stream, &mut indices);
|
||||
let results = compiler.gather_items(
|
||||
wam,
|
||||
&mut parsing_stream(stream),
|
||||
&mut indices,
|
||||
);
|
||||
|
||||
let module_name = if let Some(ref module) = &compiler.module {
|
||||
module.module_decl.name.clone()
|
||||
@@ -114,14 +117,14 @@ fn load_module_from_file(
|
||||
let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?;
|
||||
let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl);
|
||||
|
||||
let file_handle = File::open(&path_buf).or_else(|_| {
|
||||
let file_handle = Stream::from(File::open(&path_buf).or_else(|_| {
|
||||
Err(SessionError::InvalidFileName(filename.clone()))
|
||||
})?;
|
||||
})?);
|
||||
|
||||
path_buf.pop();
|
||||
|
||||
let listing_src = ListingSource::from_file_and_path(filename, path_buf);
|
||||
load_module(wam, parsing_stream(file_handle), suppress_warnings, &listing_src)
|
||||
load_module(wam, file_handle, suppress_warnings, &listing_src)
|
||||
}
|
||||
|
||||
pub type PredicateCompileQueue = (Predicate, VecDeque<TopLevel>);
|
||||
@@ -320,10 +323,11 @@ fn setup_module_expansions(wam: &mut Machine, module: &Module) {
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn compile_into_module<R: Read>(
|
||||
pub(super)
|
||||
fn compile_into_module(
|
||||
wam: &mut Machine,
|
||||
module_name: ClauseName,
|
||||
src: ParsingStream<R>,
|
||||
src: Stream,
|
||||
name: ClauseName,
|
||||
) -> EvalSession {
|
||||
let mut indices = default_index_store!(wam.atom_tbl_of(&name));
|
||||
@@ -333,7 +337,11 @@ pub(super) fn compile_into_module<R: Read>(
|
||||
indices.op_dir = module.op_dir.clone();
|
||||
indices.atom_tbl = module.atom_tbl.clone();
|
||||
|
||||
let mut compiler = ListingCompiler::new(&wam.code_repo, true, module.listing_src.clone());
|
||||
let mut compiler = ListingCompiler::new(
|
||||
&wam.code_repo,
|
||||
true,
|
||||
module.listing_src.clone(),
|
||||
);
|
||||
|
||||
match compile_into_module_impl(wam, &mut compiler, module, src, indices) {
|
||||
Ok(()) => EvalSession::EntrySuccess,
|
||||
@@ -348,11 +356,11 @@ pub(super) fn compile_into_module<R: Read>(
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_into_module_impl<R: Read>(
|
||||
fn compile_into_module_impl(
|
||||
wam: &mut Machine,
|
||||
compiler: &mut ListingCompiler,
|
||||
module: Module,
|
||||
src: ParsingStream<R>,
|
||||
src: Stream,
|
||||
mut indices: IndexStore,
|
||||
) -> Result<(), SessionError> {
|
||||
setup_module_expansions(wam, &module);
|
||||
@@ -363,7 +371,11 @@ fn compile_into_module_impl<R: Read>(
|
||||
wam.code_repo.compile_hook(CompileTimeHook::TermExpansion)?;
|
||||
wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion)?;
|
||||
|
||||
let mut results = compiler.gather_items(wam, src, &mut indices)?;
|
||||
let mut results = compiler.gather_items(
|
||||
wam,
|
||||
&mut parsing_stream(src),
|
||||
&mut indices,
|
||||
)?;
|
||||
|
||||
compiler.adapt_in_situ_code(
|
||||
results.worker_results,
|
||||
@@ -392,7 +404,6 @@ fn compile_into_module_impl<R: Read>(
|
||||
);
|
||||
|
||||
wam.code_repo.code.extend(results.in_situ_code.into_iter());
|
||||
|
||||
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
|
||||
|
||||
Ok(compiler.drop_expansions(&mut wam.code_repo))
|
||||
@@ -548,8 +559,8 @@ fn add_module(
|
||||
term_dir: TermDir,
|
||||
) {
|
||||
module.code_dir.extend(indices.code_dir);
|
||||
module.op_dir.extend(indices.op_dir.into_iter());
|
||||
module.term_dir.extend(term_dir.into_iter());
|
||||
module.op_dir.extend(indices.op_dir);
|
||||
module.term_dir.extend(term_dir);
|
||||
|
||||
wam.add_in_situ_module_dir(indices.module_dir);
|
||||
wam.add_module(module);
|
||||
@@ -568,7 +579,7 @@ fn add_non_module_code(
|
||||
clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?;
|
||||
|
||||
add_toplevel(wam, indices, term_dir);
|
||||
wam.code_repo.code.extend(code.into_iter());
|
||||
wam.code_repo.code.extend(code);
|
||||
clause_code_generator.add_clause_code(wam, dynamic_clause_map);
|
||||
|
||||
Ok(())
|
||||
@@ -591,12 +602,18 @@ fn load_library(
|
||||
|
||||
load_module(
|
||||
wam,
|
||||
parsing_stream(code.as_bytes()),
|
||||
Stream::from(*code),
|
||||
suppress_warnings,
|
||||
&listing_src,
|
||||
)
|
||||
}
|
||||
None => Err(SessionError::ModuleNotFound)
|
||||
None => {
|
||||
let err = ExistenceError::SourceSink(ModuleSource::Library(
|
||||
name.clone()
|
||||
));
|
||||
|
||||
Err(SessionError::ExistenceError(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,7 +699,11 @@ impl ListingCompiler {
|
||||
|
||||
Ok(wam_indices.insert_module(submodule))
|
||||
} else {
|
||||
Err(SessionError::ModuleNotFound)
|
||||
let err = ExistenceError::SourceSink(ModuleSource::File(
|
||||
module_name,
|
||||
));
|
||||
|
||||
Err(SessionError::ExistenceError(err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,7 +737,11 @@ impl ListingCompiler {
|
||||
|
||||
Ok(wam_indices.insert_module(submodule))
|
||||
} else {
|
||||
Err(SessionError::ModuleNotFound)
|
||||
let err = ExistenceError::SourceSink(ModuleSource::File(
|
||||
module_name
|
||||
));
|
||||
|
||||
Err(SessionError::ExistenceError(err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,6 +993,10 @@ impl ListingCompiler {
|
||||
Declaration::Op(op_decl) => {
|
||||
self.submit_op(wam, indices, &op_decl)
|
||||
}
|
||||
Declaration::SetPrologFlag(dbl_quotes) => {
|
||||
wam.machine_st.flags.double_quotes = dbl_quotes;
|
||||
Ok(())
|
||||
}
|
||||
Declaration::UseModule(ModuleSource::Library(name)) => {
|
||||
let name = if !wam.indices.modules.contains_key(&name) {
|
||||
load_library(wam, name, true)?
|
||||
@@ -1018,10 +1047,10 @@ impl ListingCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_multifile_decl<R: Read>(
|
||||
fn setup_multifile_decl(
|
||||
&self,
|
||||
indicator: MultiFileIndicator,
|
||||
worker: &mut TopLevelBatchWorker<R>,
|
||||
worker: &mut TopLevelBatchWorker,
|
||||
) -> Result<(), SessionError> {
|
||||
match indicator {
|
||||
MultiFileIndicator::LocalScoped(name, arity) => {
|
||||
@@ -1042,7 +1071,11 @@ impl ListingCompiler {
|
||||
insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs);
|
||||
}
|
||||
None => {
|
||||
return Err(SessionError::ModuleNotFound);
|
||||
let err = ExistenceError::SourceSink(ModuleSource::File(
|
||||
module_name,
|
||||
));
|
||||
|
||||
return Err(SessionError::ExistenceError(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1051,10 +1084,10 @@ impl ListingCompiler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_and_commit_decl<R: Read>(
|
||||
fn process_and_commit_decl(
|
||||
&mut self,
|
||||
decl: Declaration,
|
||||
worker: &mut TopLevelBatchWorker<R>,
|
||||
worker: &mut TopLevelBatchWorker,
|
||||
indices: &mut IndexStore,
|
||||
flags: MachineFlags,
|
||||
) -> Result<(), SessionError> {
|
||||
@@ -1101,15 +1134,15 @@ impl ListingCompiler {
|
||||
result
|
||||
}
|
||||
|
||||
pub(crate) fn gather_items<R: Read>(
|
||||
pub(crate) fn gather_items(
|
||||
&mut self,
|
||||
wam: &mut Machine,
|
||||
mut src: ParsingStream<R>,
|
||||
src: &mut ParsingStream<Stream>,
|
||||
indices: &mut IndexStore,
|
||||
) -> Result<GatherResult, SessionError> {
|
||||
let flags = wam.machine_flags();
|
||||
let atom_tbl = indices.atom_tbl.clone();
|
||||
let mut worker = TopLevelBatchWorker::new(&mut src, atom_tbl.clone(), flags, wam);
|
||||
let mut worker = TopLevelBatchWorker::new(src, atom_tbl.clone(), flags, wam);
|
||||
|
||||
let mut toplevel_results = vec![];
|
||||
let mut toplevel_indices = default_index_store!(atom_tbl.clone());
|
||||
@@ -1302,28 +1335,32 @@ fn compile_work_impl(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_work<R: Read>(
|
||||
fn compile_work(
|
||||
compiler: &mut ListingCompiler,
|
||||
wam: &mut Machine,
|
||||
src: ParsingStream<R>,
|
||||
src: Stream,
|
||||
mut indices: IndexStore,
|
||||
) -> EvalSession {
|
||||
let src = &mut parsing_stream(src);
|
||||
let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
|
||||
|
||||
try_eval_session!(compile_work_impl(compiler, wam, indices, results));
|
||||
|
||||
EvalSession::EntrySuccess
|
||||
}
|
||||
|
||||
/* This is a truncated version of compile_user_module, used for
|
||||
compiling code composing special forms, ie. the code that calls
|
||||
M:verify_attributes on attributed variables. */
|
||||
pub fn compile_special_form<R: Read>(
|
||||
pub fn compile_special_form(
|
||||
wam: &mut Machine,
|
||||
src: ParsingStream<R>,
|
||||
src: Stream,
|
||||
listing_src: ListingSource,
|
||||
) -> Result<usize, SessionError> {
|
||||
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
|
||||
setup_indices(wam, clause_name!("builtins"), &mut indices)?;
|
||||
|
||||
let src = &mut parsing_stream(src);
|
||||
let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src);
|
||||
let mut results = compiler.gather_items(wam, src, &mut indices)?;
|
||||
|
||||
@@ -1348,9 +1385,9 @@ pub fn compile_special_form<R: Read>(
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn compile_listing<R: Read>(
|
||||
pub fn compile_listing(
|
||||
wam: &mut Machine,
|
||||
src: ParsingStream<R>,
|
||||
src: Stream,
|
||||
indices: IndexStore,
|
||||
suppress_warnings: bool,
|
||||
listing_src: ListingSource,
|
||||
@@ -1373,20 +1410,24 @@ pub(super) fn setup_indices(
|
||||
module: ClauseName,
|
||||
indices: &mut IndexStore,
|
||||
) -> Result<(), SessionError> {
|
||||
if let Some(module) = wam.indices.take_module(module) {
|
||||
if let Some(module) = wam.indices.take_module(module.clone()) {
|
||||
let flags = wam.machine_flags();
|
||||
let result = indices.use_module(&mut wam.code_repo, flags, &module);
|
||||
|
||||
wam.indices.insert_module(module);
|
||||
result
|
||||
} else {
|
||||
Err(SessionError::ModuleNotFound)
|
||||
let err = ExistenceError::SourceSink(ModuleSource::Library(
|
||||
module
|
||||
));
|
||||
|
||||
Err(SessionError::ExistenceError(err))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_user_module<R: Read>(
|
||||
pub fn compile_user_module(
|
||||
wam: &mut Machine,
|
||||
src: ParsingStream<R>,
|
||||
src: Stream,
|
||||
suppress_warnings: bool,
|
||||
listing_src: ListingSource,
|
||||
) -> EvalSession {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
use crate::prolog::machine::stack::*;
|
||||
use crate::prolog::machine::streams::*;
|
||||
|
||||
use std::mem;
|
||||
use std::ops::IndexMut;
|
||||
|
||||
type Trail = Vec<(Ref, HeapCellValue)>;
|
||||
@@ -11,12 +13,13 @@ pub enum AttrVarPolicy {
|
||||
StripAttributes
|
||||
}
|
||||
|
||||
pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
||||
fn threshold(&self) -> usize;
|
||||
fn push(&mut self, val: HeapCellValue);
|
||||
fn store(&self, val: Addr) -> Addr;
|
||||
pub(crate)
|
||||
trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
||||
fn deref(&self, val: Addr) -> Addr;
|
||||
fn push(&mut self, val: HeapCellValue);
|
||||
fn stack(&mut self) -> &mut Stack;
|
||||
fn store(&self, val: Addr) -> Addr;
|
||||
fn threshold(&self) -> usize;
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
@@ -30,13 +33,13 @@ struct CopyTermState<T: CopierTarget> {
|
||||
scan: usize,
|
||||
old_h: usize,
|
||||
target: T,
|
||||
attr_var_policy: AttrVarPolicy
|
||||
attr_var_policy: AttrVarPolicy,
|
||||
}
|
||||
|
||||
impl<T: CopierTarget> CopyTermState<T> {
|
||||
fn new(target: T, attr_var_policy: AttrVarPolicy) -> Self {
|
||||
CopyTermState {
|
||||
trail: vec![],
|
||||
trail: Trail::new(),
|
||||
scan: 0,
|
||||
old_h: target.threshold(),
|
||||
target,
|
||||
@@ -50,152 +53,99 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
&mut self.target[scan]
|
||||
}
|
||||
|
||||
fn copied_list(&mut self, addr: usize) -> bool {
|
||||
match &self.target[addr] {
|
||||
HeapCellValue::Addr(Addr::Lis(addr)) | HeapCellValue::Addr(Addr::HeapCell(addr)) => {
|
||||
if *addr >= self.old_h {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(*addr));
|
||||
self.scan += 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
|
||||
let trail_item = mem::replace(
|
||||
&mut self.target[addr],
|
||||
HeapCellValue::Addr(Addr::Lis(threshold)),
|
||||
);
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn copied_partial_string(&mut self, addr: usize) -> bool {
|
||||
if let HeapCellValue::PartialString(ref pstr) = &self.target[addr] {
|
||||
if let Addr::PStrLocation(h, n) = pstr.tail_addr() {
|
||||
if *h >= self.old_h {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(*h, *n));
|
||||
self.scan += 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
self.trail.push((
|
||||
Ref::HeapCell(addr),
|
||||
trail_item,
|
||||
));
|
||||
}
|
||||
|
||||
fn copy_list(&mut self, addr: usize) {
|
||||
if self.copied_list(addr) {
|
||||
for offset in 0 .. 2 {
|
||||
if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h));
|
||||
self.scan += 1;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
|
||||
|
||||
let ra = self.target[addr].as_addr(threshold);
|
||||
let rd = self.target.store(self.target.deref(ra.clone()));
|
||||
|
||||
self.target.push(HeapCellValue::Addr(ra.clone()));
|
||||
|
||||
let hcv = HeapCellValue::Addr(self.target[addr + 1].as_addr(addr + 1));
|
||||
|
||||
for i in 0 .. 2 {
|
||||
let hcv = self.target[addr + i].context_free_clone();
|
||||
self.target.push(hcv);
|
||||
|
||||
match rd.clone() {
|
||||
Addr::AttrVar(h) | Addr::HeapCell(h) | Addr::PStrTail(h, _)
|
||||
if h >= self.old_h => {
|
||||
self.target[threshold] = HeapCellValue::Addr(rd)
|
||||
}
|
||||
var @ Addr::AttrVar(_)
|
||||
| var @ Addr::HeapCell(..)
|
||||
| var @ Addr::StackCell(..)
|
||||
| var @ Addr::PStrTail(..) => {
|
||||
if ra == rd {
|
||||
self.reinstantiate_var(var, threshold);
|
||||
|
||||
if let AttrVarPolicy::StripAttributes = self.attr_var_policy {
|
||||
self.trail.push((Ref::HeapCell(addr), HeapCellValue::Addr(ra)));
|
||||
self.target[addr] = HeapCellValue::Addr(Addr::HeapCell(threshold));
|
||||
}
|
||||
let cdr = self.target.store(self.target.deref(Addr::HeapCell(addr + 1)));
|
||||
|
||||
if !cdr.is_ref() {
|
||||
self.trail_list_cell(addr + 1, threshold);
|
||||
} else {
|
||||
self.target[threshold] = HeapCellValue::Addr(ra);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.trail.push((
|
||||
Ref::HeapCell(addr),
|
||||
HeapCellValue::Addr(self.target[addr].as_addr(addr)),
|
||||
));
|
||||
let car = self.target.store(self.target.deref(Addr::HeapCell(addr)));
|
||||
|
||||
self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold))
|
||||
if !car.is_ref() {
|
||||
self.trail_list_cell(addr, threshold);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.scan += 1;
|
||||
}
|
||||
|
||||
|
||||
fn copy_partial_string(&mut self, addr: usize, n: usize) {
|
||||
let threshold = self.target.threshold();
|
||||
if let &HeapCellValue::Addr(Addr::PStrLocation(h, _)) = &self.target[addr] {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, n));
|
||||
self.scan += 1;
|
||||
|
||||
let tail_addr =
|
||||
match &self.target[addr] {
|
||||
HeapCellValue::PartialString(ref pstr) => {
|
||||
self.trail.push((
|
||||
Ref::PStrTail(addr, 0),
|
||||
HeapCellValue::Addr(pstr.tail.clone()),
|
||||
));
|
||||
|
||||
self.target.store(self.target.deref(pstr.tail.clone()))
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
let pstr =
|
||||
match &mut self.target[addr] {
|
||||
HeapCellValue::PartialString(ref mut pstr) => {
|
||||
let mut new_pstr = pstr.clone_from_offset(n);
|
||||
|
||||
if let Addr::PStrTail(h, n) = &tail_addr {
|
||||
new_pstr.tail = if *h == addr {
|
||||
Addr::PStrTail(threshold, *n)
|
||||
} else {
|
||||
Addr::HeapCell(threshold + 1)
|
||||
};
|
||||
} else {
|
||||
new_pstr.tail = Addr::HeapCell(threshold + 1);
|
||||
}
|
||||
|
||||
pstr.tail = Addr::PStrLocation(threshold, 0);
|
||||
new_pstr
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
match tail_addr {
|
||||
Addr::PStrTail(h, _) if h == addr => {
|
||||
self.target.push(HeapCellValue::PartialString(pstr));
|
||||
}
|
||||
addr => {
|
||||
self.target.push(HeapCellValue::PartialString(pstr));
|
||||
self.target.push(HeapCellValue::Addr(addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_partial_string_from(&mut self, addr: usize, n: usize) {
|
||||
if self.copied_partial_string(addr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
self.target[self.scan] =
|
||||
HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
|
||||
*self.value_at_scan() =
|
||||
HeapCellValue::Addr(Addr::PStrLocation(threshold, 0));
|
||||
|
||||
self.scan += 1;
|
||||
|
||||
self.copy_partial_string(addr, n);
|
||||
let (pstr, has_tail) =
|
||||
match &self.target[addr] {
|
||||
&HeapCellValue::PartialString(ref pstr, has_tail) => {
|
||||
(pstr.clone_from_offset(n), has_tail)
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
self.target.push(HeapCellValue::PartialString(pstr, has_tail));
|
||||
|
||||
let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, 0));
|
||||
|
||||
let trail_item = mem::replace(
|
||||
&mut self.target[addr],
|
||||
replacement,
|
||||
);
|
||||
|
||||
self.trail.push((
|
||||
Ref::HeapCell(addr),
|
||||
trail_item,
|
||||
));
|
||||
|
||||
if has_tail {
|
||||
let tail_addr = self.target[addr + 1].as_addr(addr + 1);
|
||||
self.target.push(HeapCellValue::Addr(tail_addr));
|
||||
}
|
||||
}
|
||||
|
||||
fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
|
||||
@@ -203,6 +153,7 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
Addr::HeapCell(h) => {
|
||||
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||
|
||||
self.trail.push((
|
||||
Ref::HeapCell(h),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h)),
|
||||
@@ -211,27 +162,12 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
Addr::StackCell(fr, sc) => {
|
||||
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||
self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier);
|
||||
|
||||
self.trail.push((
|
||||
Ref::StackCell(fr, sc),
|
||||
HeapCellValue::Addr(Addr::StackCell(fr, sc)),
|
||||
));
|
||||
}
|
||||
Addr::PStrTail(h, n) => {
|
||||
match &mut self.target[h] {
|
||||
HeapCellValue::PartialString(ref mut pstr) => {
|
||||
pstr.tail = Addr::PStrTail(frontier, n);
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
self.target[frontier] = HeapCellValue::Addr(Addr::PStrTail(frontier, n));
|
||||
self.trail.push((
|
||||
Ref::PStrTail(h, n),
|
||||
HeapCellValue::Addr(Addr::PStrTail(h, n))
|
||||
));
|
||||
}
|
||||
Addr::AttrVar(h) => {
|
||||
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||
self.target.threshold()
|
||||
@@ -241,6 +177,7 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
|
||||
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold));
|
||||
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
|
||||
|
||||
self.trail.push((
|
||||
Ref::AttrVar(h),
|
||||
HeapCellValue::Addr(Addr::AttrVar(h)),
|
||||
@@ -249,18 +186,20 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||
self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
|
||||
|
||||
let list_val = self.target[h + 1].clone();
|
||||
let list_val = self.target[h + 1].context_free_clone();
|
||||
self.target.push(list_val);
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_var(&mut self, addr: Addr) {
|
||||
let rd = self.target.store(self.target.deref(addr.clone()));
|
||||
let rd = self.target.store(self.target.deref(addr));
|
||||
|
||||
match rd.clone() {
|
||||
match rd {
|
||||
Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(rd);
|
||||
self.scan += 1;
|
||||
@@ -275,30 +214,54 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_stream(&mut self, addr: usize) {
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
let trail_item = mem::replace(
|
||||
&mut self.target[addr],
|
||||
HeapCellValue::Addr(Addr::Stream(threshold)),
|
||||
);
|
||||
|
||||
self.trail.push((
|
||||
Ref::HeapCell(addr),
|
||||
trail_item,
|
||||
));
|
||||
|
||||
self.target.push(HeapCellValue::Stream(Stream::null_stream()));
|
||||
|
||||
self.scan += 1;
|
||||
}
|
||||
|
||||
fn copy_structure(&mut self, addr: usize) {
|
||||
match self.target[addr].clone() {
|
||||
match self.target[addr].context_free_clone() {
|
||||
HeapCellValue::NamedStr(arity, name, fixity) => {
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold));
|
||||
self.target[addr] = HeapCellValue::Addr(Addr::Str(threshold));
|
||||
|
||||
let trail_item = mem::replace(
|
||||
&mut self.target[addr],
|
||||
HeapCellValue::Addr(Addr::Str(threshold)),
|
||||
);
|
||||
|
||||
self.trail.push((
|
||||
Ref::HeapCell(addr),
|
||||
HeapCellValue::NamedStr(arity, name.clone(), fixity.clone()),
|
||||
trail_item,
|
||||
));
|
||||
|
||||
self.target.push(HeapCellValue::NamedStr(arity, name, fixity));
|
||||
|
||||
for i in 0..arity {
|
||||
let hcv = self.target[addr + 1 + i].clone();
|
||||
let hcv = self.target[addr + 1 + i].context_free_clone();
|
||||
self.target.push(hcv);
|
||||
}
|
||||
}
|
||||
HeapCellValue::Addr(Addr::Str(addr)) => {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr))
|
||||
}
|
||||
_ => {}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
self.scan += 1;
|
||||
@@ -310,32 +273,43 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
|
||||
while self.scan < self.target.threshold() {
|
||||
match self.value_at_scan() {
|
||||
HeapCellValue::NamedStr(..) => {
|
||||
&mut HeapCellValue::Addr(addr) => {
|
||||
match addr {
|
||||
Addr::Con(h) => {
|
||||
let addr = self.target[h].as_addr(h);
|
||||
|
||||
if addr == Addr::Con(h) {
|
||||
*self.value_at_scan() = self.target[h].context_free_clone();
|
||||
} else {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(addr);
|
||||
}
|
||||
}
|
||||
Addr::Lis(h) if h >= self.old_h => {
|
||||
self.scan += 1;
|
||||
}
|
||||
HeapCellValue::Addr(ref addr) => {
|
||||
match addr.clone() {
|
||||
Addr::Lis(addr) => {
|
||||
self.copy_list(addr);
|
||||
Addr::Lis(h) => {
|
||||
self.copy_list(h);
|
||||
}
|
||||
addr @ Addr::AttrVar(_)
|
||||
| addr @ Addr::HeapCell(_)
|
||||
| addr @ Addr::StackCell(..)
|
||||
| addr @ Addr::PStrTail(..) => {
|
||||
addr @ Addr::AttrVar(_) |
|
||||
addr @ Addr::HeapCell(_) |
|
||||
addr @ Addr::StackCell(..) => {
|
||||
self.copy_var(addr);
|
||||
}
|
||||
Addr::Str(addr) => {
|
||||
self.copy_structure(addr);
|
||||
}
|
||||
Addr::PStrLocation(addr, n) => {
|
||||
self.copy_partial_string_from(addr, n);
|
||||
self.copy_partial_string(addr, n);
|
||||
}
|
||||
Addr::Con(_) | Addr::DBRef(_) => {
|
||||
Addr::Stream(h) => {
|
||||
self.copy_stream(h);
|
||||
}
|
||||
_ => {
|
||||
self.scan += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
HeapCellValue::PartialString(_) => {
|
||||
_ => {
|
||||
self.scan += 1;
|
||||
}
|
||||
}
|
||||
@@ -349,10 +323,6 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
match r {
|
||||
Ref::AttrVar(h) | Ref::HeapCell(h) =>
|
||||
self.target[h] = value,
|
||||
Ref::PStrTail(h, _) =>
|
||||
if let HeapCellValue::PartialString(ref mut pstr) = &mut self.target[h] {
|
||||
pstr.tail = value.as_addr(0);
|
||||
},
|
||||
Ref::StackCell(fr, sc) =>
|
||||
self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0),
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use prolog_parser::ast::*;
|
||||
|
||||
use crate::prolog::heap_print::*;
|
||||
use crate::prolog::machine::*;
|
||||
use crate::prolog::machine::compile::*;
|
||||
use crate::prolog::machine::machine_errors::*;
|
||||
use crate::prolog::machine::*;
|
||||
use crate::prolog::machine::streams::*;
|
||||
|
||||
use std::io::Read;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
impl Machine {
|
||||
pub(super) fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> {
|
||||
@@ -15,9 +16,9 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_into_machine<R: Read>(
|
||||
fn compile_into_machine(
|
||||
&mut self,
|
||||
src: ParsingStream<R>,
|
||||
src: Stream,
|
||||
name: ClauseName,
|
||||
arity: usize,
|
||||
) -> EvalSession {
|
||||
@@ -42,13 +43,35 @@ impl Machine {
|
||||
let arity = self.machine_st[arity].clone();
|
||||
|
||||
let name = match self.machine_st.store(self.machine_st.deref(name)) {
|
||||
Addr::Con(Constant::Atom(name, _)) => name,
|
||||
Addr::Con(h) =>
|
||||
if let HeapCellValue::Atom(ref name, _) = &self.machine_st.heap[h] {
|
||||
name.clone()
|
||||
} else {
|
||||
unreachable!()
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let arity = match self.machine_st.store(self.machine_st.deref(arity)) {
|
||||
Addr::Con(Constant::Integer(arity)) => arity.to_usize().unwrap(),
|
||||
_ => unreachable!(),
|
||||
Addr::Con(h) => {
|
||||
match &self.machine_st.heap[h] {
|
||||
HeapCellValue::Integer(ref arity) => {
|
||||
arity.to_usize().unwrap()
|
||||
}
|
||||
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
|
||||
usize::try_from(*arity).unwrap()
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Addr::Usize(n) => {
|
||||
n
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
(name, arity)
|
||||
@@ -102,7 +125,9 @@ impl Machine {
|
||||
let module_addr = self.machine_st[module].clone();
|
||||
|
||||
let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) {
|
||||
Addr::Con(Constant::Atom(module, _)) => match self.indices.modules.get_mut(&module) {
|
||||
Addr::Con(h) =>
|
||||
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
|
||||
match self.indices.modules.get_mut(module) {
|
||||
Some(ref mut module) => {
|
||||
module.code_dir.remove(&(name.clone(), arity));
|
||||
module.module_decl.name.clone()
|
||||
@@ -111,6 +136,9 @@ impl Machine {
|
||||
self.machine_st.fail = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
@@ -130,7 +158,12 @@ impl Machine {
|
||||
) {
|
||||
let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
|
||||
|
||||
let result = self.compile_into_machine(parsing_stream(pred_str.as_bytes()), name, arity);
|
||||
let result = self.compile_into_machine(
|
||||
Stream::from(pred_str),
|
||||
name,
|
||||
arity,
|
||||
);
|
||||
|
||||
self.machine_st = machine_st;
|
||||
|
||||
if let EvalSession::Error(err) = result {
|
||||
@@ -158,20 +191,33 @@ impl Machine {
|
||||
place.push_to_queue(&mut addrs, added_clause);
|
||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||
}
|
||||
Err(err) => return self.machine_st.throw_exception(err),
|
||||
Err(err) => {
|
||||
return self.machine_st.throw_exception(err);
|
||||
}
|
||||
};
|
||||
|
||||
self.handle_eval_result_from_dynamic_compile(pred_str, name, arity, place.predicate_name());
|
||||
self.handle_eval_result_from_dynamic_compile(
|
||||
pred_str,
|
||||
name,
|
||||
arity,
|
||||
place.predicate_name(),
|
||||
);
|
||||
}
|
||||
|
||||
fn set_module_atom_tbl(&mut self, module_addr: Addr, name: &mut ClauseName) -> bool {
|
||||
let atom_tbl = match self.machine_st.store(self.machine_st.deref(module_addr)) {
|
||||
Addr::Con(Constant::Atom(module, _)) => match self.indices.modules.get(&module) {
|
||||
Addr::Con(h) =>
|
||||
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
|
||||
match self.indices.modules.get(module) {
|
||||
Some(ref module) => module.atom_tbl.clone(),
|
||||
None => {
|
||||
self.machine_st.fail = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.machine_st.fail = true;
|
||||
return false;
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
@@ -200,7 +246,18 @@ impl Machine {
|
||||
fn retract_from_dynamic_predicate_in_module(&mut self) {
|
||||
let index = self.machine_st[temp_v!(3)].clone();
|
||||
let index = match self.machine_st.store(self.machine_st.deref(index)) {
|
||||
Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(),
|
||||
Addr::Con(h) =>
|
||||
match &self.machine_st.heap[h] {
|
||||
HeapCellValue::Integer(ref arity) => {
|
||||
arity.to_usize().unwrap()
|
||||
}
|
||||
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
|
||||
usize::try_from(*arity).unwrap()
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
@@ -220,7 +277,9 @@ impl Machine {
|
||||
|
||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||
}
|
||||
Err(err) => return self.machine_st.throw_exception(err),
|
||||
Err(err) => {
|
||||
return self.machine_st.throw_exception(err);
|
||||
}
|
||||
};
|
||||
|
||||
self.handle_eval_result_from_dynamic_compile(
|
||||
@@ -235,8 +294,22 @@ impl Machine {
|
||||
fn retract_from_dynamic_predicate(&mut self) {
|
||||
let index = self.machine_st[temp_v!(3)].clone();
|
||||
let index = match self.machine_st.store(self.machine_st.deref(index)) {
|
||||
Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(),
|
||||
_ => unreachable!(),
|
||||
Addr::Con(h) => {
|
||||
match &self.machine_st.heap[h] {
|
||||
HeapCellValue::Integer(ref arity) => {
|
||||
arity.to_usize().unwrap()
|
||||
}
|
||||
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
|
||||
usize::try_from(*arity).unwrap()
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
|
||||
@@ -253,7 +326,9 @@ impl Machine {
|
||||
|
||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||
}
|
||||
Err(err) => return self.machine_st.throw_exception(err),
|
||||
Err(err) => {
|
||||
return self.machine_st.throw_exception(err);
|
||||
}
|
||||
};
|
||||
|
||||
self.handle_eval_result_from_dynamic_compile(
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::prolog_parser::ast::*;
|
||||
use crate::prolog_parser::ast::Constant;
|
||||
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
use crate::prolog::machine::partial_string::*;
|
||||
use crate::prolog::machine::raw_block::*;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::ptr;
|
||||
@@ -39,12 +40,12 @@ impl<T: RawBlockTraits> Drop for HeapTemplate<T> {
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
struct HeapIntoIterator<T: RawBlockTraits> {
|
||||
struct HeapIntoIter<T: RawBlockTraits> {
|
||||
offset: usize,
|
||||
buf: RawBlock<T>,
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> Drop for HeapIntoIterator<T> {
|
||||
impl<T: RawBlockTraits> Drop for HeapIntoIter<T> {
|
||||
fn drop(&mut self) {
|
||||
let mut heap =
|
||||
HeapTemplate { buf: self.buf.take(), _marker: PhantomData };
|
||||
@@ -54,7 +55,7 @@ impl<T: RawBlockTraits> Drop for HeapIntoIterator<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> Iterator for HeapIntoIterator<T> {
|
||||
impl<T: RawBlockTraits> Iterator for HeapIntoIter<T> {
|
||||
type Item = HeapCellValue;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@@ -72,19 +73,19 @@ impl<T: RawBlockTraits> Iterator for HeapIntoIterator<T> {
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
struct HeapIterator<'a, T: RawBlockTraits> {
|
||||
struct HeapIter<'a, T: RawBlockTraits> {
|
||||
offset: usize,
|
||||
buf: &'a RawBlock<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: RawBlockTraits> HeapIterator<'a, T> {
|
||||
impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
|
||||
pub(crate)
|
||||
fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
|
||||
HeapIterator { buf, offset }
|
||||
HeapIter { buf, offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: RawBlockTraits> Iterator for HeapIterator<'a, T> {
|
||||
impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
|
||||
type Item = &'a HeapCellValue;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@@ -101,20 +102,28 @@ impl<'a, T: RawBlockTraits> Iterator for HeapIterator<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate)
|
||||
struct HeapIteratorMut<'a, T: RawBlockTraits> {
|
||||
fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
|
||||
for (index, term) in heap.enumerate() {
|
||||
println!("{} : {}", h + index, term);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
struct HeapIterMut<'a, T: RawBlockTraits> {
|
||||
offset: usize,
|
||||
buf: &'a mut RawBlock<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: RawBlockTraits> HeapIteratorMut<'a, T> {
|
||||
impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> {
|
||||
pub(crate)
|
||||
fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
|
||||
HeapIteratorMut { buf, offset }
|
||||
HeapIterMut { buf, offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: RawBlockTraits> Iterator for HeapIteratorMut<'a, T> {
|
||||
impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> {
|
||||
type Item = &'a mut HeapCellValue;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@@ -140,17 +149,183 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn push(&mut self, val: HeapCellValue) {
|
||||
unsafe {
|
||||
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>());
|
||||
ptr::write(self.buf.top as *mut _, val);
|
||||
self.buf.top = new_top;
|
||||
fn clone(&self, h: usize) -> HeapCellValue {
|
||||
match &self[h] {
|
||||
&HeapCellValue::Addr(addr) => {
|
||||
HeapCellValue::Addr(addr)
|
||||
}
|
||||
&HeapCellValue::Atom(ref name, ref op) => {
|
||||
HeapCellValue::Atom(name.clone(), op.clone())
|
||||
}
|
||||
&HeapCellValue::DBRef(ref db_ref) => {
|
||||
HeapCellValue::DBRef(db_ref.clone())
|
||||
}
|
||||
&HeapCellValue::Integer(ref n) => {
|
||||
HeapCellValue::Integer(n.clone())
|
||||
}
|
||||
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
|
||||
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
|
||||
}
|
||||
&HeapCellValue::Rational(ref r) => {
|
||||
HeapCellValue::Rational(r.clone())
|
||||
}
|
||||
&HeapCellValue::PartialString(..) => {
|
||||
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
|
||||
}
|
||||
&HeapCellValue::Stream(_) => {
|
||||
HeapCellValue::Addr(Addr::Stream(h))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn allocate_pstr(&mut self, mut src: &str) -> Option<Addr> {
|
||||
fn put_complete_string(&mut self, s: &str) -> Addr {
|
||||
let addr = self.allocate_pstr(s);
|
||||
self.pop();
|
||||
|
||||
let h = self.h();
|
||||
|
||||
match &mut self[h - 1] {
|
||||
&mut HeapCellValue::PartialString(_, ref mut has_tail) => {
|
||||
*has_tail = false;
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
addr
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn put_constant(&mut self, c: Constant) -> Addr {
|
||||
match c {
|
||||
Constant::Atom(name, op) => {
|
||||
Addr::Con(self.push(HeapCellValue::Atom(name, op)))
|
||||
}
|
||||
Constant::Char(c) => {
|
||||
Addr::Char(c)
|
||||
}
|
||||
Constant::CharCode(c) => {
|
||||
Addr::CharCode(c)
|
||||
}
|
||||
Constant::EmptyList => {
|
||||
Addr::EmptyList
|
||||
}
|
||||
Constant::Fixnum(n) => {
|
||||
Addr::Fixnum(n)
|
||||
}
|
||||
Constant::Integer(n) => {
|
||||
Addr::Con(self.push(HeapCellValue::Integer(n)))
|
||||
}
|
||||
Constant::Rational(r) => {
|
||||
Addr::Con(self.push(HeapCellValue::Rational(r)))
|
||||
}
|
||||
Constant::Float(f) => {
|
||||
Addr::Float(f)
|
||||
}
|
||||
Constant::String(s) => {
|
||||
if s.is_empty() {
|
||||
Addr::EmptyList
|
||||
} else {
|
||||
self.put_complete_string(&s)
|
||||
}
|
||||
}
|
||||
Constant::Usize(n) => {
|
||||
Addr::Usize(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn pop(&mut self) {
|
||||
let h = self.h();
|
||||
|
||||
if h > 0 {
|
||||
self.truncate(h - 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn push(&mut self, val: HeapCellValue) -> usize {
|
||||
let h = self.h();
|
||||
|
||||
unsafe {
|
||||
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>());
|
||||
ptr::write(self.buf.top as *mut _, val);
|
||||
self.buf.top = new_top;
|
||||
}
|
||||
|
||||
h
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn atom_at(&self, h: usize) -> bool {
|
||||
if let HeapCellValue::Atom(..) = &self[h] {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn to_unifiable(&mut self, non_heap_value: HeapCellValue) -> Addr {
|
||||
match non_heap_value {
|
||||
HeapCellValue::Addr(addr) => {
|
||||
addr
|
||||
}
|
||||
val @ HeapCellValue::Atom(..)
|
||||
| val @ HeapCellValue::Integer(_)
|
||||
| val @ HeapCellValue::DBRef(_)
|
||||
| val @ HeapCellValue::Rational(_) => {
|
||||
Addr::Con(self.push(val))
|
||||
}
|
||||
val @ HeapCellValue::NamedStr(..) => {
|
||||
Addr::Str(self.push(val))
|
||||
}
|
||||
val @ HeapCellValue::Stream(..) => {
|
||||
Addr::Stream(self.push(val))
|
||||
}
|
||||
HeapCellValue::PartialString(pstr, has_tail) => {
|
||||
let h = self.push(HeapCellValue::PartialString(pstr, has_tail));
|
||||
|
||||
if has_tail {
|
||||
self.push(HeapCellValue::Addr(Addr::EmptyList));
|
||||
}
|
||||
|
||||
Addr::Con(h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn allocate_pstr(&mut self, src: &str) -> Addr {
|
||||
self.write_pstr(src)
|
||||
.unwrap_or_else(|| {
|
||||
let h = self.h();
|
||||
|
||||
self.push(HeapCellValue::PartialString(
|
||||
PartialString::empty(),
|
||||
true,
|
||||
));
|
||||
|
||||
self.push(HeapCellValue::Addr(
|
||||
Addr::HeapCell(h + 1)
|
||||
));
|
||||
|
||||
Addr::PStrLocation(h, 0)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_pstr(&mut self, mut src: &str) -> Option<Addr> {
|
||||
let orig_h = self.h();
|
||||
|
||||
loop {
|
||||
@@ -158,17 +333,8 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
return if orig_h == self.h() {
|
||||
None
|
||||
} else {
|
||||
let prev_h = self.h() - 1;
|
||||
|
||||
match &mut self[prev_h] {
|
||||
HeapCellValue::PartialString(ref mut pstr) => {
|
||||
let s = pstr.block_as_str();
|
||||
pstr.tail = Addr::PStrTail(prev_h, s.len());
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
let tail_h = self.h() - 1;
|
||||
self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h));
|
||||
|
||||
Some(Addr::PStrLocation(orig_h, 0))
|
||||
};
|
||||
@@ -176,8 +342,8 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
|
||||
let h = self.h();
|
||||
|
||||
let (mut pstr, rest_src) =
|
||||
match PartialString::new(src, h) {
|
||||
let (pstr, rest_src) =
|
||||
match PartialString::new(src) {
|
||||
Some(tuple) => {
|
||||
tuple
|
||||
}
|
||||
@@ -188,44 +354,19 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
} else if orig_h == h {
|
||||
return None;
|
||||
} else {
|
||||
let prev_h = h - 1;
|
||||
|
||||
match &mut self[prev_h] {
|
||||
HeapCellValue::PartialString(ref mut pstr) => {
|
||||
let s = pstr.block_as_str();
|
||||
pstr.tail = Addr::PStrTail(prev_h, s.len());
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1));
|
||||
return Some(Addr::PStrLocation(orig_h, 0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let new_top = unsafe {
|
||||
self.buf.new_block(mem::size_of::<HeapCellValue>())
|
||||
};
|
||||
self.push(HeapCellValue::PartialString(pstr, true));
|
||||
|
||||
if rest_src != "" {
|
||||
pstr.tail = Addr::PStrLocation(h+1, 0);
|
||||
self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0)));
|
||||
src = rest_src;
|
||||
} else {
|
||||
pstr.tail = Addr::PStrTail(h, src.len());
|
||||
}
|
||||
|
||||
unsafe{
|
||||
ptr::write(
|
||||
self.buf.top as *mut _,
|
||||
HeapCellValue::PartialString(pstr),
|
||||
);
|
||||
}
|
||||
|
||||
self.buf.top = new_top;
|
||||
|
||||
if rest_src == "" {
|
||||
self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
|
||||
return Some(Addr::PStrLocation(orig_h, 0));
|
||||
}
|
||||
}
|
||||
@@ -279,35 +420,39 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn to_list<Iter: Iterator<Item = Addr>>(&mut self, values: Iter) -> usize {
|
||||
fn to_list<Iter, SrcT>(&mut self, values: Iter) -> usize
|
||||
where Iter: Iterator<Item = SrcT>,
|
||||
SrcT: Into<HeapCellValue>
|
||||
{
|
||||
let head_addr = self.h();
|
||||
let mut h = head_addr;
|
||||
|
||||
for value in values {
|
||||
let h = self.h();
|
||||
|
||||
for value in values.map(|v| v.into()) {
|
||||
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||
self.push(HeapCellValue::Addr(value));
|
||||
self.push(value);
|
||||
|
||||
h += 2;
|
||||
}
|
||||
|
||||
self.push(HeapCellValue::Addr(Addr::Con(Constant::EmptyList)));
|
||||
self.push(HeapCellValue::Addr(Addr::EmptyList));
|
||||
|
||||
head_addr
|
||||
}
|
||||
|
||||
/* Create an iterator starting from the passed offset. */
|
||||
pub(crate)
|
||||
fn iter_from<'a>(&'a self, offset: usize) -> HeapIterator<'a, T> {
|
||||
HeapIterator::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
|
||||
fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> {
|
||||
HeapIter::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIteratorMut<'a, T> {
|
||||
HeapIteratorMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
|
||||
fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> {
|
||||
HeapIterMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn into_iter(mut self) -> HeapIntoIterator<T> {
|
||||
HeapIntoIterator { buf: self.buf.take(), offset: 0 }
|
||||
fn into_iter(mut self) -> HeapIntoIter<T> {
|
||||
HeapIntoIter { buf: self.buf.take(), offset: 0 }
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
@@ -320,8 +465,9 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
pub(crate)
|
||||
fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
|
||||
let extract_integer = |s: usize| -> Option<usize> {
|
||||
match self[s].as_addr(s) {
|
||||
Addr::Con(Constant::Integer(n)) => n.to_usize(),
|
||||
match &self[s] {
|
||||
&HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(),
|
||||
&HeapCellValue::Integer(ref n) => n.to_usize(),
|
||||
_ => None
|
||||
}
|
||||
};
|
||||
@@ -361,6 +507,19 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub
|
||||
fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
|
||||
match addr {
|
||||
&Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) => {
|
||||
RefOrOwned::Borrowed(&self[h])
|
||||
}
|
||||
addr => {
|
||||
RefOrOwned::Owned(HeapCellValue::Addr(*addr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use prolog_parser::ast::*;
|
||||
|
||||
use crate::prolog::forms::PredicateKey;
|
||||
use crate::prolog::forms::{ModuleSource, Number, PredicateKey};
|
||||
use crate::prolog::machine::heap::*;
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
use crate::prolog::machine::machine_state::*;
|
||||
use crate::prolog::rug::Integer;
|
||||
@@ -21,34 +22,103 @@ pub(super) struct MachineError {
|
||||
from: ErrorProvenance,
|
||||
}
|
||||
|
||||
impl MachineError {
|
||||
pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub {
|
||||
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None)));
|
||||
functor!(
|
||||
"/",
|
||||
2,
|
||||
[name, heap_integer!(Integer::from(arity))],
|
||||
SharedOpDesc::new(400, YFX)
|
||||
)
|
||||
}
|
||||
pub(super)
|
||||
trait TypeError {
|
||||
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError;
|
||||
}
|
||||
|
||||
impl TypeError for Addr {
|
||||
fn type_error(self, _: usize, valid_type: ValidType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"type_error",
|
||||
[atom(valid_type.as_str()), addr(self)]
|
||||
);
|
||||
|
||||
pub(super) fn evaluation_error(eval_error: EvalError) -> Self {
|
||||
let stub = functor!("evaluation_error", 1, [heap_atom!(eval_error.as_str())]);
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
from: ErrorProvenance::Received
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn type_error(valid_type: ValidType, culprit: Addr) -> Self {
|
||||
impl TypeError for MachineStub {
|
||||
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"type_error",
|
||||
2,
|
||||
[
|
||||
heap_atom!(valid_type.as_str()),
|
||||
HeapCellValue::Addr(culprit)
|
||||
]
|
||||
[atom(valid_type.as_str()), aux(h, 0)],
|
||||
[self]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeError for Number {
|
||||
fn type_error(self, _h: usize, valid_type: ValidType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"type_error",
|
||||
[atom(valid_type.as_str()), number(self)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
trait PermissionError {
|
||||
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError;
|
||||
}
|
||||
|
||||
impl PermissionError for Addr {
|
||||
fn permission_error(self, _: usize, index_str: &'static str, perm: Permission) -> MachineError {
|
||||
let stub = functor!(
|
||||
"permission_error",
|
||||
[atom(perm.as_str()), atom(index_str), addr(self)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PermissionError for MachineStub {
|
||||
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError {
|
||||
let stub = functor!(
|
||||
"permission_error",
|
||||
[atom(perm.as_str()), atom(index_str), aux(h, 0)],
|
||||
[self]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
trait DomainError {
|
||||
fn domain_error(self, error: DomainErrorType) -> MachineError;
|
||||
}
|
||||
|
||||
impl DomainError for Addr {
|
||||
fn domain_error(self, error: DomainErrorType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"domain_error",
|
||||
[atom(error.as_str()), addr(self)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
@@ -57,55 +127,74 @@ impl MachineError {
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn module_resolution_error(
|
||||
impl DomainError for Number {
|
||||
fn domain_error(self, error: DomainErrorType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"domain_error",
|
||||
[atom(error.as_str()), number(self)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineError {
|
||||
pub(super)
|
||||
fn functor_stub(name: ClauseName, arity: usize) -> MachineStub {
|
||||
functor!(
|
||||
"/",
|
||||
SharedOpDesc::new(400, YFX),
|
||||
[clause_name(name), integer(arity)]
|
||||
)
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn evaluation_error(eval_error: EvalError) -> Self {
|
||||
let stub = functor!("evaluation_error", [atom(eval_error.as_str())]);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn type_error<T: TypeError>(h: usize, valid_type: ValidType, culprit: T) -> Self {
|
||||
culprit.type_error(h, valid_type)
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn module_resolution_error(
|
||||
h: usize,
|
||||
mod_name: ClauseName,
|
||||
name: ClauseName,
|
||||
arity: usize,
|
||||
) -> Self {
|
||||
let mod_name = HeapCellValue::Addr(Addr::Con(Constant::Atom(mod_name, None)));
|
||||
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None)));
|
||||
|
||||
let mut stub = functor!(
|
||||
"evaluation_error",
|
||||
1,
|
||||
[HeapCellValue::Addr(Addr::HeapCell(h + 2))]
|
||||
);
|
||||
|
||||
stub.append(&mut functor!(
|
||||
"/",
|
||||
2,
|
||||
[
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 2 + 3)),
|
||||
heap_integer!(Integer::from(arity))
|
||||
],
|
||||
SharedOpDesc::new(400, YFX)
|
||||
));
|
||||
|
||||
stub.append(&mut functor!(
|
||||
let res_stub = functor!(
|
||||
":",
|
||||
2,
|
||||
[mod_name, name],
|
||||
SharedOpDesc::new(600, XFY)
|
||||
));
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn existence_error(h: usize, err: ExistenceError) -> Self {
|
||||
match err {
|
||||
ExistenceError::Procedure(name, arity) => {
|
||||
let mut stub = functor!(
|
||||
"existence_error",
|
||||
2,
|
||||
[heap_atom!("procedure"), heap_str!(3 + h)]
|
||||
SharedOpDesc::new(600, XFY),
|
||||
[clause_name(mod_name), clause_name(name)]
|
||||
);
|
||||
|
||||
let ind_stub = functor!(
|
||||
"/",
|
||||
SharedOpDesc::new(400, YFX),
|
||||
[aux(h + 2, 0), integer(arity)],
|
||||
[res_stub]
|
||||
);
|
||||
|
||||
let stub = functor!(
|
||||
"evaluation_error",
|
||||
[aux(h, 0)],
|
||||
[ind_stub]
|
||||
);
|
||||
stub.append(&mut Self::functor_stub(name, arity));
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
@@ -113,57 +202,34 @@ impl MachineError {
|
||||
from: ErrorProvenance::Constructed,
|
||||
}
|
||||
}
|
||||
ExistenceError::Module(name) => {
|
||||
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None)));
|
||||
let stub = functor!("existence_error", 2, [heap_atom!("module"), name]);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn session_error(h: usize, err: SessionError) -> Self {
|
||||
pub(super)
|
||||
fn existence_error(h: usize, err: ExistenceError) -> Self {
|
||||
match err {
|
||||
SessionError::ParserError(err) => Self::syntax_error(h, err),
|
||||
SessionError::CannotOverwriteBuiltIn(pred_str)
|
||||
| SessionError::CannotOverwriteImport(pred_str) => {
|
||||
Self::permission_error(PermissionError::Modify, "private_procedure", pred_str)
|
||||
}
|
||||
SessionError::InvalidFileName(filename) => {
|
||||
Self::existence_error(h, ExistenceError::Module(filename))
|
||||
}
|
||||
SessionError::ModuleDoesNotContainExport(..) => Self::permission_error(
|
||||
PermissionError::Access,
|
||||
"private_procedure",
|
||||
clause_name!("module_does_not_contain_claimed_export"),
|
||||
),
|
||||
SessionError::ModuleNotFound => Self::permission_error(
|
||||
PermissionError::Access,
|
||||
"private_procedure",
|
||||
clause_name!("module_does_not_exist"),
|
||||
),
|
||||
SessionError::OpIsInfixAndPostFix(op) => {
|
||||
Self::permission_error(PermissionError::Create, "operator", op)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
ExistenceError::Module(name) => {
|
||||
let stub = functor!(
|
||||
"existence_error",
|
||||
[atom("source_sink"), clause_name(name)]
|
||||
);
|
||||
|
||||
pub(super) fn permission_error(
|
||||
err: PermissionError,
|
||||
index_str: &'static str,
|
||||
pred_str: ClauseName,
|
||||
) -> Self {
|
||||
let pred_str = HeapCellValue::Addr(Addr::Con(Constant::Atom(pred_str, None)));
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
ExistenceError::Procedure(name, arity) => {
|
||||
let culprit = functor!(
|
||||
"/",
|
||||
SharedOpDesc::new(400, YFX),
|
||||
[clause_name(name), integer(arity)]
|
||||
);
|
||||
|
||||
let err = vec![heap_atom!(err.as_str()), heap_atom!(index_str), pred_str];
|
||||
let mut stub = functor!("permission_error", 3);
|
||||
|
||||
stub.extend(err.into_iter());
|
||||
let stub = functor!(
|
||||
"existence_error",
|
||||
[atom("procedure"), aux(h, 0)],
|
||||
[culprit]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
@@ -171,46 +237,168 @@ impl MachineError {
|
||||
from: ErrorProvenance::Constructed,
|
||||
}
|
||||
}
|
||||
ExistenceError::SourceSink(source) => {
|
||||
let source_stub = source.as_functor_stub();
|
||||
|
||||
let stub = functor!(
|
||||
"existence_error",
|
||||
[atom("source_sink"), aux(h, 0)],
|
||||
[source_stub]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed,
|
||||
}
|
||||
}
|
||||
ExistenceError::Stream(culprit) => {
|
||||
let stub = functor!(
|
||||
"existence_error",
|
||||
[atom("stream"), addr(culprit)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn permission_error<T: PermissionError>(
|
||||
h: usize,
|
||||
err: Permission,
|
||||
index_str: &'static str,
|
||||
culprit: T,
|
||||
) -> Self {
|
||||
culprit.permission_error(
|
||||
h,
|
||||
index_str,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
fn arithmetic_error(h: usize, err: ArithmeticError) -> Self {
|
||||
match err {
|
||||
ArithmeticError::UninstantiatedVar => Self::instantiation_error(),
|
||||
ArithmeticError::UninstantiatedVar => {
|
||||
Self::instantiation_error()
|
||||
}
|
||||
ArithmeticError::NonEvaluableFunctor(name, arity) => {
|
||||
let name = HeapCellValue::Addr(Addr::Con(name));
|
||||
let culprit = functor!(
|
||||
"/",
|
||||
2,
|
||||
[name, heap_integer!(Integer::from(arity))],
|
||||
SharedOpDesc::new(400, YFX)
|
||||
SharedOpDesc::new(400, YFX),
|
||||
[constant(h, &name), integer(arity)]
|
||||
);
|
||||
|
||||
let mut stub = Self::type_error(ValidType::Evaluable, Addr::HeapCell(3 + h)).stub;
|
||||
stub.extend(culprit.into_iter());
|
||||
Self::type_error(h, ValidType::Evaluable, culprit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn domain_error<T: DomainError>(error: DomainErrorType, culprit: T) -> Self {
|
||||
culprit.domain_error(error)
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn instantiation_error() -> Self {
|
||||
let stub = functor!("instantiation_error");
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn uninstantiation_error(culprit: Addr) -> Self {
|
||||
let stub = functor!(
|
||||
"uninstantiation_error",
|
||||
[addr(culprit)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn session_error(h: usize, err: SessionError) -> Self {
|
||||
match err {
|
||||
SessionError::CannotOverwriteBuiltIn(pred_str) |
|
||||
SessionError::CannotOverwriteImport(pred_str) => {
|
||||
Self::permission_error(
|
||||
h,
|
||||
Permission::Modify,
|
||||
"private_procedure",
|
||||
functor!(clause_name(pred_str)),
|
||||
)
|
||||
}
|
||||
SessionError::ExistenceError(err) => {
|
||||
Self::existence_error(h, err)
|
||||
}
|
||||
SessionError::InvalidFileName(filename) => {
|
||||
Self::existence_error(h, ExistenceError::Module(filename))
|
||||
}
|
||||
SessionError::ModuleDoesNotContainExport(..) => {
|
||||
Self::permission_error(
|
||||
h,
|
||||
Permission::Access,
|
||||
"private_procedure",
|
||||
functor!("module_does_not_contain_claimed_export"),
|
||||
)
|
||||
}
|
||||
SessionError::NamelessEntry => {
|
||||
Self::permission_error(
|
||||
h,
|
||||
Permission::Create,
|
||||
"static_procedure",
|
||||
functor!("nameless_procedure")
|
||||
)
|
||||
}
|
||||
SessionError::OpIsInfixAndPostFix(op) => {
|
||||
Self::permission_error(
|
||||
h,
|
||||
Permission::Create,
|
||||
"operator",
|
||||
functor!(clause_name(op)),
|
||||
)
|
||||
}
|
||||
SessionError::ParserError(err) => {
|
||||
Self::syntax_error(h, err)
|
||||
}
|
||||
SessionError::QueryCannotBeDefinedAsFact => {
|
||||
Self::permission_error(
|
||||
h,
|
||||
Permission::Create,
|
||||
"static_procedure",
|
||||
functor!("query_cannot_be_defined_as_fact")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn syntax_error(h: usize, err: ParserError) -> Self {
|
||||
pub(super)
|
||||
fn syntax_error(h: usize, err: ParserError) -> Self {
|
||||
if let ParserError::Arithmetic(err) = err {
|
||||
return Self::arithmetic_error(h, err);
|
||||
}
|
||||
|
||||
let location = err.line_and_col_num();
|
||||
let err = vec![heap_atom!(err.as_str())];
|
||||
let stub = functor!(err.as_str());
|
||||
|
||||
let mut stub = if err.len() == 1 {
|
||||
functor!("syntax_error", 1)
|
||||
} else {
|
||||
functor!("syntax_error", 1, [heap_str!(h + 2)])
|
||||
};
|
||||
|
||||
stub.extend(err.into_iter());
|
||||
let stub = functor!(
|
||||
"syntax_error",
|
||||
[aux(h, 0)],
|
||||
[stub]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
@@ -219,30 +407,10 @@ impl MachineError {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn domain_error(error: DomainError, culprit: Addr) -> Self {
|
||||
let stub = functor!(
|
||||
"domain_error",
|
||||
2,
|
||||
[heap_atom!(error.as_str()), HeapCellValue::Addr(culprit)]
|
||||
);
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
pub(super)
|
||||
fn representation_error(flag: RepFlag) -> Self {
|
||||
let stub = functor!("representation_error", [atom(flag.as_str())]);
|
||||
|
||||
pub(super) fn instantiation_error() -> Self {
|
||||
let stub = functor!("instantiation_error");
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn representation_error(flag: RepFlag) -> Self {
|
||||
let stub = functor!("representation_error", 1, [heap_atom!(flag.as_str())]);
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
@@ -268,18 +436,22 @@ impl MachineError {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PermissionError {
|
||||
pub enum Permission {
|
||||
Access,
|
||||
Create,
|
||||
InputStream,
|
||||
Modify,
|
||||
OutputStream,
|
||||
}
|
||||
|
||||
impl PermissionError {
|
||||
impl Permission {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
PermissionError::Access => "access",
|
||||
PermissionError::Create => "create",
|
||||
PermissionError::Modify => "modify",
|
||||
Permission::Access => "access",
|
||||
Permission::Create => "create",
|
||||
Permission::InputStream => "input",
|
||||
Permission::Modify => "modify",
|
||||
Permission::OutputStream => "output",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -331,14 +503,18 @@ impl ValidType {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum DomainError {
|
||||
pub enum DomainErrorType {
|
||||
NotLessThanZero,
|
||||
Stream,
|
||||
StreamOrAlias,
|
||||
}
|
||||
|
||||
impl DomainError {
|
||||
impl DomainErrorType {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
DomainError::NotLessThanZero => "not_less_than_zero",
|
||||
DomainErrorType::NotLessThanZero => "not_less_than_zero",
|
||||
DomainErrorType::Stream => "stream",
|
||||
DomainErrorType::StreamOrAlias => "stream_or_alias",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,21 +564,20 @@ impl EvalError {
|
||||
}
|
||||
|
||||
// used by '$skip_max_list'.
|
||||
#[derive(Clone, Copy)]
|
||||
pub(super) enum CycleSearchResult {
|
||||
EmptyList,
|
||||
NotList,
|
||||
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
|
||||
ProperList(usize), // the list length.
|
||||
CompleteString(usize, Rc<String>), // the string length (in bytes), the string.
|
||||
UntouchedString(usize, Rc<String>), // the cut off, past which is the untouched string.
|
||||
PStrLocation(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string.
|
||||
PStrTail(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string.
|
||||
UntouchedList(usize), // the address of an uniterated Addr::Lis(address).
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
// see 8.4.3 of Draft Technical Corrigendum 2.
|
||||
pub(super) fn check_sort_errors(&self) -> CallResult {
|
||||
pub(super)
|
||||
fn check_sort_errors(&self) -> CallResult {
|
||||
let stub = MachineError::functor_stub(clause_name!("sort"), 2);
|
||||
let list = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||
@@ -412,14 +587,14 @@ impl MachineState {
|
||||
return Err(self.error_form(MachineError::instantiation_error(), stub))
|
||||
}
|
||||
CycleSearchResult::NotList => {
|
||||
return Err(self.error_form(MachineError::type_error(ValidType::List, list), stub))
|
||||
return Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match self.detect_cycles(sorted.clone()) {
|
||||
CycleSearchResult::NotList if !sorted.is_ref() => {
|
||||
Err(self.error_form(MachineError::type_error(ValidType::List, sorted), stub))
|
||||
Err(self.error_form(MachineError::type_error(0, ValidType::List, sorted), stub))
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
@@ -430,7 +605,7 @@ impl MachineState {
|
||||
|
||||
match self.detect_cycles(list.clone()) {
|
||||
CycleSearchResult::NotList if !list.is_ref() => {
|
||||
Err(self.error_form(MachineError::type_error(ValidType::List, list), stub))
|
||||
Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
|
||||
}
|
||||
_ => {
|
||||
let mut addr = list;
|
||||
@@ -439,18 +614,23 @@ impl MachineState {
|
||||
let mut new_l = l;
|
||||
|
||||
loop {
|
||||
match self.heap[new_l].clone() {
|
||||
HeapCellValue::Addr(Addr::Str(l)) => new_l = l,
|
||||
HeapCellValue::NamedStr(2, ref name, Some(_))
|
||||
if name.as_str() == "-" =>
|
||||
{
|
||||
break
|
||||
match self.heap.clone(new_l) {
|
||||
HeapCellValue::Addr(Addr::Str(l)) => {
|
||||
new_l = l;
|
||||
}
|
||||
HeapCellValue::NamedStr(2, ref name, Some(_))
|
||||
if name.as_str() == "-" => {
|
||||
break;
|
||||
}
|
||||
HeapCellValue::Addr(Addr::HeapCell(_)) => {
|
||||
break;
|
||||
}
|
||||
HeapCellValue::Addr(Addr::StackCell(..)) => {
|
||||
break;
|
||||
}
|
||||
HeapCellValue::Addr(Addr::HeapCell(_)) => break,
|
||||
HeapCellValue::Addr(Addr::StackCell(..)) => break,
|
||||
_ => {
|
||||
return Err(self.error_form(
|
||||
MachineError::type_error(ValidType::Pair, Addr::HeapCell(l)),
|
||||
MachineError::type_error(0, ValidType::Pair, Addr::HeapCell(l)),
|
||||
stub,
|
||||
))
|
||||
}
|
||||
@@ -466,8 +646,10 @@ impl MachineState {
|
||||
}
|
||||
|
||||
// see 8.4.4 of Draft Technical Corrigendum 2.
|
||||
pub(super) fn check_keysort_errors(&self) -> CallResult {
|
||||
pub(super)
|
||||
fn check_keysort_errors(&self) -> CallResult {
|
||||
let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
|
||||
|
||||
let pairs = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||
|
||||
@@ -476,7 +658,7 @@ impl MachineState {
|
||||
Err(self.error_form(MachineError::instantiation_error(), stub))
|
||||
}
|
||||
CycleSearchResult::NotList => {
|
||||
Err(self.error_form(MachineError::type_error(ValidType::List, pairs), stub))
|
||||
Err(self.error_form(MachineError::type_error(0, ValidType::List, pairs), stub))
|
||||
}
|
||||
_ => Ok(()),
|
||||
}?;
|
||||
@@ -484,7 +666,8 @@ impl MachineState {
|
||||
self.check_for_list_pairs(sorted)
|
||||
}
|
||||
|
||||
pub(super) fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub {
|
||||
pub(super)
|
||||
fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub {
|
||||
let location = err.location;
|
||||
let err_len = err.len();
|
||||
|
||||
@@ -500,21 +683,17 @@ impl MachineState {
|
||||
if let Some((line_num, _)) = location {
|
||||
let colon_op_desc = Some(SharedOpDesc::new(600, XFY));
|
||||
|
||||
stub.extend(
|
||||
vec![
|
||||
HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)),
|
||||
heap_integer!(Integer::from(line_num)),
|
||||
]
|
||||
.into_iter(),
|
||||
);
|
||||
stub.push(HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc));
|
||||
stub.push(HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)));
|
||||
stub.push(HeapCellValue::Integer(Rc::new(Integer::from(line_num))));
|
||||
}
|
||||
|
||||
stub.extend(src.into_iter());
|
||||
stub
|
||||
}
|
||||
|
||||
pub(super) fn throw_exception(&mut self, err: MachineStub) {
|
||||
pub(super)
|
||||
fn throw_exception(&mut self, err: MachineStub) {
|
||||
let h = self.heap.h();
|
||||
|
||||
self.ball.boundary = 0;
|
||||
@@ -532,16 +711,19 @@ impl MachineState {
|
||||
pub enum ExistenceError {
|
||||
Module(ClauseName),
|
||||
Procedure(ClauseName, usize),
|
||||
SourceSink(ModuleSource),
|
||||
Stream(Addr),
|
||||
}
|
||||
|
||||
pub enum SessionError {
|
||||
CannotOverwriteBuiltIn(ClauseName),
|
||||
CannotOverwriteImport(ClauseName),
|
||||
ExistenceError(ExistenceError),
|
||||
InvalidFileName(ClauseName),
|
||||
ModuleDoesNotContainExport(ClauseName, PredicateKey),
|
||||
ModuleNotFound,
|
||||
NamelessEntry,
|
||||
OpIsInfixAndPostFix(ClauseName),
|
||||
QueryCannotBeDefinedAsFact,
|
||||
ParserError(ParserError),
|
||||
}
|
||||
|
||||
@@ -566,4 +748,5 @@ impl From<ParserError> for EvalSession {
|
||||
fn from(err: ParserError) -> Self {
|
||||
EvalSession::from(SessionError::ParserError(err))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,16 +7,20 @@ use crate::prolog::forms::*;
|
||||
use crate::prolog::machine::code_repo::CodeRepo;
|
||||
use crate::prolog::machine::Ball;
|
||||
use crate::prolog::machine::heap::*;
|
||||
use crate::prolog::machine::machine_state::*;
|
||||
use crate::prolog::machine::partial_string::*;
|
||||
use crate::prolog::machine::raw_block::RawBlockTraits;
|
||||
use crate::prolog::machine::streams::Stream;
|
||||
use crate::prolog::instructions::*;
|
||||
use crate::prolog::rug::Integer;
|
||||
use crate::prolog::ordered_float::OrderedFloat;
|
||||
use crate::prolog::rug::{Integer, Rational};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
use std::rc::Rc;
|
||||
@@ -38,25 +42,40 @@ pub enum DBRef {
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Addr {
|
||||
AttrVar(usize),
|
||||
Con(Constant),
|
||||
DBRef(DBRef),
|
||||
Lis(usize),
|
||||
HeapCell(usize),
|
||||
StackCell(usize, usize),
|
||||
Str(usize),
|
||||
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
|
||||
PStrTail(usize, usize), // location of pstr in heap, offset into string in bytes.
|
||||
// 7.2
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum TermOrderCategory {
|
||||
Variable,
|
||||
FloatingPoint,
|
||||
Integer,
|
||||
Atom,
|
||||
Compound,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Addr {
|
||||
AttrVar(usize),
|
||||
Char(char),
|
||||
CharCode(u32),
|
||||
Con(usize),
|
||||
CutPoint(usize),
|
||||
EmptyList,
|
||||
Fixnum(isize),
|
||||
Float(OrderedFloat<f64>),
|
||||
Lis(usize),
|
||||
HeapCell(usize),
|
||||
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
|
||||
StackCell(usize, usize),
|
||||
Str(usize),
|
||||
Stream(usize),
|
||||
Usize(usize),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Hash, Eq, PartialEq, PartialOrd)]
|
||||
pub enum Ref {
|
||||
AttrVar(usize),
|
||||
HeapCell(usize),
|
||||
StackCell(usize, usize),
|
||||
PStrTail(usize, usize),
|
||||
}
|
||||
|
||||
impl Ref {
|
||||
@@ -65,7 +84,28 @@ impl Ref {
|
||||
Ref::AttrVar(h) => Addr::AttrVar(h),
|
||||
Ref::HeapCell(h) => Addr::HeapCell(h),
|
||||
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
|
||||
Ref::PStrTail(h, n) => Addr::PStrTail(h, n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Ref {
|
||||
fn cmp(&self, other: &Ref) -> Ordering {
|
||||
match (self, other) {
|
||||
(Ref::AttrVar(h1), Ref::AttrVar(h2))
|
||||
| (Ref::HeapCell(h1), Ref::HeapCell(h2))
|
||||
| (Ref::HeapCell(h1), Ref::AttrVar(h2))
|
||||
| (Ref::AttrVar(h1), Ref::HeapCell(h2)) => {
|
||||
h1.cmp(&h2)
|
||||
}
|
||||
(Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => {
|
||||
fr1.cmp(&fr2).then_with(|| sc1.cmp(&sc2))
|
||||
}
|
||||
(Ref::StackCell(..), _) => {
|
||||
Ordering::Greater
|
||||
}
|
||||
(_, Ref::StackCell(..)) => {
|
||||
Ordering::Less
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,7 +122,7 @@ impl PartialOrd<Ref> for Addr {
|
||||
match self {
|
||||
&Addr::StackCell(fr, sc) => {
|
||||
match *r {
|
||||
Ref::AttrVar(_) | Ref::HeapCell(_) | Ref::PStrTail(..) => {
|
||||
Ref::AttrVar(_) | Ref::HeapCell(_) => {
|
||||
Some(Ordering::Greater)
|
||||
}
|
||||
Ref::StackCell(fr1, sc1) => {
|
||||
@@ -104,22 +144,6 @@ impl PartialOrd<Ref> for Addr {
|
||||
Ref::AttrVar(h1) | Ref::HeapCell(h1) => {
|
||||
h.partial_cmp(h1)
|
||||
}
|
||||
Ref::PStrTail(h1, _) => {
|
||||
h.partial_cmp(h1)
|
||||
}
|
||||
}
|
||||
}
|
||||
&Addr::PStrTail(h, n) => {
|
||||
match r {
|
||||
Ref::StackCell(..) => {
|
||||
Some(Ordering::Less)
|
||||
}
|
||||
Ref::AttrVar(h1) | Ref::HeapCell(h1) => {
|
||||
h.partial_cmp(h1)
|
||||
}
|
||||
Ref::PStrTail(h1, n1) => {
|
||||
Some(h.cmp(h1).then_with(|| n.cmp(n1)))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -130,9 +154,24 @@ impl PartialOrd<Ref> for Addr {
|
||||
}
|
||||
|
||||
impl Addr {
|
||||
#[inline]
|
||||
pub fn is_heap_bound(&self) -> bool {
|
||||
match self {
|
||||
Addr::Char(_) | Addr::CharCode(_) | Addr::EmptyList |
|
||||
Addr::CutPoint(_) | Addr::Usize(_) | Addr::Fixnum(_) |
|
||||
Addr::Float(_) => {
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_ref(&self) -> bool {
|
||||
match self {
|
||||
Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) | Addr::PStrTail(..) => {
|
||||
Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
@@ -141,16 +180,115 @@ impl Addr {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_var(&self) -> Option<Ref> {
|
||||
match self {
|
||||
&Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
|
||||
&Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
|
||||
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
|
||||
&Addr::PStrTail(h, n) => Some(Ref::PStrTail(h, n)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn order_category(&self, heap: &Heap) -> Option<TermOrderCategory> {
|
||||
match Number::try_from((*self, heap)) {
|
||||
Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => {
|
||||
Some(TermOrderCategory::Integer)
|
||||
}
|
||||
Ok(Number::Float(_)) => {
|
||||
Some(TermOrderCategory::FloatingPoint)
|
||||
}
|
||||
_ => {
|
||||
match self {
|
||||
Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => {
|
||||
Some(TermOrderCategory::Variable)
|
||||
}
|
||||
Addr::Float(_) => {
|
||||
Some(TermOrderCategory::FloatingPoint)
|
||||
}
|
||||
&Addr::Con(h) => {
|
||||
match &heap[h] {
|
||||
HeapCellValue::Atom(..) => {
|
||||
Some(TermOrderCategory::Atom)
|
||||
}
|
||||
HeapCellValue::DBRef(_) => {
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Addr::Char(_) | Addr::EmptyList => {
|
||||
Some(TermOrderCategory::Atom)
|
||||
}
|
||||
Addr::CharCode(_) | Addr::Fixnum(_) | Addr::Usize(_) => {
|
||||
Some(TermOrderCategory::Integer)
|
||||
}
|
||||
Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
|
||||
Some(TermOrderCategory::Compound)
|
||||
}
|
||||
Addr::CutPoint(_) | Addr::Stream(_) => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_constant(&self, machine_st: &MachineState) -> Option<Constant> {
|
||||
match self {
|
||||
&Addr::Char(c) => {
|
||||
Some(Constant::Char(c))
|
||||
}
|
||||
&Addr::CharCode(c) => {
|
||||
Some(Constant::CharCode(c))
|
||||
}
|
||||
&Addr::Con(h) => {
|
||||
match &machine_st.heap[h] {
|
||||
&HeapCellValue::Atom(ref name, ref op) => {
|
||||
Some(Constant::Atom(name.clone(), op.clone()))
|
||||
}
|
||||
&HeapCellValue::Integer(ref n) => {
|
||||
Some(Constant::Integer(n.clone()))
|
||||
}
|
||||
&HeapCellValue::Rational(ref n) => {
|
||||
Some(Constant::Rational(n.clone()))
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
&Addr::EmptyList => {
|
||||
Some(Constant::EmptyList)
|
||||
}
|
||||
&Addr::Fixnum(n) => {
|
||||
Some(Constant::Fixnum(n))
|
||||
}
|
||||
&Addr::Float(f) => {
|
||||
Some(Constant::Float(f))
|
||||
}
|
||||
&Addr::PStrLocation(h, n) => {
|
||||
let mut heap_pstr_iter =
|
||||
machine_st.heap_pstr_iter(Addr::PStrLocation(h, n));
|
||||
|
||||
let buf = heap_pstr_iter.to_string();
|
||||
let end_addr = heap_pstr_iter.focus();
|
||||
|
||||
if end_addr == Addr::EmptyList {
|
||||
Some(Constant::String(Rc::new(buf)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_protected(&self, e: usize) -> bool {
|
||||
match self {
|
||||
&Addr::StackCell(addr, _) if addr >= e => false,
|
||||
@@ -164,12 +302,13 @@ impl Add<usize> for Addr {
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
Addr::Stream(h) => Addr::Stream(h + rhs),
|
||||
Addr::Con(h) => Addr::Con(h + rhs),
|
||||
Addr::Lis(a) => Addr::Lis(a + rhs),
|
||||
Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
|
||||
Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
|
||||
Addr::Str(s) => Addr::Str(s + rhs),
|
||||
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n),
|
||||
Addr::PStrTail(h, n) => Addr::PStrTail(h + rhs, n),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
@@ -181,11 +320,12 @@ impl Sub<i64> for Addr {
|
||||
fn sub(self, rhs: i64) -> Self::Output {
|
||||
if rhs < 0 {
|
||||
match self {
|
||||
Addr::Stream(h) => Addr::Stream(h + rhs.abs() as usize),
|
||||
Addr::Con(h) => Addr::Con(h + rhs.abs() as usize),
|
||||
Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize),
|
||||
Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize),
|
||||
Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize),
|
||||
Addr::Str(s) => Addr::Str(s + rhs.abs() as usize),
|
||||
Addr::PStrTail(h, n) => Addr::PStrTail(h + rhs.abs() as usize, n),
|
||||
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n),
|
||||
_ => self,
|
||||
}
|
||||
@@ -200,11 +340,12 @@ impl Sub<usize> for Addr {
|
||||
|
||||
fn sub(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
Addr::Stream(h) => Addr::Stream(h - rhs),
|
||||
Addr::Con(h) => Addr::Con(h - rhs),
|
||||
Addr::Lis(a) => Addr::Lis(a - rhs),
|
||||
Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
|
||||
Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
|
||||
Addr::Str(s) => Addr::Str(s - rhs),
|
||||
Addr::PStrTail(h, n) => Addr::PStrTail(h - rhs, n),
|
||||
Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n),
|
||||
_ => self,
|
||||
}
|
||||
@@ -230,27 +371,76 @@ impl From<Ref> for TrailRef {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum HeapCellValue {
|
||||
Addr(Addr),
|
||||
Atom(ClauseName, Option<SharedOpDesc>),
|
||||
DBRef(DBRef),
|
||||
Integer(Rc<Integer>),
|
||||
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
|
||||
PartialString(PartialString),
|
||||
Rational(Rc<Rational>),
|
||||
PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant.
|
||||
Stream(Stream),
|
||||
}
|
||||
|
||||
impl HeapCellValue {
|
||||
#[inline]
|
||||
pub fn as_addr(&self, focus: usize) -> Addr {
|
||||
match self {
|
||||
HeapCellValue::Addr(ref a) => {
|
||||
a.clone()
|
||||
*a
|
||||
}
|
||||
HeapCellValue::Atom(..) | HeapCellValue::DBRef(..) | HeapCellValue::Integer(..) |
|
||||
HeapCellValue::Rational(..) => {
|
||||
Addr::Con(focus)
|
||||
}
|
||||
HeapCellValue::NamedStr(_, _, _) => {
|
||||
Addr::Str(focus)
|
||||
}
|
||||
HeapCellValue::PartialString(_) => {
|
||||
HeapCellValue::PartialString(..) => {
|
||||
Addr::PStrLocation(focus, 0)
|
||||
}
|
||||
HeapCellValue::Stream(_) => {
|
||||
Addr::Stream(focus)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn context_free_clone(&self) -> HeapCellValue {
|
||||
match self {
|
||||
&HeapCellValue::Addr(addr) => {
|
||||
HeapCellValue::Addr(addr)
|
||||
}
|
||||
&HeapCellValue::Atom(ref name, ref op) => {
|
||||
HeapCellValue::Atom(name.clone(), op.clone())
|
||||
}
|
||||
&HeapCellValue::DBRef(ref db_ref) => {
|
||||
HeapCellValue::DBRef(db_ref.clone())
|
||||
}
|
||||
&HeapCellValue::Integer(ref n) => {
|
||||
HeapCellValue::Integer(n.clone())
|
||||
}
|
||||
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
|
||||
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
|
||||
}
|
||||
&HeapCellValue::Rational(ref r) => {
|
||||
HeapCellValue::Rational(r.clone())
|
||||
}
|
||||
&HeapCellValue::PartialString(ref pstr, has_tail) => {
|
||||
HeapCellValue::PartialString(pstr.clone(), has_tail)
|
||||
}
|
||||
&HeapCellValue::Stream(_) => {
|
||||
HeapCellValue::Stream(Stream::null_stream())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Addr> for HeapCellValue {
|
||||
#[inline]
|
||||
fn from(value: Addr) -> HeapCellValue {
|
||||
HeapCellValue::Addr(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
|
||||
@@ -428,37 +618,31 @@ impl LocalCodePtr {
|
||||
LocalCodePtr::DirEntry(p) => {
|
||||
heap.append(functor!(
|
||||
"dir_entry",
|
||||
1,
|
||||
[heap_integer!(Integer::from(*p))]
|
||||
[integer(*p)]
|
||||
));
|
||||
}
|
||||
LocalCodePtr::InSituDirEntry(p) => {
|
||||
heap.append(functor!(
|
||||
"in_situ_dir_entry",
|
||||
1,
|
||||
[heap_integer!(Integer::from(*p))]
|
||||
[integer(*p)]
|
||||
));
|
||||
}
|
||||
LocalCodePtr::TopLevel(chunk_num, offset) => {
|
||||
heap.append(functor!(
|
||||
"top_level",
|
||||
2,
|
||||
[heap_integer!(Integer::from(*chunk_num)),
|
||||
heap_integer!(Integer::from(*offset))]
|
||||
[integer(*chunk_num), integer(*offset)]
|
||||
));
|
||||
}
|
||||
LocalCodePtr::UserGoalExpansion(p) => {
|
||||
heap.append(functor!(
|
||||
"user_goal_expansion",
|
||||
1,
|
||||
[heap_integer!(Integer::from(*p))]
|
||||
[integer(*p)]
|
||||
));
|
||||
}
|
||||
LocalCodePtr::UserTermExpansion(p) => {
|
||||
heap.append(functor!(
|
||||
"user_term_expansion",
|
||||
1,
|
||||
[heap_integer!(Integer::from(*p))]
|
||||
[integer(*p)]
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -470,8 +654,12 @@ impl LocalCodePtr {
|
||||
impl PartialOrd<CodePtr> for CodePtr {
|
||||
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
|
||||
match (self, other) {
|
||||
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => l1.partial_cmp(l2),
|
||||
_ => Some(Ordering::Greater),
|
||||
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => {
|
||||
l1.partial_cmp(l2)
|
||||
}
|
||||
_ => {
|
||||
Some(Ordering::Greater)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -486,8 +674,12 @@ impl PartialOrd<LocalCodePtr> for LocalCodePtr {
|
||||
| (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
|
||||
p1.partial_cmp(p2)
|
||||
}
|
||||
(_, &LocalCodePtr::TopLevel(_, _)) => Some(Ordering::Less),
|
||||
_ => Some(Ordering::Greater),
|
||||
(_, &LocalCodePtr::TopLevel(_, _)) => {
|
||||
Some(Ordering::Less)
|
||||
}
|
||||
_ => {
|
||||
Some(Ordering::Greater)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -613,17 +805,19 @@ impl ModuleStub {
|
||||
}
|
||||
|
||||
pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
|
||||
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
|
||||
|
||||
pub struct IndexStore {
|
||||
pub(super) atom_tbl: TabledData<Atom>,
|
||||
pub(super) code_dir: CodeDir,
|
||||
pub(super) module_dir: ModuleDir,
|
||||
pub(super) dynamic_code_dir: DynamicCodeDir,
|
||||
pub(super) global_variables: GlobalVarDir,
|
||||
pub(super) in_situ_code_dir: InSituCodeDir,
|
||||
pub(super) in_situ_module_dir: ModuleStubDir,
|
||||
pub(super) module_dir: ModuleDir,
|
||||
pub(super) modules: ModuleDir,
|
||||
pub(super) op_dir: OpDir,
|
||||
pub(super) stream_aliases: StreamAliasDir,
|
||||
}
|
||||
|
||||
impl IndexStore {
|
||||
@@ -710,6 +904,7 @@ impl IndexStore {
|
||||
in_situ_module_dir: ModuleStubDir::new(),
|
||||
op_dir: default_op_dir(),
|
||||
modules: ModuleDir::new(),
|
||||
stream_aliases: StreamAliasDir::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,13 +935,13 @@ impl IndexStore {
|
||||
let r_w_h = clause_name!("run_cleaners_with_handling");
|
||||
let r_wo_h = clause_name!("run_cleaners_without_handling");
|
||||
|
||||
let non_iso = clause_name!("non_iso");
|
||||
let iso_ext = clause_name!("iso_ext");
|
||||
|
||||
let r_w_h = self
|
||||
.get_internal(r_w_h, 0, non_iso.clone())
|
||||
.get_internal(r_w_h, 0, iso_ext.clone())
|
||||
.and_then(|item| item.local());
|
||||
let r_wo_h = self
|
||||
.get_internal(r_wo_h, 1, non_iso)
|
||||
.get_internal(r_wo_h, 1, iso_ext)
|
||||
.and_then(|item| item.local());
|
||||
|
||||
if let Some(r_w_h) = r_w_h {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::tabled_rc::*;
|
||||
|
||||
use crate::prolog::clause_types::*;
|
||||
use crate::prolog::forms::*;
|
||||
use crate::prolog::heap_print::*;
|
||||
use crate::prolog::machine::attributed_variables::*;
|
||||
use crate::prolog::machine::copier::*;
|
||||
use crate::prolog::machine::heap::*;
|
||||
@@ -9,16 +11,191 @@ use crate::prolog::machine::machine_errors::*;
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
use crate::prolog::machine::modules::*;
|
||||
use crate::prolog::machine::stack::*;
|
||||
use crate::prolog::read::PrologStream;
|
||||
use crate::prolog::machine::streams::*;
|
||||
use crate::prolog::read::readline;
|
||||
use crate::prolog::rug::Integer;
|
||||
|
||||
use downcast::Any;
|
||||
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::io::{stdout, Write};
|
||||
use std::convert::TryFrom;
|
||||
use std::io::Write;
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
pub(crate) struct HeapPStrIter<'a> {
|
||||
focus: Addr,
|
||||
machine_st: &'a MachineState,
|
||||
seen: IndexSet<Addr>,
|
||||
}
|
||||
|
||||
impl<'a> HeapPStrIter<'a> {
|
||||
#[inline]
|
||||
fn new(machine_st: &'a MachineState, focus: Addr) -> Self {
|
||||
HeapPStrIter {
|
||||
focus,
|
||||
machine_st,
|
||||
seen: IndexSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn focus(&'a self) -> Addr {
|
||||
self.machine_st.store(self.machine_st.deref(self.focus))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn to_string(&mut self) -> String {
|
||||
let mut buf = String::new();
|
||||
|
||||
while let Some(iteratee) = self.next() {
|
||||
match iteratee {
|
||||
PStrIteratee::Char(c) => {
|
||||
buf.push(c);
|
||||
}
|
||||
PStrIteratee::PStrSegment(h, n) => {
|
||||
match &self.machine_st.heap[h] {
|
||||
HeapCellValue::PartialString(ref pstr, _) => {
|
||||
buf += pstr.as_str_from(n);
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum PStrIteratee {
|
||||
Char(char),
|
||||
PStrSegment(usize, usize),
|
||||
}
|
||||
|
||||
impl<'a> Iterator for HeapPStrIter<'a> {
|
||||
type Item = PStrIteratee;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let addr = self.machine_st.store(self.machine_st.deref(self.focus));
|
||||
|
||||
if !self.seen.contains(&addr) {
|
||||
self.seen.insert(addr);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
||||
match addr {
|
||||
Addr::PStrLocation(h, n) => {
|
||||
if let &HeapCellValue::PartialString(_, has_tail) = &self.machine_st.heap[h] {
|
||||
self.focus = if has_tail {
|
||||
Addr::HeapCell(h + 1)
|
||||
} else {
|
||||
Addr::EmptyList
|
||||
};
|
||||
|
||||
return Some(PStrIteratee::PStrSegment(h, n));
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
Addr::Lis(l) => {
|
||||
let addr = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l)));
|
||||
|
||||
let opt_c = match addr {
|
||||
Addr::Con(h) if self.machine_st.heap.atom_at(h) => {
|
||||
if let HeapCellValue::Atom(ref atom, _) = &self.machine_st.heap[h] {
|
||||
if atom.is_char() {
|
||||
Some(atom.as_str().chars().next().unwrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
Addr::Char(c) => {
|
||||
Some(c)
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(c) = opt_c {
|
||||
self.focus = Addr::HeapCell(l + 1);
|
||||
return Some(PStrIteratee::Char(c));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Addr::EmptyList => {
|
||||
self.focus = Addr::EmptyList;
|
||||
return None;
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn compare_pstr_to_string<'a>(
|
||||
heap_pstr_iter: &mut HeapPStrIter<'a>,
|
||||
s: &String,
|
||||
) -> Option<usize> {
|
||||
let mut s_offset = 0;
|
||||
|
||||
while let Some(iteratee) = heap_pstr_iter.next() {
|
||||
match iteratee {
|
||||
PStrIteratee::Char(c1) => {
|
||||
if let Some(c2) = s[s_offset ..].chars().next() {
|
||||
if c1 != c2 {
|
||||
return None;
|
||||
} else {
|
||||
s_offset += c1.len_utf8();
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
PStrIteratee::PStrSegment(h, n) => {
|
||||
match heap_pstr_iter.machine_st.heap[h] {
|
||||
HeapCellValue::PartialString(ref pstr, _) => {
|
||||
let t = pstr.as_str_from(n);
|
||||
|
||||
if s[s_offset ..].starts_with(t) {
|
||||
s_offset += t.len();
|
||||
} else if t.starts_with(&s[s_offset ..]) {
|
||||
heap_pstr_iter.focus =
|
||||
Addr::PStrLocation(h, n + s[s_offset ..].len());
|
||||
|
||||
s_offset += s[s_offset ..].len();
|
||||
return Some(s_offset);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(s_offset)
|
||||
}
|
||||
|
||||
pub struct Ball {
|
||||
pub(super) boundary: usize,
|
||||
pub(super) stub: Heap,
|
||||
@@ -57,13 +234,12 @@ impl Ball {
|
||||
|
||||
for heap_value in self.stub.iter_from(0) {
|
||||
stub.push(match heap_value {
|
||||
HeapCellValue::Addr(ref addr) => HeapCellValue::Addr(addr.clone() - diff),
|
||||
HeapCellValue::PartialString(ref pstr) => {
|
||||
let mut new_pstr = pstr.clone();
|
||||
new_pstr.tail = pstr.tail.clone() - diff;
|
||||
HeapCellValue::PartialString(new_pstr)
|
||||
&HeapCellValue::Addr(addr) => {
|
||||
HeapCellValue::Addr(addr - diff)
|
||||
}
|
||||
heap_value => {
|
||||
heap_value.context_free_clone()
|
||||
}
|
||||
heap_value => heap_value.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -185,14 +361,18 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
|
||||
let index = h - self.heap_boundary;
|
||||
self.stub[index].as_addr(h)
|
||||
}
|
||||
Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc].clone(),
|
||||
addr => addr,
|
||||
Addr::StackCell(fr, sc) => {
|
||||
self.stack.index_and_frame(fr)[sc]
|
||||
}
|
||||
addr => {
|
||||
addr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deref(&self, mut addr: Addr) -> Addr {
|
||||
loop {
|
||||
let value = self.store(addr.clone());
|
||||
let value = self.store(addr);
|
||||
|
||||
if value.is_ref() && value != addr {
|
||||
addr = value;
|
||||
@@ -225,9 +405,12 @@ impl Index<RegType> for MachineState {
|
||||
impl IndexMut<RegType> for MachineState {
|
||||
fn index_mut(&mut self, reg: RegType) -> &mut Self::Output {
|
||||
match reg {
|
||||
RegType::Temp(temp) => &mut self.registers[temp],
|
||||
RegType::Temp(temp) => {
|
||||
&mut self.registers[temp]
|
||||
}
|
||||
RegType::Perm(perm) => {
|
||||
let e = self.e;
|
||||
|
||||
&mut self.stack.index_and_frame_mut(e)[perm]
|
||||
}
|
||||
}
|
||||
@@ -242,8 +425,49 @@ pub(super) enum MachineMode {
|
||||
Write,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(super) enum HeapPtr {
|
||||
HeapCell(usize),
|
||||
PStrChar(usize, usize),
|
||||
PStrLocation(usize, usize),
|
||||
}
|
||||
|
||||
impl HeapPtr {
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn read(&self, heap: &Heap) -> Addr {
|
||||
match self {
|
||||
&HeapPtr::HeapCell(h) => {
|
||||
Addr::HeapCell(h)
|
||||
}
|
||||
&HeapPtr::PStrChar(h, n) => {
|
||||
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &heap[h] {
|
||||
if let Some(c) = pstr.range_from(n ..).next() {
|
||||
Addr::Char(c)
|
||||
} else if has_tail {
|
||||
Addr::HeapCell(h + 1)
|
||||
} else {
|
||||
Addr::EmptyList
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
&HeapPtr::PStrLocation(h, n) => {
|
||||
Addr::PStrLocation(h, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HeapPtr {
|
||||
fn default() -> Self {
|
||||
HeapPtr::HeapCell(0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MachineState {
|
||||
pub(super) s: usize,
|
||||
pub(super) s: HeapPtr,
|
||||
pub(super) p: CodePtr,
|
||||
pub(super) b: usize,
|
||||
pub(super) b0: usize,
|
||||
@@ -270,37 +494,208 @@ pub struct MachineState {
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(crate)
|
||||
fn read_term(
|
||||
&mut self,
|
||||
current_input_stream: &mut Stream,
|
||||
indices: &mut IndexStore,
|
||||
) -> CallResult {
|
||||
match self.read(
|
||||
&mut parsing_stream(current_input_stream.clone()),
|
||||
indices.atom_tbl.clone(),
|
||||
&indices.op_dir,
|
||||
) {
|
||||
Ok(term_write_result) => {
|
||||
let a1 = self[temp_v!(1)];
|
||||
self.unify(Addr::HeapCell(term_write_result.heap_loc), a1);
|
||||
|
||||
if self.fail {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut list_of_var_eqs = vec![];
|
||||
|
||||
for (var, binding) in term_write_result.var_dict.into_iter().rev() {
|
||||
let var_atom = clause_name!(var.to_string(), indices.atom_tbl);
|
||||
|
||||
let h = self.heap.h();
|
||||
let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
|
||||
|
||||
self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec));
|
||||
self.heap.push(HeapCellValue::Atom(var_atom, None));
|
||||
self.heap.push(HeapCellValue::Addr(binding));
|
||||
|
||||
list_of_var_eqs.push(Addr::Str(h));
|
||||
}
|
||||
|
||||
let a2 = self[temp_v!(2)];
|
||||
let list_offset =
|
||||
Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter()));
|
||||
|
||||
Ok(self.unify(list_offset, a2))
|
||||
}
|
||||
Err(err) => {
|
||||
if let ParserError::UnexpectedEOF = err {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
// reset the input stream after an input failure.
|
||||
*current_input_stream = readline::input_stream();
|
||||
|
||||
let h = self.heap.h();
|
||||
let syntax_error = MachineError::syntax_error(h, err);
|
||||
let stub = MachineError::functor_stub(clause_name!("read_term"), 2);
|
||||
|
||||
Err(self.error_form(syntax_error, stub))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn write_term<'a>(
|
||||
&'a self,
|
||||
op_dir: &'a OpDir,
|
||||
) -> Result<Option<HCPrinter<'a, PrinterOutputter>>, MachineStub>
|
||||
{
|
||||
let ignore_ops = self.store(self.deref(self[temp_v!(2)]));
|
||||
let numbervars = self.store(self.deref(self[temp_v!(3)]));
|
||||
let quoted = self.store(self.deref(self[temp_v!(4)]));
|
||||
let max_depth = self.store(self.deref(self[temp_v!(6)]));
|
||||
|
||||
let mut printer = HCPrinter::new(&self, op_dir, PrinterOutputter::new());
|
||||
|
||||
if let &Addr::Con(h) = &ignore_ops {
|
||||
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
|
||||
printer.ignore_ops = name.as_str() == "true";
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
if let &Addr::Con(h) = &numbervars {
|
||||
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
|
||||
printer.numbervars = name.as_str() == "true";
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
if let &Addr::Con(h) = "ed {
|
||||
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
|
||||
printer.quoted = name.as_str() == "true";
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
match Number::try_from((max_depth, &self.heap)) {
|
||||
Ok(Number::Fixnum(n)) => {
|
||||
if let Ok(n) = usize::try_from(n) {
|
||||
printer.max_depth = n;
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
Ok(Number::Integer(n)) => {
|
||||
if let Some(n) = n.to_usize() {
|
||||
printer.max_depth = n;
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
let stub = MachineError::functor_stub(clause_name!("write_term"), 2);
|
||||
|
||||
match self.try_from_list(temp_v!(5), stub) {
|
||||
Ok(addrs) => {
|
||||
let mut var_names: IndexMap<Addr, String> = IndexMap::new();
|
||||
|
||||
for addr in addrs {
|
||||
match addr {
|
||||
Addr::Str(s) => match &self.heap[s] {
|
||||
&HeapCellValue::NamedStr(2, ref name, _)
|
||||
if name.as_str() == "=" =>
|
||||
{
|
||||
let atom = self.heap[s + 1].as_addr(s + 1);
|
||||
let var = self.heap[s + 2].as_addr(s + 2);
|
||||
|
||||
let atom = match self.store(self.deref(atom)) {
|
||||
Addr::Con(h) => {
|
||||
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
|
||||
atom.to_string()
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
Addr::Char(c) => c.to_string(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let var = self.store(self.deref(var));
|
||||
|
||||
if var_names.contains_key(&var) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var_names.insert(var, atom);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
printer.var_names = var_names;
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some(printer))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn heap_pstr_iter<'a>(&'a self, focus: Addr) -> HeapPStrIter<'a> {
|
||||
HeapPStrIter::new(self, focus)
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn try_char_list(&self, addrs: Vec<Addr>) -> Result<String, MachineError> {
|
||||
let mut chars = String::new();
|
||||
let mut iter = addrs.iter();
|
||||
|
||||
while let Some(addr) = iter.next() {
|
||||
match addr {
|
||||
&Addr::Con(Constant::String(n, ref s))
|
||||
if self.flags.double_quotes.is_chars() => {
|
||||
if s.len() < n {
|
||||
chars += &s[n ..];
|
||||
}
|
||||
let addr = self.store(self.deref(*addr));
|
||||
|
||||
if iter.next().is_some() {
|
||||
return Err(MachineError::type_error(ValidType::Character, addr.clone()));
|
||||
}
|
||||
}
|
||||
&Addr::Con(Constant::Char(c)) => {
|
||||
match addr {
|
||||
Addr::Char(c) => {
|
||||
chars.push(c);
|
||||
continue;
|
||||
}
|
||||
&Addr::Con(Constant::Atom(ref name, _))
|
||||
if name.as_str().len() == 1 => {
|
||||
Addr::Con(h) => {
|
||||
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
|
||||
if name.is_char() {
|
||||
chars += name.as_str();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
};
|
||||
|
||||
let h = self.heap.h();
|
||||
|
||||
return Err(
|
||||
MachineError::type_error(ValidType::Character, addr.clone())
|
||||
MachineError::type_error(h, ValidType::Character, addr)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(chars)
|
||||
}
|
||||
@@ -384,15 +779,15 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
|
||||
fn try_in_situ_lookup(name: ClauseName, arity: usize, indices: &IndexStore) -> Option<usize>
|
||||
fn try_in_situ_lookup(name: ClauseName, arity: usize, indices: &IndexStore) -> Option<LocalCodePtr>
|
||||
{
|
||||
match indices.in_situ_code_dir.get(&(name.clone(), arity)) {
|
||||
Some(p) => Some(*p),
|
||||
Some(p) => Some(LocalCodePtr::InSituDirEntry(*p)),
|
||||
None =>
|
||||
match indices.code_dir.get(&(name, arity)) {
|
||||
Some(ref idx) => {
|
||||
if let IndexPtr::Index(p) = idx.0.borrow().0 {
|
||||
Some(p)
|
||||
Some(LocalCodePtr::DirEntry(p))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -411,12 +806,12 @@ fn try_in_situ(
|
||||
) -> CallResult {
|
||||
if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) {
|
||||
if last_call {
|
||||
machine_st.execute_at_index(arity, LocalCodePtr::DirEntry(p));
|
||||
machine_st.execute_at_index(arity, p);
|
||||
} else {
|
||||
machine_st.call_at_index(arity, LocalCodePtr::DirEntry(p));
|
||||
machine_st.call_at_index(arity, p);
|
||||
}
|
||||
|
||||
machine_st.p = in_situ_dir_entry!(p);
|
||||
machine_st.p = CodePtr::Local(p);
|
||||
Ok(())
|
||||
} else {
|
||||
let stub = MachineError::functor_stub(name.clone(), arity);
|
||||
@@ -435,7 +830,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
|
||||
|
||||
for i in 1 .. n + 1 {
|
||||
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone();
|
||||
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1];
|
||||
}
|
||||
|
||||
machine_st.num_of_args = n;
|
||||
@@ -474,7 +869,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
|
||||
|
||||
for i in 1 .. n + 1 {
|
||||
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone();
|
||||
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1];
|
||||
}
|
||||
|
||||
machine_st.num_of_args = n;
|
||||
@@ -510,7 +905,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
|
||||
|
||||
for i in 1 .. n + 1 {
|
||||
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone();
|
||||
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1];
|
||||
}
|
||||
|
||||
machine_st.num_of_args = n;
|
||||
@@ -536,8 +931,8 @@ pub(crate) trait CallPolicy: Any {
|
||||
attr_var_init_bindings_b,
|
||||
);
|
||||
|
||||
machine_st.stack.truncate(machine_st.b);
|
||||
machine_st.b = machine_st.stack.index_or_frame(b).prelude.b;
|
||||
machine_st.stack.truncate(b);
|
||||
|
||||
machine_st.hb = machine_st.heap.h();
|
||||
machine_st.p += offset;
|
||||
@@ -550,7 +945,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
|
||||
|
||||
for i in 1 .. n + 1 {
|
||||
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone();
|
||||
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1];
|
||||
}
|
||||
|
||||
machine_st.num_of_args = n;
|
||||
@@ -576,8 +971,8 @@ pub(crate) trait CallPolicy: Any {
|
||||
attr_var_init_bindings_b,
|
||||
);
|
||||
|
||||
machine_st.stack.truncate(machine_st.b);
|
||||
machine_st.b = machine_st.stack.index_or_frame(b).prelude.b;
|
||||
machine_st.stack.truncate(b);
|
||||
|
||||
machine_st.hb = machine_st.heap.h();
|
||||
machine_st.p += 1;
|
||||
@@ -667,11 +1062,12 @@ pub(crate) trait CallPolicy: Any {
|
||||
machine_st: &mut MachineState,
|
||||
ct: &BuiltInClauseType,
|
||||
indices: &mut IndexStore,
|
||||
parsing_stream: &mut PrologStream,
|
||||
current_input_stream: &mut Stream,
|
||||
current_output_stream: &mut Stream,
|
||||
) -> CallResult {
|
||||
match ct {
|
||||
&BuiltInClauseType::AcyclicTerm => {
|
||||
let addr = machine_st[temp_v!(1)].clone();
|
||||
let addr = machine_st[temp_v!(1)];
|
||||
machine_st.fail = machine_st.is_cyclic_term(addr);
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
}
|
||||
@@ -680,48 +1076,50 @@ pub(crate) trait CallPolicy: Any {
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
}
|
||||
&BuiltInClauseType::Compare => {
|
||||
let a1 = machine_st[temp_v!(1)].clone();
|
||||
let a2 = machine_st[temp_v!(2)].clone();
|
||||
let a3 = machine_st[temp_v!(3)].clone();
|
||||
let a1 = machine_st[temp_v!(1)];
|
||||
let a2 = machine_st[temp_v!(2)];
|
||||
let a3 = machine_st[temp_v!(3)];
|
||||
|
||||
let c = match machine_st.compare_term_test(&a2, &a3) {
|
||||
Ordering::Greater => {
|
||||
let atom = match machine_st.compare_term_test(&a2, &a3) {
|
||||
Some(Ordering::Greater) => {
|
||||
let spec = fetch_atom_op_spec(clause_name!(">"), None, &indices.op_dir);
|
||||
Addr::Con(Constant::Atom(clause_name!(">"), spec))
|
||||
HeapCellValue::Atom(clause_name!(">"), spec)
|
||||
}
|
||||
Ordering::Equal => {
|
||||
Some(Ordering::Equal) => {
|
||||
let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
|
||||
Addr::Con(Constant::Atom(clause_name!("="), spec))
|
||||
HeapCellValue::Atom(clause_name!("="), spec)
|
||||
}
|
||||
Ordering::Less => {
|
||||
None | Some(Ordering::Less) => {
|
||||
let spec = fetch_atom_op_spec(clause_name!("<"), None, &indices.op_dir);
|
||||
Addr::Con(Constant::Atom(clause_name!("<"), spec))
|
||||
HeapCellValue::Atom(clause_name!("<"), spec)
|
||||
}
|
||||
};
|
||||
|
||||
machine_st.unify(a1, c);
|
||||
let h = machine_st.heap.h();
|
||||
|
||||
machine_st.heap.push(atom);
|
||||
machine_st.unify(a1, Addr::Con(h));
|
||||
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
}
|
||||
&BuiltInClauseType::CompareTerm(qt) => {
|
||||
machine_st.compare_term(qt);
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
}
|
||||
&BuiltInClauseType::CyclicTerm => {
|
||||
let addr = machine_st[temp_v!(1)].clone();
|
||||
machine_st.fail = !machine_st.is_cyclic_term(addr);
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
}
|
||||
&BuiltInClauseType::Nl => {
|
||||
let mut stdout = stdout();
|
||||
write!(current_output_stream, "\n").unwrap();
|
||||
current_output_stream.flush().unwrap();
|
||||
|
||||
write!(stdout, "\n").unwrap();
|
||||
stdout.flush().unwrap();
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
}
|
||||
&BuiltInClauseType::Read => {
|
||||
match machine_st.read(parsing_stream, indices.atom_tbl.clone(), &indices.op_dir) {
|
||||
match machine_st.read(
|
||||
&mut parsing_stream(current_input_stream.clone()),
|
||||
indices.atom_tbl.clone(),
|
||||
&indices.op_dir,
|
||||
) {
|
||||
Ok(offset) => {
|
||||
let addr = machine_st[temp_v!(1)].clone();
|
||||
let addr = machine_st[temp_v!(1)];
|
||||
machine_st.unify(addr, Addr::HeapCell(offset.heap_loc));
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -741,8 +1139,8 @@ pub(crate) trait CallPolicy: Any {
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
}
|
||||
&BuiltInClauseType::Eq => {
|
||||
let a1 = machine_st[temp_v!(1)].clone();
|
||||
let a2 = machine_st[temp_v!(2)].clone();
|
||||
let a1 = machine_st[temp_v!(1)];
|
||||
let a2 = machine_st[temp_v!(2)];
|
||||
|
||||
machine_st.fail = machine_st.eq_test(a1, a2);
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
@@ -756,10 +1154,11 @@ pub(crate) trait CallPolicy: Any {
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
}
|
||||
&BuiltInClauseType::NotEq => {
|
||||
let a1 = machine_st[temp_v!(1)].clone();
|
||||
let a2 = machine_st[temp_v!(2)].clone();
|
||||
let a1 = machine_st[temp_v!(1)];
|
||||
let a2 = machine_st[temp_v!(2)];
|
||||
|
||||
machine_st.fail = if let Ordering::Equal = machine_st.compare_term_test(&a1, &a2) {
|
||||
machine_st.fail =
|
||||
if let Some(Ordering::Equal) = machine_st.compare_term_test(&a1, &a2) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -773,12 +1172,15 @@ pub(crate) trait CallPolicy: Any {
|
||||
let stub = MachineError::functor_stub(clause_name!("sort"), 2);
|
||||
let mut list = machine_st.try_from_list(temp_v!(1), stub)?;
|
||||
|
||||
list.sort_unstable_by(|a1, a2| machine_st.compare_term_test(a1, a2));
|
||||
list.sort_unstable_by(|a1, a2| {
|
||||
machine_st.compare_term_test(a1, a2).unwrap_or(Ordering::Less)
|
||||
});
|
||||
|
||||
machine_st.term_dedup(&mut list);
|
||||
|
||||
let heap_addr = Addr::HeapCell(machine_st.heap.to_list(list.into_iter()));
|
||||
|
||||
let r2 = machine_st[temp_v!(2)].clone();
|
||||
let r2 = machine_st[temp_v!(2)];
|
||||
machine_st.unify(r2, heap_addr);
|
||||
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
@@ -795,21 +1197,25 @@ pub(crate) trait CallPolicy: Any {
|
||||
key_pairs.push((key, val.clone()));
|
||||
}
|
||||
|
||||
key_pairs.sort_by(|a1, a2| machine_st.compare_term_test(&a1.0, &a2.0));
|
||||
key_pairs.sort_by(|a1, a2| {
|
||||
machine_st.compare_term_test(&a1.0, &a2.0).unwrap_or(Ordering::Less)
|
||||
});
|
||||
|
||||
let key_pairs = key_pairs.into_iter().map(|kp| kp.1);
|
||||
let heap_addr = Addr::HeapCell(machine_st.heap.to_list(key_pairs));
|
||||
|
||||
let r2 = machine_st[temp_v!(2)].clone();
|
||||
let r2 = machine_st[temp_v!(2)];
|
||||
machine_st.unify(r2, heap_addr);
|
||||
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
}
|
||||
&BuiltInClauseType::Is(r, ref at) => {
|
||||
let a1 = machine_st[r].clone();
|
||||
let a2 = machine_st.get_number(at)?;
|
||||
let a1 = machine_st[r];
|
||||
let n2 = machine_st.get_number(at)?;
|
||||
|
||||
let n2 = machine_st.heap.put_constant(n2.into());
|
||||
machine_st.unify(a1, n2);
|
||||
|
||||
machine_st.unify(a1, Addr::Con(a2.to_constant()));
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
}
|
||||
}
|
||||
@@ -842,13 +1248,20 @@ pub(crate) trait CallPolicy: Any {
|
||||
machine_st: &mut MachineState,
|
||||
arity: usize,
|
||||
indices: &mut IndexStore,
|
||||
parsing_stream: &mut PrologStream,
|
||||
current_input_stream: &mut Stream,
|
||||
current_output_stream: &mut Stream,
|
||||
) -> CallResult {
|
||||
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
||||
match ClauseType::from(name.clone(), arity, None) {
|
||||
ClauseType::BuiltIn(built_in) => {
|
||||
machine_st.setup_built_in_call(built_in.clone());
|
||||
self.call_builtin(machine_st, &built_in, indices, parsing_stream)?;
|
||||
self.call_builtin(
|
||||
machine_st,
|
||||
&built_in,
|
||||
indices,
|
||||
current_input_stream,
|
||||
current_output_stream,
|
||||
)?;
|
||||
}
|
||||
ClauseType::CallN => {
|
||||
machine_st.handle_internal_call_n(arity);
|
||||
@@ -876,11 +1289,13 @@ pub(crate) trait CallPolicy: Any {
|
||||
}
|
||||
}
|
||||
ClauseType::Hook(_) | ClauseType::System(_) => {
|
||||
let name = Addr::Con(Constant::Atom(name, None));
|
||||
let name = functor!(clause_name(name));
|
||||
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
|
||||
|
||||
return Err(machine_st
|
||||
.error_form(MachineError::type_error(ValidType::Callable, name), stub));
|
||||
return Err(machine_st.error_form(
|
||||
MachineError::type_error(machine_st.heap.h(), ValidType::Callable, name),
|
||||
stub,
|
||||
));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -928,10 +1343,17 @@ impl CallPolicy for CWILCallPolicy {
|
||||
machine_st: &mut MachineState,
|
||||
ct: &BuiltInClauseType,
|
||||
indices: &mut IndexStore,
|
||||
parsing_stream: &mut PrologStream,
|
||||
current_input_stream: &mut Stream,
|
||||
current_output_stream: &mut Stream,
|
||||
) -> CallResult {
|
||||
self.prev_policy
|
||||
.call_builtin(machine_st, ct, indices, parsing_stream)?;
|
||||
self.prev_policy.call_builtin(
|
||||
machine_st,
|
||||
ct,
|
||||
indices,
|
||||
current_input_stream,
|
||||
current_output_stream
|
||||
)?;
|
||||
|
||||
self.increment(machine_st)
|
||||
}
|
||||
|
||||
@@ -940,10 +1362,17 @@ impl CallPolicy for CWILCallPolicy {
|
||||
machine_st: &mut MachineState,
|
||||
arity: usize,
|
||||
indices: &mut IndexStore,
|
||||
parsing_stream: &mut PrologStream,
|
||||
current_input_stream: &mut Stream,
|
||||
current_output_stream: &mut Stream,
|
||||
) -> CallResult {
|
||||
self.prev_policy
|
||||
.call_n(machine_st, arity, indices, parsing_stream)?;
|
||||
self.prev_policy.call_n(
|
||||
machine_st,
|
||||
arity,
|
||||
indices,
|
||||
current_input_stream,
|
||||
current_output_stream,
|
||||
)?;
|
||||
|
||||
self.increment(machine_st)
|
||||
}
|
||||
}
|
||||
@@ -962,7 +1391,8 @@ pub(crate) struct CWILCallPolicy {
|
||||
}
|
||||
|
||||
impl CWILCallPolicy {
|
||||
pub(crate) fn new_in_place(policy: &mut Box<dyn CallPolicy>) {
|
||||
pub(crate)
|
||||
fn new_in_place(policy: &mut Box<dyn CallPolicy>) {
|
||||
let mut prev_policy: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {});
|
||||
mem::swap(&mut prev_policy, policy);
|
||||
|
||||
@@ -972,6 +1402,7 @@ impl CWILCallPolicy {
|
||||
limits: vec![],
|
||||
inference_limit_exceeded: false,
|
||||
};
|
||||
|
||||
*policy = Box::new(new_policy);
|
||||
}
|
||||
|
||||
@@ -983,10 +1414,10 @@ impl CWILCallPolicy {
|
||||
if let Some(&(ref limit, bp)) = self.limits.last() {
|
||||
if self.count == *limit {
|
||||
self.inference_limit_exceeded = true;
|
||||
|
||||
return Err(functor!(
|
||||
"inference_limit_exceeded",
|
||||
1,
|
||||
[HeapCellValue::Addr(Addr::Con(Constant::Usize(bp)))]
|
||||
[addr(Addr::Usize(bp))]
|
||||
));
|
||||
} else {
|
||||
self.count += 1;
|
||||
@@ -996,7 +1427,8 @@ impl CWILCallPolicy {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer {
|
||||
pub(crate)
|
||||
fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer {
|
||||
limit += &self.count;
|
||||
|
||||
match self.limits.last().cloned() {
|
||||
@@ -1007,7 +1439,8 @@ impl CWILCallPolicy {
|
||||
&self.count
|
||||
}
|
||||
|
||||
pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer {
|
||||
pub(crate)
|
||||
fn remove_limit(&mut self, b: usize) -> &Integer {
|
||||
if let Some((_, bp)) = self.limits.last().cloned() {
|
||||
if bp == b {
|
||||
self.limits.pop();
|
||||
@@ -1017,11 +1450,13 @@ impl CWILCallPolicy {
|
||||
&self.count
|
||||
}
|
||||
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
pub(crate)
|
||||
fn is_empty(&self) -> bool {
|
||||
self.limits.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn into_inner(&mut self) -> Box<dyn CallPolicy> {
|
||||
pub(crate)
|
||||
fn into_inner(&mut self) -> Box<dyn CallPolicy> {
|
||||
let mut new_inner: Box<dyn CallPolicy> = Box::new(DefaultCallPolicy {});
|
||||
mem::swap(&mut self.prev_policy, &mut new_inner);
|
||||
new_inner
|
||||
@@ -1030,16 +1465,16 @@ impl CWILCallPolicy {
|
||||
|
||||
pub(crate) trait CutPolicy: Any {
|
||||
// returns true iff we fail or cut redirected the MachineState's p itself
|
||||
fn cut(&mut self, _: &mut MachineState, _: RegType) -> bool;
|
||||
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool;
|
||||
}
|
||||
|
||||
downcast!(dyn CutPolicy);
|
||||
|
||||
fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool {
|
||||
fn cut_body(machine_st: &mut MachineState, addr: &Addr) -> bool {
|
||||
let b = machine_st.b;
|
||||
|
||||
match addr {
|
||||
Addr::Con(Constant::CutPoint(b0)) | Addr::Con(Constant::Usize(b0)) => {
|
||||
&Addr::CutPoint(b0) | &Addr::Usize(b0) => {
|
||||
if b > b0 {
|
||||
machine_st.b = b0;
|
||||
machine_st.tidy_trail();
|
||||
@@ -1057,14 +1492,14 @@ fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool {
|
||||
pub(crate) struct DefaultCutPolicy {}
|
||||
|
||||
pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) {
|
||||
let addr = machine_st.store(machine_st.deref(machine_st[r].clone()));
|
||||
cut_body(machine_st, addr);
|
||||
let addr = machine_st.store(machine_st.deref(machine_st[r]));
|
||||
cut_body(machine_st, &addr);
|
||||
}
|
||||
|
||||
impl CutPolicy for DefaultCutPolicy {
|
||||
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
|
||||
let addr = machine_st[r].clone();
|
||||
cut_body(machine_st, addr)
|
||||
let addr = machine_st[r];
|
||||
cut_body(machine_st, &addr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1102,7 +1537,7 @@ impl SCCCutPolicy {
|
||||
let (idx, arity) = if machine_st.block < prev_block {
|
||||
(dir_entry!(self.r_c_w_h), 0)
|
||||
} else {
|
||||
machine_st[temp_v!(1)] = Addr::Con(Constant::Usize(b_cutoff));
|
||||
machine_st[temp_v!(1)] = Addr::Usize(b_cutoff);
|
||||
(dir_entry!(self.r_c_wo_h), 1)
|
||||
};
|
||||
|
||||
@@ -1124,8 +1559,8 @@ impl CutPolicy for SCCCutPolicy {
|
||||
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
|
||||
let b = machine_st.b;
|
||||
|
||||
match machine_st[r].clone() {
|
||||
Addr::Con(Constant::Usize(b0)) | Addr::Con(Constant::CutPoint(b0)) => {
|
||||
match machine_st[r] {
|
||||
Addr::Usize(b0) | Addr::CutPoint(b0) => {
|
||||
if b > b0 {
|
||||
machine_st.b = b0;
|
||||
machine_st.tidy_trail();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,12 +19,15 @@ pub mod machine_errors;
|
||||
pub mod machine_indices;
|
||||
pub(super) mod machine_state;
|
||||
pub mod modules;
|
||||
mod partial_string;
|
||||
pub mod partial_string;
|
||||
mod raw_block;
|
||||
mod stack;
|
||||
pub(crate) mod streams;
|
||||
pub(super) mod term_expansion;
|
||||
pub mod toplevel;
|
||||
|
||||
#[macro_use]
|
||||
mod arithmetic_ops;
|
||||
#[macro_use]
|
||||
mod machine_state_impl;
|
||||
mod system_calls;
|
||||
@@ -36,14 +39,14 @@ use crate::prolog::machine::machine_errors::*;
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
use crate::prolog::machine::machine_state::*;
|
||||
use crate::prolog::machine::modules::*;
|
||||
use crate::prolog::machine::streams::*;
|
||||
use crate::prolog::machine::toplevel::*;
|
||||
use crate::prolog::read::PrologStream;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::mem;
|
||||
use std::ops::Index;
|
||||
use std::path::PathBuf;
|
||||
@@ -76,7 +79,8 @@ pub struct Machine {
|
||||
pub(super) indices: IndexStore,
|
||||
pub(super) code_repo: CodeRepo,
|
||||
pub(super) toplevel_idx: usize,
|
||||
pub(super) prolog_stream: ParsingStream<Box<dyn Read>>,
|
||||
pub(super) current_input_stream: Stream,
|
||||
pub(super) current_output_stream: Stream,
|
||||
}
|
||||
|
||||
impl Index<LocalCodePtr> for CodeRepo {
|
||||
@@ -149,8 +153,16 @@ impl SubModuleUser for IndexStore {
|
||||
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) {
|
||||
if let Some(ref code_idx) = self.code_dir.get(&(name.clone(), arity)) {
|
||||
if !code_idx.is_undefined() {
|
||||
match (name.as_str(), arity) {
|
||||
("term_expansion", 2) => {
|
||||
}
|
||||
("goal_expansion", 2) => {
|
||||
}
|
||||
_ => {
|
||||
println!("Warning: overwriting {}/{}", &name, arity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (p, module_name) = idx.0.borrow().clone();
|
||||
set_code_index!(code_idx, p, module_name);
|
||||
@@ -193,7 +205,11 @@ impl SubModuleUser for IndexStore {
|
||||
|
||||
#[inline]
|
||||
fn current_dir() -> std::path::PathBuf {
|
||||
let mut path_buf = std::path::PathBuf::from(file!());
|
||||
let mut path_buf = std::path::PathBuf::from(PROJECT_DIR);
|
||||
|
||||
// file!() always produces a path relative to PROJECT_DIR.
|
||||
path_buf = path_buf.join(std::path::PathBuf::from(file!()));
|
||||
|
||||
path_buf.pop();
|
||||
path_buf
|
||||
}
|
||||
@@ -212,7 +228,11 @@ impl Machine {
|
||||
current_dir.clone(),
|
||||
);
|
||||
|
||||
match compile_special_form(self, parsing_stream(VERIFY_ATTRS.as_bytes()), verify_attrs_src)
|
||||
match compile_special_form(
|
||||
self,
|
||||
Stream::from(VERIFY_ATTRS),
|
||||
verify_attrs_src,
|
||||
)
|
||||
{
|
||||
Ok(p) => {
|
||||
self.machine_st.attr_var_init.verify_attrs_loc = p;
|
||||
@@ -226,7 +246,11 @@ impl Machine {
|
||||
current_dir,
|
||||
);
|
||||
|
||||
match compile_special_form(self, parsing_stream(PROJECT_ATTRS.as_bytes()), project_attrs_src)
|
||||
match compile_special_form(
|
||||
self,
|
||||
Stream::from(PROJECT_ATTRS),
|
||||
project_attrs_src,
|
||||
)
|
||||
{
|
||||
Ok(p) => {
|
||||
self.machine_st.attr_var_init.project_attrs_loc = p;
|
||||
@@ -250,7 +274,7 @@ impl Machine {
|
||||
|
||||
compile_user_module(
|
||||
self,
|
||||
parsing_stream(TOPLEVEL.as_bytes()),
|
||||
Stream::from(TOPLEVEL),
|
||||
true,
|
||||
top_lvl_src,
|
||||
);
|
||||
@@ -264,7 +288,11 @@ impl Machine {
|
||||
|
||||
Ok(self.indices.insert_module(module))
|
||||
} else {
|
||||
Err(SessionError::ModuleNotFound)
|
||||
let err = ExistenceError::SourceSink(ModuleSource::File(
|
||||
clause_name!("$toplevel"),
|
||||
));
|
||||
|
||||
Err(SessionError::ExistenceError(err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +306,7 @@ impl Machine {
|
||||
|
||||
if path.is_file() {
|
||||
let file_src = match File::open(&path) {
|
||||
Ok(file_handle) => parsing_stream(file_handle),
|
||||
Ok(file_handle) => Stream::from(file_handle),
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
@@ -293,7 +321,7 @@ impl Machine {
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn reset(&mut self) {
|
||||
self.prolog_stream = readline::input_stream();
|
||||
self.current_input_stream = readline::input_stream();
|
||||
self.policies.cut_policy = Box::new(DefaultCutPolicy {});
|
||||
self.machine_st.reset();
|
||||
}
|
||||
@@ -319,8 +347,8 @@ impl Machine {
|
||||
// the first of these is the path to the scryer-prolog executable, so skip
|
||||
// it.
|
||||
for filename in env::args().skip(1) {
|
||||
let atom = atom!(filename, self.indices.atom_tbl);
|
||||
filename_atoms.push(Addr::Con(atom));
|
||||
let atom = clause_name!(filename, self.indices.atom_tbl);
|
||||
filename_atoms.push(HeapCellValue::Atom(atom, None));
|
||||
}
|
||||
|
||||
let list_addr =
|
||||
@@ -332,7 +360,7 @@ impl Machine {
|
||||
self.run_query();
|
||||
}
|
||||
|
||||
pub fn new(prolog_stream: PrologStream) -> Self
|
||||
pub fn new(current_input_stream: Stream, current_output_stream: Stream) -> Self
|
||||
{
|
||||
let mut wam = Machine {
|
||||
machine_st: MachineState::new(),
|
||||
@@ -341,7 +369,8 @@ impl Machine {
|
||||
indices: IndexStore::new(),
|
||||
code_repo: CodeRepo::new(),
|
||||
toplevel_idx: 0,
|
||||
prolog_stream,
|
||||
current_input_stream,
|
||||
current_output_stream,
|
||||
};
|
||||
|
||||
let atom_tbl = wam.indices.atom_tbl.clone();
|
||||
@@ -354,7 +383,7 @@ impl Machine {
|
||||
|
||||
compile_listing(
|
||||
&mut wam,
|
||||
parsing_stream(BUILTINS.as_bytes()),
|
||||
Stream::from(BUILTINS),
|
||||
default_index_store!(atom_tbl.clone()),
|
||||
true,
|
||||
ListingSource::from_file_and_path(
|
||||
@@ -365,25 +394,36 @@ impl Machine {
|
||||
|
||||
wam.compile_special_forms();
|
||||
|
||||
compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()), true,
|
||||
compile_user_module(&mut wam,
|
||||
Stream::from(ERROR),
|
||||
true,
|
||||
ListingSource::from_file_and_path(
|
||||
clause_name!("error"),
|
||||
lib_path.clone(),
|
||||
)
|
||||
);
|
||||
compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()), true,
|
||||
|
||||
compile_user_module(&mut wam,
|
||||
Stream::from(LISTS),
|
||||
true,
|
||||
ListingSource::from_file_and_path(
|
||||
clause_name!("lists"),
|
||||
lib_path.clone(),
|
||||
),
|
||||
);
|
||||
compile_user_module(&mut wam, parsing_stream(NON_ISO.as_bytes()), true,
|
||||
|
||||
compile_user_module(&mut wam,
|
||||
Stream::from(ISO_EXT),
|
||||
true,
|
||||
ListingSource::from_file_and_path(
|
||||
clause_name!("non_iso"),
|
||||
clause_name!("iso_ext"),
|
||||
lib_path.clone(),
|
||||
)
|
||||
);
|
||||
compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true,
|
||||
|
||||
compile_user_module(&mut wam,
|
||||
Stream::from(SI),
|
||||
true,
|
||||
ListingSource::from_file_and_path(
|
||||
clause_name!("si"),
|
||||
lib_path.clone(),
|
||||
@@ -514,15 +554,17 @@ impl Machine {
|
||||
HeapCellValue::NamedStr(arity, ref name, _)
|
||||
if *arity == 2 && name.as_str() == "/" => {
|
||||
let name = match &self.machine_st.heap[s+1] {
|
||||
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
|
||||
&HeapCellValue::Atom(ref name, _) =>
|
||||
name.clone(),
|
||||
_ =>
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let arity = match &self.machine_st.heap[s+2] {
|
||||
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
|
||||
&HeapCellValue::Integer(ref arity) =>
|
||||
arity.to_usize().unwrap(),
|
||||
&HeapCellValue::Addr(Addr::Fixnum(n)) =>
|
||||
usize::try_from(n).unwrap(),
|
||||
_ =>
|
||||
unreachable!()
|
||||
};
|
||||
@@ -532,22 +574,24 @@ impl Machine {
|
||||
HeapCellValue::NamedStr(arity, ref name, _)
|
||||
if *arity == 3 && name.as_str() == "op" => {
|
||||
let name = match &self.machine_st.heap[s+3] {
|
||||
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
|
||||
&HeapCellValue::Atom(ref name, _) =>
|
||||
name.clone(),
|
||||
_ =>
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let spec = match &self.machine_st.heap[s+2] {
|
||||
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
|
||||
&HeapCellValue::Atom(ref name, _) =>
|
||||
name.clone(),
|
||||
_ =>
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let prec = match &self.machine_st.heap[s+1] {
|
||||
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
|
||||
&HeapCellValue::Integer(ref arity) =>
|
||||
arity.to_usize().unwrap(),
|
||||
&HeapCellValue::Addr(Addr::Fixnum(n)) =>
|
||||
usize::try_from(n).unwrap(),
|
||||
_ =>
|
||||
unreachable!()
|
||||
};
|
||||
@@ -577,9 +621,13 @@ impl Machine {
|
||||
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
|
||||
|
||||
let module_spec = self.machine_st[temp_v!(1)].clone();
|
||||
let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
|
||||
Addr::Con(Constant::Atom(name, _)) => name,
|
||||
_ => unreachable!()
|
||||
let name = {
|
||||
let addr = self.machine_st.store(self.machine_st.deref(module_spec));
|
||||
|
||||
match self.machine_st.heap.index_addr(&addr).as_ref() {
|
||||
HeapCellValue::Atom(name, _) => name.clone(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
|
||||
let load_result = match to_src(name) {
|
||||
@@ -620,9 +668,13 @@ impl Machine {
|
||||
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
|
||||
|
||||
let module_spec = self.machine_st[temp_v!(1)].clone();
|
||||
let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
|
||||
Addr::Con(Constant::Atom(name, _)) => name,
|
||||
_ => unreachable!()
|
||||
let name = {
|
||||
let addr = self.machine_st.store(self.machine_st.deref(module_spec));
|
||||
|
||||
match self.machine_st.heap.index_addr(&addr).as_ref() {
|
||||
HeapCellValue::Atom(name, _) => name.clone(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
|
||||
let exports = match self.extract_module_export_list() {
|
||||
@@ -699,7 +751,7 @@ impl Machine {
|
||||
snapshot.e = self.machine_st.e;
|
||||
snapshot.b = self.machine_st.b;
|
||||
snapshot.b0 = self.machine_st.b0;
|
||||
snapshot.s = self.machine_st.s;
|
||||
snapshot.s = self.machine_st.s.clone();
|
||||
snapshot.tr = self.machine_st.tr;
|
||||
snapshot.num_of_args = self.machine_st.num_of_args;
|
||||
|
||||
@@ -751,12 +803,16 @@ impl Machine {
|
||||
&mut self.indices,
|
||||
&mut self.policies,
|
||||
&mut self.code_repo,
|
||||
&mut self.prolog_stream,
|
||||
&mut self.current_input_stream,
|
||||
&mut self.current_output_stream,
|
||||
);
|
||||
|
||||
match self.machine_st.p {
|
||||
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {}
|
||||
CodePtr::REPL(code_ptr, p) => self.handle_toplevel_command(code_ptr, p),
|
||||
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {
|
||||
}
|
||||
CodePtr::REPL(code_ptr, p) => {
|
||||
self.handle_toplevel_command(code_ptr, p)
|
||||
}
|
||||
CodePtr::DynamicTransaction(trans_type, p) => {
|
||||
// self.code_repo.cached_query is about to be overwritten by the term expander,
|
||||
// so hold onto it locally and restore it after the compiler has finished.
|
||||
@@ -784,29 +840,37 @@ impl MachineState {
|
||||
indices: &mut IndexStore,
|
||||
policies: &mut MachinePolicies,
|
||||
code_repo: &CodeRepo,
|
||||
prolog_stream: &mut PrologStream,
|
||||
current_input_stream: &mut Stream,
|
||||
current_output_stream: &mut Stream,
|
||||
) {
|
||||
match instr {
|
||||
&Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr),
|
||||
&Line::Arithmetic(ref arith_instr) => {
|
||||
self.execute_arith_instr(arith_instr)
|
||||
}
|
||||
&Line::Choice(ref choice_instr) => {
|
||||
self.execute_choice_instr(choice_instr, &mut policies.call_policy)
|
||||
}
|
||||
&Line::Cut(ref cut_instr) => {
|
||||
self.execute_cut_instr(cut_instr, &mut policies.cut_policy)
|
||||
}
|
||||
&Line::Control(ref control_instr) => self.execute_ctrl_instr(
|
||||
&Line::Control(ref control_instr) => {
|
||||
self.execute_ctrl_instr(
|
||||
indices,
|
||||
code_repo,
|
||||
&mut policies.call_policy,
|
||||
&mut policies.cut_policy,
|
||||
prolog_stream,
|
||||
current_input_stream,
|
||||
current_output_stream,
|
||||
control_instr,
|
||||
),
|
||||
)
|
||||
}
|
||||
&Line::Fact(ref fact_instr) => {
|
||||
self.execute_fact_instr(&fact_instr);
|
||||
self.p += 1;
|
||||
}
|
||||
&Line::Indexing(ref indexing_instr) => self.execute_indexing_instr(&indexing_instr),
|
||||
&Line::Indexing(ref indexing_instr) => {
|
||||
self.execute_indexing_instr(&indexing_instr)
|
||||
}
|
||||
&Line::IndexedChoice(ref choice_instr) => {
|
||||
self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy)
|
||||
}
|
||||
@@ -822,14 +886,22 @@ impl MachineState {
|
||||
indices: &mut IndexStore,
|
||||
policies: &mut MachinePolicies,
|
||||
code_repo: &CodeRepo,
|
||||
prolog_stream: &mut PrologStream,
|
||||
current_input_stream: &mut Stream,
|
||||
current_output_stream: &mut Stream,
|
||||
) {
|
||||
let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
|
||||
Some(instr) => instr,
|
||||
None => return,
|
||||
};
|
||||
|
||||
self.dispatch_instr(instr.as_ref(), indices, policies, code_repo, prolog_stream);
|
||||
self.dispatch_instr(
|
||||
instr.as_ref(),
|
||||
indices,
|
||||
policies,
|
||||
code_repo,
|
||||
current_input_stream,
|
||||
current_output_stream,
|
||||
);
|
||||
}
|
||||
|
||||
fn backtrack(&mut self) {
|
||||
@@ -880,7 +952,8 @@ impl MachineState {
|
||||
indices: &mut IndexStore,
|
||||
policies: &mut MachinePolicies,
|
||||
code_repo: &mut CodeRepo,
|
||||
prolog_stream: &mut PrologStream,
|
||||
current_input_stream: &mut Stream,
|
||||
current_output_stream: &mut Stream,
|
||||
) -> bool {
|
||||
loop {
|
||||
let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
|
||||
@@ -896,7 +969,14 @@ impl MachineState {
|
||||
None => return false,
|
||||
};
|
||||
|
||||
self.dispatch_instr(instr.as_ref(), indices, policies, code_repo, prolog_stream);
|
||||
self.dispatch_instr(
|
||||
instr.as_ref(),
|
||||
indices,
|
||||
policies,
|
||||
code_repo,
|
||||
current_input_stream,
|
||||
current_output_stream,
|
||||
);
|
||||
|
||||
if self.fail {
|
||||
self.backtrack();
|
||||
@@ -920,10 +1000,17 @@ impl MachineState {
|
||||
indices: &mut IndexStore,
|
||||
policies: &mut MachinePolicies,
|
||||
code_repo: &mut CodeRepo,
|
||||
prolog_stream: &mut PrologStream,
|
||||
current_input_stream: &mut Stream,
|
||||
current_output_stream: &mut Stream,
|
||||
) {
|
||||
loop {
|
||||
self.execute_instr(indices, policies, code_repo, prolog_stream);
|
||||
self.execute_instr(
|
||||
indices,
|
||||
policies,
|
||||
code_repo,
|
||||
current_input_stream,
|
||||
current_output_stream,
|
||||
);
|
||||
|
||||
if self.fail {
|
||||
self.backtrack();
|
||||
@@ -939,7 +1026,13 @@ impl MachineState {
|
||||
if !instigating_instr.as_ref().is_head_instr() {
|
||||
let cp = self.p.local();
|
||||
self.run_verify_attr_interrupt(cp);
|
||||
} else if !self.verify_attr_stepper(indices, policies, code_repo, prolog_stream) {
|
||||
} else if !self.verify_attr_stepper(
|
||||
indices,
|
||||
policies,
|
||||
code_repo,
|
||||
current_input_stream,
|
||||
current_output_stream,
|
||||
) {
|
||||
if self.fail {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
use crate::prolog::machine::raw_block::*;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use std::alloc;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::ops::RangeFrom;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
|
||||
pub(crate) struct PartialStringTraits {}
|
||||
|
||||
impl RawBlockTraits for PartialStringTraits {
|
||||
#[inline]
|
||||
fn init_size() -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn align() -> usize {
|
||||
mem::align_of::<char>()
|
||||
}
|
||||
pub struct PartialString {
|
||||
buf: *const u8,
|
||||
len: usize,
|
||||
_marker: PhantomData<[u8]>,
|
||||
}
|
||||
|
||||
pub struct PartialString {
|
||||
pub(super) buf: RawBlock<PartialStringTraits>,
|
||||
pub(super) tail: Addr,
|
||||
impl Drop for PartialString {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(self.len, mem::align_of::<u8>());
|
||||
alloc::dealloc(self.buf as *mut u8, layout);
|
||||
|
||||
self.buf = ptr::null();
|
||||
self.len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for PartialString {
|
||||
@@ -32,17 +32,10 @@ impl Clone for PartialString {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for PartialString {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self as *const _ == other as *const _
|
||||
}
|
||||
}
|
||||
|
||||
fn scan_for_terminator(src: &str) -> usize {
|
||||
fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
|
||||
let mut terminator_idx = 0;
|
||||
|
||||
for c in src.chars() {
|
||||
for c in iter {
|
||||
if c == '\u{0}' {
|
||||
break;
|
||||
}
|
||||
@@ -53,12 +46,61 @@ fn scan_for_terminator(src: &str) -> usize {
|
||||
terminator_idx
|
||||
}
|
||||
|
||||
pub struct PStrIter {
|
||||
buf: *const u8,
|
||||
}
|
||||
|
||||
impl PStrIter {
|
||||
#[inline]
|
||||
fn from(buf: *const u8, idx: usize) -> Self {
|
||||
PStrIter {
|
||||
buf: (buf as usize + idx) as *const _
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for PStrIter {
|
||||
type Item = char;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
let mut byte_count = 0;
|
||||
|
||||
for n in 0 .. mem::size_of::<char>() {
|
||||
let b = ptr::read((self.buf as usize + n) as *const u8);
|
||||
|
||||
if b == 0u8 {
|
||||
break;
|
||||
} else {
|
||||
byte_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if byte_count == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let slice = slice::from_raw_parts(self.buf, byte_count);
|
||||
let s = str::from_utf8(slice).unwrap();
|
||||
|
||||
if let Some(c) = s.chars().next() {
|
||||
self.buf = self.buf.offset(c.len_utf8() as isize);
|
||||
Some(c)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialString {
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn new(src: &str, h: usize) -> Option<(Self, &str)> {
|
||||
fn new(src: &str) -> Option<(Self, &str)> {
|
||||
let pstr = PartialString {
|
||||
buf: RawBlock::with_capacity(src.len() + '\u{0}'.len_utf8()),
|
||||
tail: Addr::PStrTail(h, 0),
|
||||
buf: ptr::null_mut(),
|
||||
len: 0,
|
||||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
@@ -66,22 +108,51 @@ impl PartialString {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn empty() -> Self {
|
||||
let mut pstr = PartialString {
|
||||
buf: ptr::null(),
|
||||
len: 0,
|
||||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(
|
||||
'\u{0}'.len_utf8(),
|
||||
mem::align_of::<u8>(),
|
||||
);
|
||||
|
||||
pstr.buf = alloc::alloc(layout) as *const _;
|
||||
pstr.len = '\u{0}'.len_utf8();
|
||||
|
||||
pstr.write_terminator_at(0);
|
||||
}
|
||||
|
||||
pstr
|
||||
}
|
||||
|
||||
unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
|
||||
let terminator_idx = scan_for_terminator(src);
|
||||
let terminator_idx = scan_for_terminator(src.chars());
|
||||
|
||||
if terminator_idx == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let new_top = self.buf.new_block(terminator_idx + '\u{0}'.len_utf8());
|
||||
let layout = alloc::Layout::from_size_align_unchecked(
|
||||
terminator_idx + '\u{0}'.len_utf8(),
|
||||
mem::align_of::<u8>(),
|
||||
);
|
||||
|
||||
self.buf = alloc::alloc(layout) as *const _;
|
||||
self.len = terminator_idx + '\u{0}'.len_utf8();
|
||||
|
||||
ptr::copy(
|
||||
src.as_ptr(),
|
||||
self.buf.top as *mut _,
|
||||
self.buf as *mut _,
|
||||
terminator_idx,
|
||||
);
|
||||
|
||||
self.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
|
||||
self.write_terminator_at(terminator_idx);
|
||||
|
||||
Some(if terminator_idx != src.len() {
|
||||
@@ -91,30 +162,38 @@ impl PartialString {
|
||||
})
|
||||
}
|
||||
|
||||
/* Ordinarily cloning of heap cell values is done in copy_term,
|
||||
* so we rely on it to set the tail correctly. here it's set to PStrTail(0, 0),
|
||||
* because we don't know its heap location. */
|
||||
pub(super)
|
||||
fn clone_from_offset(&self, n: usize) -> Self {
|
||||
let len =
|
||||
if self.len - '\u{0}'.len_utf8() > n {
|
||||
self.len - n - '\u{0}'.len_utf8()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let mut pstr = PartialString {
|
||||
buf: RawBlock::with_capacity(self.len() + '\u{0}'.len_utf8()),
|
||||
tail: Addr::PStrTail(0, 0),
|
||||
buf: ptr::null_mut(),
|
||||
len: len + '\u{0}'.len_utf8(),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let len = if self.len() > n { self.len() - n } else { 0 };
|
||||
let new_top = pstr.buf.new_block(len + '\u{0}'.len_utf8());
|
||||
let layout = alloc::Layout::from_size_align_unchecked(
|
||||
len + '\u{0}'.len_utf8(),
|
||||
mem::align_of::<u8>(),
|
||||
);
|
||||
|
||||
pstr.buf = alloc::alloc(layout);
|
||||
|
||||
if len > 0 {
|
||||
ptr::copy(
|
||||
(self.buf.base as usize + n) as *mut u8,
|
||||
pstr.buf.base as *mut _,
|
||||
(self.buf as usize + n) as *const u8,
|
||||
pstr.buf as *mut _,
|
||||
len,
|
||||
);
|
||||
}
|
||||
|
||||
pstr.write_terminator_at(len);
|
||||
pstr.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
|
||||
}
|
||||
|
||||
pstr
|
||||
@@ -125,37 +204,35 @@ impl PartialString {
|
||||
fn write_terminator_at(&mut self, index: usize) {
|
||||
unsafe {
|
||||
ptr::write(
|
||||
(self.buf.base as usize + index) as *mut u8,
|
||||
(self.buf as usize + index) as *mut u8,
|
||||
0u8,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn block_as_str(&self) -> &str {
|
||||
pub fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
|
||||
PStrIter::from(self.buf, index.start)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn at_end(&self, end_n: usize) -> bool {
|
||||
unsafe {
|
||||
let slice = slice::from_raw_parts(self.buf.base, self.len());
|
||||
str::from_utf8(slice).unwrap()
|
||||
ptr::read((self.buf as usize + end_n) as *const u8) == 0u8
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn tail_addr(&self) -> &Addr {
|
||||
&self.tail
|
||||
}
|
||||
pub fn as_str_from(&self, n: usize) -> &str {
|
||||
unsafe {
|
||||
let slice = slice::from_raw_parts(
|
||||
self.buf,
|
||||
self.len - '\u{0}'.len_utf8(),
|
||||
);
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.buf.top as usize - self.buf.base as usize
|
||||
}
|
||||
let s = str::from_utf8(slice).unwrap();
|
||||
|
||||
#[inline]
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
if (len + self.buf.base as usize) < self.buf.top as usize {
|
||||
self.buf.top = (len + self.buf.base as usize) as *const _;
|
||||
self.write_terminator_at(len);
|
||||
&s[n ..]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,20 +36,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
||||
block
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn with_capacity(cap: usize) -> Self {
|
||||
let mut block = RawBlock { size: 0,
|
||||
base: ptr::null(),
|
||||
top: ptr::null(),
|
||||
_marker: PhantomData };
|
||||
|
||||
unsafe {
|
||||
block.init_at_size(cap);
|
||||
}
|
||||
|
||||
block
|
||||
}
|
||||
|
||||
unsafe fn init_at_size(&mut self, cap: usize) {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
|
||||
|
||||
@@ -86,7 +72,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
||||
mem::replace(self, Self::empty_block())
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
fn free_space(&self) -> usize {
|
||||
debug_assert!(self.top >= self.base,
|
||||
|
||||
@@ -49,7 +49,6 @@ impl Drop for Stack {
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FramePrelude {
|
||||
is_or_frame: u8,
|
||||
pub num_cells: usize,
|
||||
}
|
||||
|
||||
@@ -62,7 +61,6 @@ pub struct AndFramePrelude {
|
||||
|
||||
pub struct AndFrame {
|
||||
pub prelude: AndFramePrelude,
|
||||
_marker: PhantomData<Addr>,
|
||||
}
|
||||
|
||||
impl AndFrame {
|
||||
@@ -101,24 +99,6 @@ impl IndexMut<usize> for AndFrame {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AndFrame {
|
||||
fn drop(&mut self) {
|
||||
let prelude_offset = prelude_size::<AndFramePrelude>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset;
|
||||
|
||||
for idx in 0 .. self.prelude.univ_prelude.num_cells {
|
||||
let index_offset = idx * mem::size_of::<Addr>();
|
||||
let ptr = (ptr + index_offset) as *mut Addr;
|
||||
|
||||
ptr::drop_in_place(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OrFramePrelude {
|
||||
pub univ_prelude: FramePrelude,
|
||||
pub e: usize,
|
||||
@@ -135,7 +115,6 @@ pub struct OrFramePrelude {
|
||||
|
||||
pub struct OrFrame {
|
||||
pub prelude: OrFramePrelude,
|
||||
_marker: PhantomData<Addr>
|
||||
}
|
||||
|
||||
impl Index<usize> for OrFrame {
|
||||
@@ -170,24 +149,6 @@ impl IndexMut<usize> for OrFrame {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for OrFrame {
|
||||
fn drop(&mut self) {
|
||||
let prelude_offset = prelude_size::<OrFramePrelude>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset;
|
||||
|
||||
for idx in 0 .. self.prelude.univ_prelude.num_cells {
|
||||
let index_offset = idx * mem::size_of::<Addr>();
|
||||
let ptr = (ptr + index_offset) as *mut Addr;
|
||||
|
||||
ptr::drop_in_place(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OrFrame {
|
||||
pub fn size_of(num_cells: usize) -> usize {
|
||||
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>()
|
||||
@@ -211,8 +172,6 @@ impl Stack {
|
||||
}
|
||||
|
||||
let and_frame = &mut *(self.buf.top as *mut AndFrame);
|
||||
|
||||
and_frame.prelude.univ_prelude.is_or_frame = 0;
|
||||
and_frame.prelude.univ_prelude.num_cells = num_cells;
|
||||
|
||||
let e = self.buf.top as usize - self.buf.base as usize;
|
||||
@@ -234,8 +193,6 @@ impl Stack {
|
||||
}
|
||||
|
||||
let or_frame = &mut *(self.buf.top as *mut OrFrame);
|
||||
|
||||
or_frame.prelude.univ_prelude.is_or_frame = 1;
|
||||
or_frame.prelude.univ_prelude.num_cells = num_cells;
|
||||
|
||||
let b = self.buf.top as usize - self.buf.base as usize;
|
||||
@@ -281,6 +238,7 @@ impl Stack {
|
||||
Stack { buf: self.buf.take(), _marker: PhantomData }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn truncate(&mut self, b: usize) {
|
||||
if b == 0 {
|
||||
self.inner_truncate(mem::align_of::<Addr>());
|
||||
@@ -289,42 +247,14 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inner_truncate(&mut self, b: usize) {
|
||||
let mut b = b + self.buf.base as usize;
|
||||
let base = b;
|
||||
|
||||
unsafe {
|
||||
while b as *const _ < self.buf.top {
|
||||
let univ_prelude = ptr::read(b as *const FramePrelude);
|
||||
|
||||
let offset = if univ_prelude.is_or_frame == 0 {
|
||||
let frame_ptr = b as *mut AndFrame;
|
||||
let frame = &mut *frame_ptr;
|
||||
let size_of_frame = AndFrame::size_of(frame.prelude.univ_prelude.num_cells);
|
||||
|
||||
ptr::drop_in_place(frame_ptr);
|
||||
|
||||
b + size_of_frame
|
||||
} else {
|
||||
debug_assert!(univ_prelude.is_or_frame == 1);
|
||||
|
||||
let frame_ptr = b as *mut OrFrame;
|
||||
let frame = &mut *frame_ptr;
|
||||
let size_of_frame = OrFrame::size_of(frame.prelude.univ_prelude.num_cells);
|
||||
|
||||
ptr::drop_in_place(frame_ptr);
|
||||
|
||||
b + size_of_frame
|
||||
};
|
||||
|
||||
b = offset;
|
||||
}
|
||||
let base = b + self.buf.base as usize;
|
||||
|
||||
if base < self.buf.top as usize {
|
||||
self.buf.top = base as *const _;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drop_in_place(&mut self) {
|
||||
self.truncate(mem::align_of::<Addr>());
|
||||
|
||||
356
src/prolog/machine/streams.rs
Normal file
356
src/prolog/machine/streams.rs
Normal file
@@ -0,0 +1,356 @@
|
||||
use crate::prolog_parser::ast::*;
|
||||
|
||||
use crate::prolog::read::readline::*;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::{stdin, stdout, Cursor, ErrorKind, Read, Write};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::net::TcpStream;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum StreamType {
|
||||
Binary,
|
||||
Text,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum EOFAction {
|
||||
EOFCode,
|
||||
Error,
|
||||
Reset,
|
||||
}
|
||||
|
||||
/* all these streams are closed automatically when the instance is
|
||||
* dropped. */
|
||||
pub enum StreamInstance {
|
||||
Bytes(Cursor<Vec<u8>>),
|
||||
DynReadSource(Box<dyn Read>),
|
||||
File(File),
|
||||
Null,
|
||||
ReadlineStream(ReadlineStream),
|
||||
Stdin,
|
||||
Stdout,
|
||||
TcpStream(TcpStream),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct WrappedStreamInstance(Rc<RefCell<StreamInstance>>);
|
||||
|
||||
impl WrappedStreamInstance {
|
||||
#[inline]
|
||||
fn new(stream_inst: StreamInstance) -> Self {
|
||||
WrappedStreamInstance(Rc::new(RefCell::new(stream_inst)))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for WrappedStreamInstance {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Rc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for WrappedStreamInstance {}
|
||||
|
||||
impl Hash for WrappedStreamInstance {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let rc = &self.0;
|
||||
let ptr = Rc::into_raw(rc.clone());
|
||||
|
||||
state.write_usize(ptr as usize);
|
||||
|
||||
unsafe {
|
||||
// necessary to avoid memory leak.
|
||||
let _ = Rc::from_raw(ptr);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum StreamError {
|
||||
ReadFromOutputStream,
|
||||
WriteToInputStream,
|
||||
FlushToInputStream,
|
||||
}
|
||||
|
||||
impl fmt::Display for StreamError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
StreamError::ReadFromOutputStream => {
|
||||
write!(f, "attempted to read from a write-only stream")
|
||||
}
|
||||
StreamError::WriteToInputStream => {
|
||||
write!(f, "attempted to write to a read-only stream")
|
||||
}
|
||||
StreamError::FlushToInputStream => {
|
||||
write!(f, "attempted to flush a read-only stream")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for StreamError {}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct StreamOptions {
|
||||
pub stream_type: StreamType,
|
||||
pub reposition: bool,
|
||||
pub alias: Option<ClauseName>,
|
||||
pub eof_action: EOFAction,
|
||||
}
|
||||
|
||||
impl Default for StreamOptions {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
StreamOptions {
|
||||
stream_type: StreamType::Text,
|
||||
reposition: false,
|
||||
alias: None,
|
||||
eof_action: EOFAction::EOFCode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Stream {
|
||||
pub options: StreamOptions,
|
||||
stream_inst: WrappedStreamInstance,
|
||||
}
|
||||
|
||||
impl From<String> for Stream {
|
||||
fn from(string: String) -> Self {
|
||||
Stream {
|
||||
options: StreamOptions::default(),
|
||||
stream_inst: WrappedStreamInstance::new(
|
||||
StreamInstance::Bytes(Cursor::new(string.into_bytes()))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ReadlineStream> for Stream {
|
||||
fn from(rl_stream: ReadlineStream) -> Self {
|
||||
Stream {
|
||||
options: StreamOptions::default(),
|
||||
stream_inst: WrappedStreamInstance::new(
|
||||
StreamInstance::ReadlineStream(rl_stream)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Stream {
|
||||
fn from(src: &'static str) -> Stream {
|
||||
Stream {
|
||||
options: StreamOptions::default(),
|
||||
stream_inst: WrappedStreamInstance::new(
|
||||
StreamInstance::DynReadSource(Box::new(src.as_bytes()))
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<File> for Stream {
|
||||
fn from(file: File) -> Stream {
|
||||
Stream {
|
||||
options: StreamOptions::default(),
|
||||
stream_inst: WrappedStreamInstance::new(
|
||||
StreamInstance::File(file)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream {
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn as_ptr(&self) -> *const RefCell<StreamInstance> {
|
||||
let rc = self.stream_inst.0.clone();
|
||||
let ptr = Rc::into_raw(rc);
|
||||
|
||||
unsafe {
|
||||
// must be done to avoid memory leak.
|
||||
let _ = Rc::from_raw(ptr);
|
||||
}
|
||||
|
||||
ptr
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn stdout() -> Self {
|
||||
Stream {
|
||||
options: StreamOptions::default(),
|
||||
stream_inst: WrappedStreamInstance::new(
|
||||
StreamInstance::Stdout
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn stdin() -> Self {
|
||||
Stream {
|
||||
options: StreamOptions::default(),
|
||||
stream_inst: WrappedStreamInstance::new(
|
||||
StreamInstance::Stdin
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn null_stream() -> Self {
|
||||
Stream {
|
||||
options: StreamOptions::default(), // TODO: null_options?
|
||||
stream_inst: WrappedStreamInstance::new(
|
||||
StreamInstance::Null
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn is_stdout(&self) -> bool {
|
||||
match *self.stream_inst.0.borrow() {
|
||||
StreamInstance::Stdout => {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn is_stdin(&self) -> bool {
|
||||
match *self.stream_inst.0.borrow() {
|
||||
StreamInstance::Stdin | StreamInstance::ReadlineStream(_) => {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn is_input_stream(&self) -> bool {
|
||||
match *self.stream_inst.0.borrow() {
|
||||
StreamInstance::Stdin
|
||||
| StreamInstance::TcpStream(_)
|
||||
| StreamInstance::Bytes(_)
|
||||
| StreamInstance::ReadlineStream(_)
|
||||
| StreamInstance::DynReadSource(_)
|
||||
| StreamInstance::File(_) => {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn is_output_stream(&self) -> bool {
|
||||
match *self.stream_inst.0.borrow() {
|
||||
StreamInstance::Stdout
|
||||
| StreamInstance::TcpStream(_)
|
||||
| StreamInstance::Bytes(_)
|
||||
| StreamInstance::File(_) => {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Stream {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
match *self.stream_inst.0.borrow_mut() {
|
||||
StreamInstance::File(ref mut file) => {
|
||||
file.read(buf)
|
||||
}
|
||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
||||
tcp_stream.read(buf)
|
||||
}
|
||||
StreamInstance::ReadlineStream(ref mut rl_stream) => {
|
||||
rl_stream.read(buf)
|
||||
}
|
||||
StreamInstance::DynReadSource(ref mut src) => {
|
||||
src.read(buf)
|
||||
}
|
||||
StreamInstance::Bytes(ref mut cursor) => {
|
||||
cursor.read(buf)
|
||||
}
|
||||
StreamInstance::Stdin => {
|
||||
stdin().read(buf)
|
||||
}
|
||||
StreamInstance::Stdout | StreamInstance::Null => {
|
||||
Err(std::io::Error::new(
|
||||
ErrorKind::PermissionDenied,
|
||||
StreamError::ReadFromOutputStream,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Stream {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
match *self.stream_inst.0.borrow_mut() {
|
||||
StreamInstance::File(ref mut file) => {
|
||||
file.write(buf)
|
||||
}
|
||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
||||
tcp_stream.write(buf)
|
||||
}
|
||||
StreamInstance::Bytes(ref mut cursor) => {
|
||||
cursor.write(buf)
|
||||
}
|
||||
StreamInstance::Stdout => {
|
||||
stdout().write(buf)
|
||||
}
|
||||
_ => {
|
||||
Err(std::io::Error::new(
|
||||
ErrorKind::PermissionDenied,
|
||||
StreamError::WriteToInputStream,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
match *self.stream_inst.0.borrow_mut() {
|
||||
StreamInstance::File(ref mut file) => {
|
||||
file.flush()
|
||||
}
|
||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
||||
tcp_stream.flush()
|
||||
}
|
||||
StreamInstance::Bytes(ref mut cursor) => {
|
||||
cursor.flush()
|
||||
}
|
||||
StreamInstance::Stdout => {
|
||||
stdout().flush()
|
||||
}
|
||||
_ => {
|
||||
Err(std::io::Error::new(
|
||||
ErrorKind::PermissionDenied,
|
||||
StreamError::FlushToInputStream,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: write a Seek instance.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,35 +8,9 @@ use crate::prolog::rug::Integer;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::Read;
|
||||
use std::iter::Rev;
|
||||
use std::vec::IntoIter;
|
||||
|
||||
fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)> {
|
||||
if let &mut Term::Clause(_, ref name, ref mut subterms, _) = term {
|
||||
if name.as_str() == s && subterms.len() == 2 {
|
||||
let snd = *subterms.pop().unwrap();
|
||||
let fst = *subterms.pop().unwrap();
|
||||
|
||||
return Some((fst, snd));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn unfold_by_str(mut term: Term, s: &str) -> Vec<Term> {
|
||||
let mut terms = vec![];
|
||||
|
||||
while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) {
|
||||
terms.push(fst);
|
||||
term = snd;
|
||||
}
|
||||
|
||||
terms.push(term);
|
||||
terms
|
||||
}
|
||||
|
||||
pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
|
||||
where
|
||||
I: DoubleEndedIterator<Item = Term>,
|
||||
@@ -53,7 +27,11 @@ where
|
||||
term
|
||||
}
|
||||
|
||||
fn extract_from_list(head: Box<Term>, tail: Box<Term>) -> Result<Rev<IntoIter<Term>>, ParserError> {
|
||||
fn extract_from_list(
|
||||
head: Box<Term>,
|
||||
tail: Box<Term>,
|
||||
) -> Result<Rev<IntoIter<Term>>, ParserError>
|
||||
{
|
||||
let mut terms = vec![*head];
|
||||
let mut tail = *tail;
|
||||
|
||||
@@ -69,10 +47,10 @@ fn extract_from_list(head: Box<Term>, tail: Box<Term>) -> Result<Rev<IntoIter<Te
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TermStream<'a, R: Read> {
|
||||
pub struct TermStream<'a> {
|
||||
stack: Vec<Term>,
|
||||
pub(crate) wam: &'a mut Machine,
|
||||
parser: Parser<'a, R>,
|
||||
parser: Parser<'a, Stream>,
|
||||
pub(crate) flags: MachineFlags,
|
||||
term_expansion_lens: (usize, usize),
|
||||
goal_expansion_lens: (usize, usize),
|
||||
@@ -100,7 +78,7 @@ impl ExpansionAdditionResult {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Read> Drop for TermStream<'a, R> {
|
||||
impl<'a> Drop for TermStream<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.wam.indices.in_situ_code_dir.clear();
|
||||
self.wam.indices.in_situ_module_dir.clear();
|
||||
@@ -110,9 +88,9 @@ impl<'a, R: Read> Drop for TermStream<'a, R> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Read> TermStream<'a, R> {
|
||||
impl<'a> TermStream<'a> {
|
||||
pub fn new(
|
||||
src: &'a mut ParsingStream<R>,
|
||||
src: &'a mut ParsingStream<Stream>,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
flags: MachineFlags,
|
||||
wam: &'a mut Machine,
|
||||
@@ -326,7 +304,8 @@ impl<'a, R: Read> TermStream<'a, R> {
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(super) fn print_with_locs(&self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter {
|
||||
pub(super)
|
||||
fn print_with_locs(&self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter {
|
||||
let output = PrinterOutputter::new();
|
||||
let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
|
||||
let mut max_var_length = 0;
|
||||
@@ -337,12 +316,16 @@ impl MachineState {
|
||||
|
||||
printer.quoted = true;
|
||||
printer.numbervars = true;
|
||||
// the purpose of the offset is to avoid clashes with variable names that might
|
||||
// occur after the addresses in the expanded term are substituted with the variable
|
||||
// names in the pre-expansion term. This formula ensures that all generated "numbervars"-
|
||||
// style variable names will be longer than the keys of the var_dict, and therefore
|
||||
// not equal to any of them.
|
||||
|
||||
// the purpose of the offset is to avoid clashes with variable
|
||||
// names that might occur after the addresses in the expanded
|
||||
// term are substituted with the variable names in the
|
||||
// pre-expansion term. This formula ensures that all generated
|
||||
// "numbervars"- style variable names will be longer than the
|
||||
// keys of the var_dict, and therefore not equal to any of
|
||||
// them.
|
||||
printer.numbervars_offset = Integer::from(10).pow(max_var_length as u32) * 26;
|
||||
printer.print_strings_as_strs = true;
|
||||
printer.drop_toplevel_spec();
|
||||
|
||||
printer.see_all_locs();
|
||||
@@ -354,8 +337,8 @@ impl MachineState {
|
||||
}
|
||||
|
||||
// reset the machine, but keep the heap contents as they were.
|
||||
// this prevents clashes between underscored variable names
|
||||
// in the same query.
|
||||
// this prevents clashes between underscored variable names in the
|
||||
// same query.
|
||||
fn reset_with_heap_preservation(&mut self) {
|
||||
let heap = self.heap.take();
|
||||
self.reset();
|
||||
@@ -379,13 +362,16 @@ impl MachineState {
|
||||
wam.code_repo.cached_query = code;
|
||||
|
||||
self.cp = LocalCodePtr::TopLevel(0, 0);
|
||||
|
||||
self.at_end_of_expansion = false;
|
||||
self.flags.double_quotes = DoubleQuotes::Chars;
|
||||
|
||||
self.query_stepper(
|
||||
&mut wam.indices,
|
||||
&mut wam.policies,
|
||||
&mut wam.code_repo,
|
||||
&mut readline::input_stream(),
|
||||
&mut Stream::stdout(),
|
||||
);
|
||||
|
||||
if self.fail || self.at_end_of_expansion {
|
||||
@@ -398,6 +384,7 @@ impl MachineState {
|
||||
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
|
||||
|
||||
self.reset_with_heap_preservation();
|
||||
|
||||
Some(output.result())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use indexmap::{IndexMap, IndexSet};
|
||||
use std::borrow::BorrowMut;
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::Read;
|
||||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::ops::DerefMut;
|
||||
use std::rc::Rc;
|
||||
@@ -30,15 +30,15 @@ fn op_dir<'a, 'b: 'a>(from: &'b IndexSource<'a, IndexStore>) -> RefOrOwned<'a, O
|
||||
}
|
||||
}
|
||||
|
||||
struct CompositeIndices<'a, 'b, 'c, R: Read> {
|
||||
term_stream: &'b mut TermStream<'a, R>,
|
||||
struct CompositeIndices<'a, 'b, 'c> {
|
||||
term_stream: &'b mut TermStream<'a>,
|
||||
index_src: IndexSource<'c, IndexStore>,
|
||||
static_code_dir: Option<IndexSource<'c, CodeDir>>
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, R: Read> CompositeIndices<'a, 'b, 'c, R> {
|
||||
impl<'a, 'b, 'c> CompositeIndices<'a, 'b, 'c> {
|
||||
fn new(
|
||||
term_stream: &'b mut TermStream<'a, R>,
|
||||
term_stream: &'b mut TermStream<'a>,
|
||||
index_src: IndexSource<'c, IndexStore>,
|
||||
static_code_dir: Option<IndexSource<'c, CodeDir>>,
|
||||
) -> Self {
|
||||
@@ -212,8 +212,8 @@ fn setup_op_decl(
|
||||
};
|
||||
|
||||
let prec = match *terms.pop().unwrap() {
|
||||
Term::Constant(_, Constant::Integer(bi)) => match bi.to_usize() {
|
||||
Some(n) if n <= 1200 => n,
|
||||
Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
|
||||
Ok(n) if n <= 1200 => n,
|
||||
_ => return Err(ParserError::InconsistentEntry),
|
||||
},
|
||||
_ => return Err(ParserError::InconsistentEntry),
|
||||
@@ -225,16 +225,21 @@ fn setup_op_decl(
|
||||
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserError>
|
||||
{
|
||||
match term {
|
||||
Term::Clause(_, ref name, ref mut terms, Some(_))
|
||||
if name.as_str() == "/" && terms.len() == 2 =>
|
||||
Term::Clause(_, ref slash, ref mut terms, Some(_))
|
||||
if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 =>
|
||||
{
|
||||
let arity = *terms.pop().unwrap();
|
||||
let name = *terms.pop().unwrap();
|
||||
|
||||
let arity = arity
|
||||
.to_constant()
|
||||
.and_then(|c| c.to_integer())
|
||||
.and_then(|n| n.to_usize())
|
||||
.and_then(|c| {
|
||||
match c {
|
||||
Constant::Integer(n) => n.to_usize(),
|
||||
Constant::Fixnum(n) => usize::try_from(n).ok(),
|
||||
_ => None
|
||||
}
|
||||
})
|
||||
.ok_or(ParserError::InvalidModuleExport)?;
|
||||
|
||||
let name = name
|
||||
@@ -242,7 +247,11 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserErro
|
||||
.and_then(|c| c.to_atom())
|
||||
.ok_or(ParserError::InvalidModuleExport)?;
|
||||
|
||||
if slash.as_str() == "/" {
|
||||
Ok((name, arity))
|
||||
} else {
|
||||
Ok((name, arity + 2))
|
||||
}
|
||||
}
|
||||
_ => Err(ParserError::InvalidModuleExport),
|
||||
}
|
||||
@@ -339,6 +348,32 @@ fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, Pars
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, ParserError> {
|
||||
let dbl_quotes = *terms.pop().unwrap();
|
||||
|
||||
match terms[0].as_ref() {
|
||||
Term::Constant(_, Constant::Atom(ref name, _))
|
||||
if name.as_str() == "double_quotes" => {
|
||||
match dbl_quotes {
|
||||
Term::Constant(_, Constant::Atom(name, _)) => {
|
||||
match name.as_str() {
|
||||
"atom" => Ok(DoubleQuotes::Atom),
|
||||
"chars" => Ok(DoubleQuotes::Chars),
|
||||
"codes" => Ok(DoubleQuotes::Codes),
|
||||
_ => Err(ParserError::InvalidDoubleQuotesDecl),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
Err(ParserError::InvalidDoubleQuotesDecl)
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
Err(ParserError::InvalidDoubleQuotesDecl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type UseModuleExport = (ModuleSource, Vec<ModuleExport>);
|
||||
|
||||
fn setup_qualified_import(
|
||||
@@ -551,8 +586,8 @@ fn draw_from_term_dir_impl(
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_from_term_dir<R: Read>(
|
||||
indices: &CompositeIndices<R>,
|
||||
fn draw_from_term_dir(
|
||||
indices: &CompositeIndices,
|
||||
intra_module_term_dirs: &mut IndexMap<ClauseName, TermDirQuantum>,
|
||||
top_level_term_dirs: &mut TermDirQuantum,
|
||||
key: &PredicateKey,
|
||||
@@ -589,8 +624,8 @@ fn draw_from_term_dir<R: Read>(
|
||||
);
|
||||
}
|
||||
|
||||
fn setup_declaration<'a, 'b, 'c, R: Read>(
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
fn setup_declaration<'a, 'b, 'c>(
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
flags: MachineFlags,
|
||||
mut terms: Vec<Box<Term>>,
|
||||
line_num: usize,
|
||||
@@ -620,18 +655,23 @@ fn setup_declaration<'a, 'b, 'c, R: Read>(
|
||||
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
|
||||
Ok(Declaration::NonCountedBacktracking(name, arity))
|
||||
}
|
||||
("set_prolog_flag", 2) => {
|
||||
Ok(Declaration::SetPrologFlag(setup_double_quotes(terms)?))
|
||||
}
|
||||
("multifile", 1) => {
|
||||
let mut term = *terms.pop().unwrap();
|
||||
|
||||
match setup_predicate_indicator(&mut term) {
|
||||
Ok((name, arity)) =>
|
||||
Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity))),
|
||||
_ =>
|
||||
Ok((name, arity)) => {
|
||||
Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity)))
|
||||
}
|
||||
_ => {
|
||||
setup_scoped_predicate_indicator(&mut term)
|
||||
.map(|key| {
|
||||
Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
("use_module", 1) => {
|
||||
Ok(Declaration::UseModule(setup_use_module_decl(terms)?))
|
||||
@@ -644,7 +684,9 @@ fn setup_declaration<'a, 'b, 'c, R: Read>(
|
||||
Err(ParserError::InconsistentEntry)
|
||||
}
|
||||
},
|
||||
_ => Err(ParserError::InconsistentEntry),
|
||||
_ => {
|
||||
Err(ParserError::InconsistentEntry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,9 +809,9 @@ impl RelationWorker {
|
||||
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
|
||||
}
|
||||
|
||||
fn to_query_term<'a, 'b, 'c, R: Read>(
|
||||
fn to_query_term<'a, 'b, 'c>(
|
||||
&mut self,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
term: Term,
|
||||
) -> Result<QueryTerm, ParserError> {
|
||||
match term {
|
||||
@@ -843,9 +885,9 @@ impl RelationWorker {
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_query_term<'a, 'b, 'c, R: Read>(
|
||||
fn pre_query_term<'a, 'b, 'c>(
|
||||
&mut self,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
term: Term,
|
||||
) -> Result<QueryTerm, ParserError> {
|
||||
match term {
|
||||
@@ -864,9 +906,9 @@ impl RelationWorker {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_query<'a, 'b, 'c, R: Read>(
|
||||
fn setup_query<'a, 'b, 'c>(
|
||||
&mut self,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
terms: Vec<Box<Term>>,
|
||||
blocks_cuts: bool,
|
||||
) -> Result<Vec<QueryTerm>, ParserError> {
|
||||
@@ -917,10 +959,10 @@ impl RelationWorker {
|
||||
Ok(query_terms)
|
||||
}
|
||||
|
||||
fn setup_hook<'a, 'b, 'c, R: Read>(
|
||||
fn setup_hook<'a, 'b, 'c>(
|
||||
&mut self,
|
||||
hook: CompileTimeHook,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
term: Term,
|
||||
) -> Result<CompileTimeHookCompileInfo, ParserError> {
|
||||
match flatten_hook(term) {
|
||||
@@ -941,9 +983,9 @@ impl RelationWorker {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_rule<'a, 'b, 'c, R: Read>(
|
||||
fn setup_rule<'a, 'b, 'c>(
|
||||
&mut self,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
mut terms: Vec<Box<Term>>,
|
||||
blocks_cuts: bool,
|
||||
assume_dyn: bool,
|
||||
@@ -974,9 +1016,9 @@ impl RelationWorker {
|
||||
}
|
||||
}
|
||||
|
||||
fn try_term_to_query<'a, 'b, 'c, R: Read>(
|
||||
fn try_term_to_query<'a, 'b, 'c>(
|
||||
&mut self,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
terms: Vec<Box<Term>>,
|
||||
blocks_cuts: bool,
|
||||
) -> Result<TopLevel, ParserError> {
|
||||
@@ -987,10 +1029,10 @@ impl RelationWorker {
|
||||
)?))
|
||||
}
|
||||
|
||||
fn compact_module_scoped_head<'a, 'b, 'c, R: Read>(
|
||||
fn compact_module_scoped_head<'a, 'b, 'c>(
|
||||
&self,
|
||||
term: &mut Term,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
) {
|
||||
let inner_term = match term {
|
||||
Term::Clause(_, ref name, ref mut inner_terms, _)
|
||||
@@ -1015,9 +1057,9 @@ impl RelationWorker {
|
||||
*term = inner_term;
|
||||
}
|
||||
|
||||
fn try_term_to_tl<'a, 'b, 'c, R: Read>(
|
||||
fn try_term_to_tl<'a, 'b, 'c>(
|
||||
&mut self,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
term: Term,
|
||||
blocks_cuts: bool,
|
||||
) -> Result<TopLevel, ParserError> {
|
||||
@@ -1051,19 +1093,20 @@ impl RelationWorker {
|
||||
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
|
||||
}
|
||||
}
|
||||
term =>
|
||||
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)),
|
||||
term => {
|
||||
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_terms_to_tls<'a, 'b, 'c, I, R>(
|
||||
fn try_terms_to_tls<'a, 'b, 'c, I>(
|
||||
&mut self,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
terms: I,
|
||||
blocks_cuts: bool,
|
||||
) -> Result<VecDeque<TopLevel>, ParserError>
|
||||
where
|
||||
I: IntoIterator<Item = Term>, R: Read
|
||||
I: IntoIterator<Item = Term>
|
||||
{
|
||||
let mut results = VecDeque::new();
|
||||
|
||||
@@ -1074,9 +1117,9 @@ impl RelationWorker {
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
fn parse_queue<'a, 'b, 'c, R: Read>(
|
||||
fn parse_queue<'a, 'b, 'c>(
|
||||
&mut self,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||
) -> Result<VecDeque<TopLevel>, ParserError> {
|
||||
let mut queue = VecDeque::new();
|
||||
|
||||
@@ -1090,8 +1133,7 @@ impl RelationWorker {
|
||||
|
||||
fn absorb(&mut self, other: RelationWorker) {
|
||||
self.queue.extend(other.queue.into_iter());
|
||||
self.dynamic_clauses
|
||||
.extend(other.dynamic_clauses.into_iter());
|
||||
self.dynamic_clauses.extend(other.dynamic_clauses.into_iter());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1099,8 +1141,8 @@ pub type DynamicClause = Vec<(Term, Term)>;
|
||||
|
||||
pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>;
|
||||
|
||||
pub struct TopLevelBatchWorker<'a, R: Read> {
|
||||
pub(crate) term_stream: TermStream<'a, R>,
|
||||
pub struct TopLevelBatchWorker<'a> {
|
||||
pub(crate) term_stream: TermStream<'a>,
|
||||
rel_worker: RelationWorker,
|
||||
pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>,
|
||||
pub(crate) dynamic_clause_map: DynamicClauseMap,
|
||||
@@ -1110,14 +1152,14 @@ pub struct TopLevelBatchWorker<'a, R: Read> {
|
||||
pub(crate) non_counted_bt_preds: IndexSet<PredicateKey>,
|
||||
}
|
||||
|
||||
impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
||||
impl<'a> TopLevelBatchWorker<'a> {
|
||||
pub fn new(
|
||||
inner: &'a mut ParsingStream<R>,
|
||||
stream: &'a mut ParsingStream<Stream>,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
flags: MachineFlags,
|
||||
wam: &'a mut Machine,
|
||||
) -> Self {
|
||||
let term_stream = TermStream::new(inner, atom_tbl, flags, wam);
|
||||
let term_stream = TermStream::new(stream, atom_tbl, flags, wam);
|
||||
|
||||
let line_num = term_stream.line_num();
|
||||
let col_num = term_stream.col_num();
|
||||
@@ -1248,7 +1290,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
||||
TopLevel::Declaration(decl) =>
|
||||
return Ok(Some(decl)),
|
||||
TopLevel::Query(_) =>
|
||||
return Err(SessionError::NamelessEntry),
|
||||
return Err(SessionError::QueryCannotBeDefinedAsFact),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,52 +4,183 @@ macro_rules! interm {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! heap_str {
|
||||
($s:expr) => {
|
||||
HeapCellValue::Addr(Addr::Str($s))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! heap_integer {
|
||||
($i:expr) => {
|
||||
HeapCellValue::Addr(Addr::Con(Constant::Integer($i)))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! heap_cell {
|
||||
($i:expr) => {
|
||||
HeapCellValue::Addr(Addr::HeapCell($i))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! heap_con {
|
||||
($i:expr) => {
|
||||
HeapCellValue::Addr(Addr::Con($i))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! heap_atom {
|
||||
($name:expr) => {
|
||||
HeapCellValue::Addr(Addr::Con(atom!($name)))
|
||||
};
|
||||
($name:expr, $tbl:expr) => {
|
||||
HeapCellValue::Addr(Addr::Con(atom!($name, $tbl)))
|
||||
};
|
||||
/* A simple macro to count the arguments in a variadic list
|
||||
* of token trees.
|
||||
*/
|
||||
macro_rules! count_tt {
|
||||
() => { 0 };
|
||||
($odd:tt $($a:tt $b:tt)*) => { (count_tt!($($a)*) << 1) | 1 };
|
||||
($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 };
|
||||
}
|
||||
|
||||
macro_rules! functor {
|
||||
($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
|
||||
{
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut addendum = Heap::new();
|
||||
let arity = count_tt!($($dt) +);
|
||||
let aux_lens = [$($aux.len()),*];
|
||||
|
||||
let mut result =
|
||||
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
|
||||
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
|
||||
|
||||
$(
|
||||
result.extend($aux.into_iter());
|
||||
)*
|
||||
|
||||
result.extend(addendum.into_iter());
|
||||
result
|
||||
}
|
||||
});
|
||||
($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+]) => ({
|
||||
{
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut addendum = Heap::new();
|
||||
let arity = count_tt!($($dt) +);
|
||||
|
||||
let mut result =
|
||||
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
|
||||
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
|
||||
|
||||
result.extend(addendum.into_iter());
|
||||
result
|
||||
}
|
||||
});
|
||||
($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
|
||||
{
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut addendum = Heap::new();
|
||||
let arity = count_tt!($($dt) +);
|
||||
let aux_lens = [$($aux.len()),*];
|
||||
|
||||
let mut result =
|
||||
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
|
||||
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
|
||||
|
||||
$(
|
||||
result.extend($aux.into_iter());
|
||||
)*
|
||||
|
||||
result.extend(addendum.into_iter());
|
||||
result
|
||||
}
|
||||
});
|
||||
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
|
||||
{
|
||||
let arity = count_tt!($($dt) +);
|
||||
|
||||
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
|
||||
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]
|
||||
}
|
||||
});
|
||||
($name:expr, $fixity:expr) => (
|
||||
vec![ HeapCellValue::Atom(clause_name!($name), Some($fixity)) ]
|
||||
);
|
||||
(clause_name($name:expr)) => (
|
||||
vec![ HeapCellValue::Atom($name, None) ]
|
||||
);
|
||||
($name:expr) => (
|
||||
vec![ heap_atom!($name) ]
|
||||
vec![ HeapCellValue::Atom(clause_name!($name), None) ]
|
||||
);
|
||||
($name:expr, $len:expr) => (
|
||||
vec![ HeapCellValue::NamedStr($len, clause_name!($name), None) ]
|
||||
}
|
||||
|
||||
macro_rules! functor_term {
|
||||
(aux(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
HeapCellValue::Addr(Addr::HeapCell($arity + 1))
|
||||
});
|
||||
(aux($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
let len: usize = $aux_lens[0 .. $e].iter().sum();
|
||||
HeapCellValue::Addr(Addr::HeapCell($arity + 1 + len))
|
||||
});
|
||||
(aux($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1))
|
||||
});
|
||||
(aux($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
let len: usize = $aux_lens[0 .. $e].iter().sum();
|
||||
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1 + len))
|
||||
});
|
||||
(addr($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
HeapCellValue::Addr($e)
|
||||
);
|
||||
($name:expr, $len:expr, [$($args:expr),*]) => (
|
||||
vec![ HeapCellValue::NamedStr($len, clause_name!($name), None), $($args),* ]
|
||||
(constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
from_constant!($e, $h, $arity, $aux_lens, $addendum)
|
||||
);
|
||||
($name:expr, $len:expr, [$($args:expr),*], $fix: expr) => (
|
||||
vec![ HeapCellValue::NamedStr($len, clause_name!($name), Some($fix)), $($args),* ]
|
||||
(constant($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
from_constant!($e, 0, $arity, $aux_lens, $addendum)
|
||||
);
|
||||
(number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
$e.into()
|
||||
);
|
||||
(integer($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
|
||||
HeapCellValue::Integer(Rc::new(Integer::from($e)))
|
||||
);
|
||||
(clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
|
||||
HeapCellValue::Atom($e, None)
|
||||
);
|
||||
(atom($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
|
||||
HeapCellValue::Atom(clause_name!($e), None)
|
||||
);
|
||||
(string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
|
||||
let len: usize = $aux_lens.iter().sum();
|
||||
let h = len + $arity + 1 + $addendum.h() + $h;
|
||||
|
||||
$addendum.put_complete_string(&$e);
|
||||
|
||||
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
|
||||
});
|
||||
(boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
|
||||
if $e {
|
||||
functor_term!(atom("true"), $arity, $aux_lens, $addendum)
|
||||
} else {
|
||||
functor_term!(atom("false"), $arity, $aux_lens, $addendum)
|
||||
}
|
||||
});
|
||||
($e:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
$e
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! from_constant {
|
||||
($e:expr, $over_h:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
match $e {
|
||||
&Constant::Atom(ref name, ref op) => {
|
||||
HeapCellValue::Atom(name.clone(), op.clone())
|
||||
}
|
||||
&Constant::Char(c) => {
|
||||
HeapCellValue::Addr(Addr::Char(c))
|
||||
}
|
||||
&Constant::CharCode(c) => {
|
||||
HeapCellValue::Addr(Addr::CharCode(c))
|
||||
}
|
||||
&Constant::Fixnum(n) => {
|
||||
HeapCellValue::Addr(Addr::Fixnum(n))
|
||||
}
|
||||
&Constant::Integer(ref n) => {
|
||||
HeapCellValue::Integer(n.clone())
|
||||
}
|
||||
&Constant::Rational(ref r) => {
|
||||
HeapCellValue::Rational(r.clone())
|
||||
}
|
||||
&Constant::Float(f) => {
|
||||
HeapCellValue::Addr(Addr::Float(f))
|
||||
}
|
||||
&Constant::String(ref s) => {
|
||||
let len: usize = $aux_lens.iter().sum();
|
||||
let h = len + $arity + 1 + $addendum.h() + $over_h;
|
||||
|
||||
$addendum.put_complete_string(&s);
|
||||
|
||||
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
|
||||
}
|
||||
&Constant::Usize(u) => {
|
||||
HeapCellValue::Addr(Addr::Usize(u))
|
||||
}
|
||||
&Constant::EmptyList => {
|
||||
HeapCellValue::Addr(Addr::EmptyList)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! is_atom {
|
||||
@@ -94,12 +225,6 @@ macro_rules! is_nonvar {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_string {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsString($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_var {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsVar($r)), 1, 0)
|
||||
@@ -211,12 +336,6 @@ macro_rules! dir_entry {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! in_situ_dir_entry {
|
||||
($idx:expr) => {
|
||||
CodePtr::Local(LocalCodePtr::InSituDirEntry($idx))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! set_code_index {
|
||||
($idx:expr, $ip:expr, $mod_name:expr) => {{
|
||||
let mut idx = $idx.0.borrow_mut();
|
||||
@@ -238,6 +357,7 @@ macro_rules! index_store {
|
||||
in_situ_module_dir: ModuleStubDir::new(),
|
||||
op_dir: $op_dir,
|
||||
modules: $modules,
|
||||
stream_aliases: StreamAliasDir::new(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,27 +6,16 @@ use crate::prolog::forms::*;
|
||||
use crate::prolog::iterators::*;
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
use crate::prolog::machine::machine_state::MachineState;
|
||||
use crate::prolog::machine::streams::Stream;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::io::Read;
|
||||
|
||||
type SubtermDeque = VecDeque<(usize, usize)>;
|
||||
|
||||
impl<'a> TermRef<'a> {
|
||||
fn as_addr(&self, h: usize) -> Addr {
|
||||
match self {
|
||||
&TermRef::AnonVar(_) | &TermRef::Var(..) => Addr::HeapCell(h),
|
||||
&TermRef::Cons(..) => Addr::HeapCell(h),
|
||||
&TermRef::Constant(_, _, c) => Addr::Con(c.clone()),
|
||||
&TermRef::Clause(..) => Addr::Str(h),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type PrologStream = ParsingStream<Box<dyn Read>>;
|
||||
pub type PrologStream = ParsingStream<Stream>;
|
||||
|
||||
pub mod readline {
|
||||
use prolog_parser::ast::*;
|
||||
use crate::prolog::machine::streams::Stream;
|
||||
use crate::prolog::rustyline::error::ReadlineError;
|
||||
use crate::prolog::rustyline::{Cmd, Editor, KeyPress};
|
||||
use std::io::{Cursor, Read};
|
||||
@@ -52,10 +41,10 @@ pub mod readline {
|
||||
}
|
||||
|
||||
impl ReadlineStream {
|
||||
fn input_stream(pending_input: String) -> Self {
|
||||
pub fn input_stream(pending_input: String) -> Stream {
|
||||
let mut rl = Editor::<()>::new();
|
||||
rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string()));
|
||||
ReadlineStream { rl, pending_input: Cursor::new(pending_input) }
|
||||
Stream::from(ReadlineStream { rl, pending_input: Cursor::new(pending_input) })
|
||||
}
|
||||
|
||||
fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
@@ -93,15 +82,14 @@ pub mod readline {
|
||||
result => {
|
||||
result
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn input_stream() -> crate::PrologStream {
|
||||
let reader: Box<dyn Read> = Box::new(ReadlineStream::input_stream(String::from("")));
|
||||
parsing_stream(reader)
|
||||
pub fn input_stream() -> Stream {
|
||||
let input_stream = ReadlineStream::input_stream(String::from(""));
|
||||
Stream::from(input_stream)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,24 +107,17 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
|
||||
fn push_stub_addr(machine_st: &mut MachineState) {
|
||||
let h = machine_st.heap.h();
|
||||
machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
|
||||
let term_writer = TermWriter::new(machine_st);
|
||||
term_writer.write_term_to_heap(term)
|
||||
}
|
||||
|
||||
fn modify_head_of_queue(
|
||||
machine_st: &mut MachineState,
|
||||
queue: &mut SubtermDeque,
|
||||
term: TermRef,
|
||||
h: usize,
|
||||
) {
|
||||
if let Some((arity, site_h)) = queue.pop_front() {
|
||||
machine_st.heap[site_h] = HeapCellValue::Addr(term.as_addr(h));
|
||||
|
||||
if arity > 1 {
|
||||
queue.push_front((arity - 1, site_h + 1));
|
||||
}
|
||||
}
|
||||
struct TermWriter<'a> {
|
||||
machine_st: &'a mut MachineState,
|
||||
queue: SubtermDeque,
|
||||
var_dict: HeapVarDict,
|
||||
}
|
||||
|
||||
pub struct TermWriteResult {
|
||||
@@ -144,76 +125,135 @@ pub struct TermWriteResult {
|
||||
pub(crate) var_dict: HeapVarDict,
|
||||
}
|
||||
|
||||
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
|
||||
let heap_loc = machine_st.heap.h();
|
||||
impl<'a> TermWriter<'a> {
|
||||
#[inline]
|
||||
fn new(machine_st: &'a mut MachineState) -> Self {
|
||||
TermWriter {
|
||||
machine_st,
|
||||
queue: SubtermDeque::new(),
|
||||
var_dict: HeapVarDict::new(),
|
||||
}
|
||||
}
|
||||
|
||||
let mut queue = SubtermDeque::new();
|
||||
let mut var_dict = HeapVarDict::new();
|
||||
#[inline]
|
||||
fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) {
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
self.machine_st.heap[site_h] =
|
||||
HeapCellValue::Addr(self.term_as_addr(term, h));
|
||||
|
||||
if arity > 1 {
|
||||
self.queue.push_front((arity - 1, site_h + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn push_stub_addr(&mut self) {
|
||||
let h = self.machine_st.heap.h();
|
||||
self.machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
|
||||
}
|
||||
|
||||
fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> Addr {
|
||||
match term {
|
||||
&TermRef::AnonVar(_) | &TermRef::Var(..) => {
|
||||
Addr::HeapCell(h)
|
||||
}
|
||||
&TermRef::Cons(..) => {
|
||||
Addr::HeapCell(h)
|
||||
}
|
||||
&TermRef::Constant(_, _, c) => {
|
||||
self.machine_st.heap.put_constant(c.clone())
|
||||
}
|
||||
&TermRef::Clause(..) => {
|
||||
Addr::Str(h)
|
||||
}
|
||||
&TermRef::PartialString(..) => {
|
||||
Addr::PStrLocation(h, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult {
|
||||
let heap_loc = self.machine_st.heap.h();
|
||||
|
||||
for term in breadth_first_iter(term, true) {
|
||||
let h = machine_st.heap.h();
|
||||
let h = self.machine_st.heap.h();
|
||||
|
||||
match &term {
|
||||
&TermRef::Cons(lvl, ..) => {
|
||||
queue.push_back((2, h + 1));
|
||||
machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||
self.queue.push_back((2, h + 1));
|
||||
self.machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||
|
||||
push_stub_addr(machine_st);
|
||||
push_stub_addr(machine_st);
|
||||
self.push_stub_addr();
|
||||
self.push_stub_addr();
|
||||
|
||||
if let Level::Root = lvl {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
&TermRef::Clause(lvl, _, ref ct, subterms) => {
|
||||
queue.push_back((subterms.len(), h + 1));
|
||||
self.queue.push_back((subterms.len(), h + 1));
|
||||
let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec());
|
||||
|
||||
machine_st.heap.push(named);
|
||||
self.machine_st.heap.push(named);
|
||||
|
||||
for _ in 0..subterms.len() {
|
||||
push_stub_addr(machine_st);
|
||||
self.push_stub_addr();
|
||||
}
|
||||
|
||||
if let Level::Root = lvl {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
&TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => {
|
||||
machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h)))
|
||||
}
|
||||
&TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) |
|
||||
&TermRef::Var(Level::Root, ..) => {
|
||||
machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h)))
|
||||
let addr = self.term_as_addr(&term, h);
|
||||
self.machine_st.heap.push(HeapCellValue::Addr(addr));
|
||||
}
|
||||
&TermRef::AnonVar(_) => {
|
||||
if let Some((arity, site_h)) = queue.pop_front() {
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
if arity > 1 {
|
||||
queue.push_front((arity - 1, site_h + 1));
|
||||
self.queue.push_front((arity - 1, site_h + 1));
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
&TermRef::PartialString(lvl, _, ref pstr, tail) => {
|
||||
if tail.is_some() {
|
||||
self.machine_st.heap.allocate_pstr(&pstr);
|
||||
} else {
|
||||
self.machine_st.heap.put_complete_string(&pstr);
|
||||
}
|
||||
|
||||
if let Level::Root = lvl {
|
||||
} else if tail.is_some() {
|
||||
let h = self.machine_st.heap.h();
|
||||
self.queue.push_back((1, h - 1));
|
||||
}
|
||||
}
|
||||
&TermRef::Var(_, _, ref var) => {
|
||||
if let Some((arity, site_h)) = queue.pop_front() {
|
||||
if let Some(addr) = var_dict.get(var).cloned() {
|
||||
machine_st.heap[site_h] = HeapCellValue::Addr(addr);
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
if let Some(addr) = self.var_dict.get(var).cloned() {
|
||||
self.machine_st.heap[site_h] = HeapCellValue::Addr(addr);
|
||||
} else {
|
||||
var_dict.insert(var.clone(), Addr::HeapCell(site_h));
|
||||
self.var_dict.insert(var.clone(), Addr::HeapCell(site_h));
|
||||
}
|
||||
|
||||
if arity > 1 {
|
||||
queue.push_front((arity - 1, site_h + 1));
|
||||
self.queue.push_front((arity - 1, site_h + 1));
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
_ => {}
|
||||
_ => {
|
||||
}
|
||||
};
|
||||
|
||||
modify_head_of_queue(machine_st, &mut queue, term, h);
|
||||
self.modify_head_of_queue(&term, h);
|
||||
}
|
||||
|
||||
TermWriteResult { heap_loc, var_dict }
|
||||
TermWriteResult { heap_loc, var_dict: self.var_dict }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ pub trait CompilationTarget<'a> {
|
||||
fn to_void(_: usize) -> Self;
|
||||
fn is_void_instr(&self) -> bool;
|
||||
|
||||
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self;
|
||||
|
||||
fn incr_void_instr(&mut self);
|
||||
|
||||
fn constant_subterm(_: Constant) -> Self;
|
||||
@@ -62,6 +64,10 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self {
|
||||
FactInstruction::GetPartialString(lvl, string, r, has_tail)
|
||||
}
|
||||
|
||||
fn incr_void_instr(&mut self) {
|
||||
match self {
|
||||
&mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1,
|
||||
@@ -117,6 +123,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
|
||||
QueryInstruction::PutList(lvl, reg)
|
||||
}
|
||||
|
||||
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self {
|
||||
QueryInstruction::PutPartialString(lvl, string, r, has_tail)
|
||||
}
|
||||
|
||||
fn to_void(subterms: usize) -> Self {
|
||||
QueryInstruction::SetVoid(subterms)
|
||||
}
|
||||
|
||||
@@ -24,26 +24,30 @@
|
||||
% make '$compile_batch', a system routine, callable.
|
||||
'$$compile_batch' :- '$compile_batch'.
|
||||
|
||||
'$instruction_match'([Item], []) :-
|
||||
( atom(Item) -> !,
|
||||
'$instruction_match'(Term, VarList) :-
|
||||
( var(Term) ->
|
||||
throw(error(instantiation_error, repl/0))
|
||||
;
|
||||
Term = [Item] -> !,
|
||||
( atom(Item) ->
|
||||
( Item == user ->
|
||||
catch('$$compile_batch', E, '$print_exception_with_check'(E))
|
||||
; consult(Item)
|
||||
)
|
||||
; !,
|
||||
;
|
||||
catch(throw(error(type_error(atom, Item), repl/0)),
|
||||
E,
|
||||
'$print_exception_with_check'(E))
|
||||
)
|
||||
;
|
||||
'$submit_query_and_print_results'(Term, VarList)
|
||||
).
|
||||
'$instruction_match'(Term, VarList) :-
|
||||
'$submit_query_and_print_results'(Term, VarList),
|
||||
!.
|
||||
|
||||
'$submit_query_and_print_results'(Term0, VarList) :-
|
||||
( expand_goals(Term0, Term) -> true
|
||||
; Term0 = Term
|
||||
),
|
||||
( '$get_b_value'(B), call(Term), '$write_eqs_and_read_input'(B, VarList),
|
||||
( '$get_b_value'(B), write(' '), call(Term), '$write_eqs_and_read_input'(B, VarList),
|
||||
!
|
||||
% clear attribute goal lists, which may be populated by
|
||||
% copy_term/3 prior to failure.
|
||||
@@ -57,34 +61,78 @@
|
||||
_,
|
||||
false),
|
||||
( EqPrec < FPrec -> true
|
||||
; '$quoted_token'(F) -> true
|
||||
; EqPrec == FPrec,
|
||||
memberchk(EqSpec, [fx,xfx,yfx])
|
||||
).
|
||||
|
||||
'$write_goal'(G, VarList) :-
|
||||
'$fabricate_var_name'(VarName, N) :-
|
||||
char_code('A', AC),
|
||||
LN is N mod 26 + AC,
|
||||
char_code(LC, LN),
|
||||
NN is N // 26,
|
||||
( NN =:= 0 ->
|
||||
atom_chars(VarName, ['_', LC])
|
||||
; number_chars(NN, NNChars),
|
||||
atom_chars(VarName, ['_', LC | NNChars])
|
||||
).
|
||||
|
||||
'$var_list_contains_name'([VarName = _ | VarList], VarName0) :-
|
||||
( VarName == VarName0 -> true
|
||||
; '$var_list_contains_name'(VarList, VarName0)
|
||||
).
|
||||
|
||||
'$var_list_contains_variable'([_ = Var | VarList], Var0) :-
|
||||
( Var == Var0 -> true
|
||||
; '$var_list_contains_variable'(VarList, Var0)
|
||||
).
|
||||
|
||||
'$make_new_var_name'(V, VarName, N, N1, VarList) :-
|
||||
'$fabricate_var_name'(VarName0, N),
|
||||
( '$var_list_contains_name'(VarList, VarName0) ->
|
||||
N0 is N + 1,
|
||||
'$make_new_var_name'(V, VarName, N0, N1, VarList)
|
||||
; VarName = VarName0,
|
||||
N1 is N + 1
|
||||
).
|
||||
|
||||
'$extend_var_list'(Value, VarList, NewVarList) :-
|
||||
term_variables(Value, Vars),
|
||||
'$extend_var_list_'(Vars, 0, VarList, NewVarList).
|
||||
|
||||
'$extend_var_list_'([], N, VarList, VarList).
|
||||
'$extend_var_list_'([V|Vs], N, VarList, NewVarList) :-
|
||||
( '$var_list_contains_variable'(VarList, V) ->
|
||||
'$extend_var_list_'(Vs, N, VarList, NewVarList)
|
||||
; '$make_new_var_name'(V, VarName, N, N1, VarList),
|
||||
NewVarList = [VarName = V | NewVarList0],
|
||||
'$extend_var_list_'(Vs, N1, VarList, NewVarList0)
|
||||
).
|
||||
|
||||
'$write_goal'(G, VarList, MaxDepth) :-
|
||||
( G = (Var = Value) ->
|
||||
write(Var),
|
||||
write(' = '),
|
||||
( '$needs_bracketing'(Value, (=)) ->
|
||||
write('('),
|
||||
write_term(Value, [quoted(true), variable_names(VarList)]),
|
||||
write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)]),
|
||||
write(')')
|
||||
; write_term(Value, [quoted(true), variable_names(VarList)])
|
||||
; write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)])
|
||||
)
|
||||
; G == [] ->
|
||||
write('true')
|
||||
; write_term(G, [quoted(true), variable_names(VarList)])
|
||||
; write_term(G, [quoted(true), variable_names(VarList), max_depth(MaxDepth)])
|
||||
).
|
||||
|
||||
'$write_last_goal'(G, VarList) :-
|
||||
'$write_last_goal'(G, VarList, MaxDepth) :-
|
||||
( G = (Var = Value) ->
|
||||
write(Var),
|
||||
write(' = '),
|
||||
( '$needs_bracketing'(Value, (=)) ->
|
||||
write('('),
|
||||
write_term(Value, [quoted(true), variable_names(VarList)]),
|
||||
write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)]),
|
||||
write(')')
|
||||
; write_term(Value, [quoted(true), variable_names(VarList)]),
|
||||
; write_term(Value, [quoted(true), variable_names(VarList), max_depth(MaxDepth)]),
|
||||
( '$trailing_period_is_ambiguous'(Value) ->
|
||||
write(' ')
|
||||
; true
|
||||
@@ -92,16 +140,16 @@
|
||||
)
|
||||
; G == [] ->
|
||||
write('true')
|
||||
; write_term(G, [quoted(true), variable_names(VarList)])
|
||||
; write_term(G, [quoted(true), variable_names(VarList), max_depth(MaxDepth)])
|
||||
).
|
||||
|
||||
'$write_eq'((G1, G2), VarList) :-
|
||||
'$write_eq'((G1, G2), VarList, MaxDepth) :-
|
||||
!,
|
||||
'$write_goal'(G1, VarList),
|
||||
'$write_goal'(G1, VarList, MaxDepth),
|
||||
write(', '),
|
||||
'$write_eq'(G2, VarList).
|
||||
'$write_eq'(G, VarList) :-
|
||||
'$write_last_goal'(G, VarList).
|
||||
'$write_eq'(G2, VarList, MaxDepth).
|
||||
'$write_eq'(G, VarList, MaxDepth) :-
|
||||
'$write_last_goal'(G, VarList, MaxDepth).
|
||||
|
||||
'$graphic_token_char'(C) :-
|
||||
memberchk(C, ['#', '$', '&', '*', '+', '-', '.', ('/'), ':',
|
||||
@@ -118,27 +166,52 @@
|
||||
'$graphic_token_char'(Char).
|
||||
|
||||
'$write_eqs_and_read_input'(B, VarList) :-
|
||||
sort(VarList, SortedVarList),
|
||||
'$extend_var_list'(VarList, VarList, NewVarList),
|
||||
sort(NewVarList, SortedVarList),
|
||||
'$get_b_value'(B0),
|
||||
'$gather_goals'(SortedVarList, VarList, Goals),
|
||||
'$gather_goals'(SortedVarList, SortedVarList, Goals),
|
||||
( B0 == B ->
|
||||
( Goals == [] ->
|
||||
write('true.'), nl
|
||||
; thread_goals(Goals, ThreadedGoals, (',')),
|
||||
'$write_eq'(ThreadedGoals, VarList),
|
||||
'$write_eq'(ThreadedGoals, NewVarList, 20),
|
||||
write('.'),
|
||||
nl
|
||||
)
|
||||
; thread_goals(Goals, ThreadedGoals, (',')),
|
||||
'$write_eq'(ThreadedGoals, VarList),
|
||||
'$raw_input_read_char'(C),
|
||||
( C == (';'), !,
|
||||
write(' ;'), nl, false
|
||||
; C == ('.'), !,
|
||||
write(' ...'), nl
|
||||
)
|
||||
'$write_eq'(ThreadedGoals, NewVarList, 20),
|
||||
'$read_input'(ThreadedGoals, NewVarList)
|
||||
).
|
||||
|
||||
'$read_input'(ThreadedGoals, NewVarList) :-
|
||||
'$raw_input_read_char'(C),
|
||||
( C == w ->
|
||||
nl,
|
||||
write(' '),
|
||||
'$write_eq'(ThreadedGoals, NewVarList, 0),
|
||||
'$read_input'(ThreadedGoals, NewVarList)
|
||||
; C == p ->
|
||||
nl,
|
||||
write(' '),
|
||||
'$write_eq'(ThreadedGoals, NewVarList, 20),
|
||||
'$read_input'(ThreadedGoals, NewVarList)
|
||||
; C == (';') ->
|
||||
nl, write('; '), false
|
||||
; C == h ->
|
||||
'$help_message',
|
||||
'$read_input'(ThreadedGoals, NewVarList)
|
||||
; C == '.',
|
||||
nl, write('; ...'), nl
|
||||
).
|
||||
|
||||
'$help_message' :-
|
||||
nl, nl,
|
||||
write('SPACE, "n" or ";": next solution, if any\n'),
|
||||
write('".": stop enumeration\n'),
|
||||
write('"h": display this help message\n'),
|
||||
write('"w": write terms without depth limit\n'),
|
||||
write('"p": print terms with depth limit\n\n').
|
||||
|
||||
'$gather_query_vars'([_ = Var | Vars], QueryVars) :-
|
||||
( var(Var) ->
|
||||
QueryVars = [Var | QueryVars1],
|
||||
@@ -153,10 +226,8 @@
|
||||
).
|
||||
|
||||
'$gather_goals'([], VarList, Goals) :-
|
||||
'$get_attr_var_queue_beyond'(0, AttrVars),
|
||||
'$gather_query_vars'(VarList, QueryVars),
|
||||
'$call_attribute_goals'(QueryVars, AttrVars),
|
||||
'$fetch_attribute_goals'(Goals).
|
||||
copy_term(QueryVars, QueryVars, Goals).
|
||||
'$gather_goals'([Var = Value | Pairs], VarList, Goals) :-
|
||||
( ( nonvar(Value)
|
||||
; '$is_a_different_variable'(Pairs, Value)
|
||||
@@ -167,7 +238,7 @@
|
||||
).
|
||||
|
||||
'$print_exception'(E) :-
|
||||
write_term('caught: ', [quoted(false)]),
|
||||
write_term('caught: ', [quoted(false), max_depth(20)]),
|
||||
writeq(E),
|
||||
nl.
|
||||
|
||||
|
||||
@@ -58,7 +58,13 @@ impl fmt::Display for FactInstruction {
|
||||
&FactInstruction::GetConstant(lvl, ref constant, ref r) => {
|
||||
write!(f, "get_constant {}, {}{}", constant, lvl, r.reg_num())
|
||||
}
|
||||
&FactInstruction::GetList(lvl, ref r) => write!(f, "get_list {}{}", lvl, r.reg_num()),
|
||||
&FactInstruction::GetList(lvl, ref r) => {
|
||||
write!(f, "get_list {}{}", lvl, r.reg_num())
|
||||
}
|
||||
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
|
||||
write!(f, "get_partial_string({}, {}, {}, {})",
|
||||
lvl, s, r, has_tail)
|
||||
}
|
||||
&FactInstruction::GetStructure(ref ct, ref arity, ref r) => {
|
||||
write!(f, "get_structure {}/{}, {}", ct.name(), arity, r)
|
||||
}
|
||||
@@ -86,7 +92,13 @@ impl fmt::Display for QueryInstruction {
|
||||
&QueryInstruction::PutConstant(lvl, ref constant, ref r) => {
|
||||
write!(f, "put_constant {}, {}{}", constant, lvl, r.reg_num())
|
||||
}
|
||||
&QueryInstruction::PutList(lvl, ref r) => write!(f, "put_list {}{}", lvl, r.reg_num()),
|
||||
&QueryInstruction::PutList(lvl, ref r) => {
|
||||
write!(f, "put_list {}{}", lvl, r.reg_num())
|
||||
}
|
||||
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
|
||||
write!(f, "put_partial_string({}, {}, {}, {})",
|
||||
lvl, s, r, has_tail)
|
||||
}
|
||||
&QueryInstruction::PutStructure(ref ct, ref arity, ref r) => {
|
||||
write!(f, "put_structure {}/{}, {}", ct.name(), arity, r)
|
||||
}
|
||||
@@ -143,6 +155,10 @@ impl fmt::Display for HeapCellValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&HeapCellValue::Addr(ref addr) => write!(f, "{}", addr),
|
||||
&HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()),
|
||||
&HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref),
|
||||
&HeapCellValue::Integer(ref n) => write!(f, "{}", n),
|
||||
&HeapCellValue::Rational(ref n) => write!(f, "{}", n),
|
||||
&HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!(
|
||||
f,
|
||||
"{}/{} (op, priority: {}, spec: {})",
|
||||
@@ -154,8 +170,16 @@ impl fmt::Display for HeapCellValue {
|
||||
&HeapCellValue::NamedStr(arity, ref name, None) => {
|
||||
write!(f, "{}/{}", name.as_str(), arity)
|
||||
}
|
||||
&HeapCellValue::PartialString(ref pstr) => {
|
||||
write!(f, "pstr ( buf: {}, tail: {} )", pstr.block_as_str(), pstr.tail_addr())
|
||||
&HeapCellValue::PartialString(ref pstr, has_tail) => {
|
||||
write!(
|
||||
f,
|
||||
"pstr ( buf: \"{}\", has_tail({}) )",
|
||||
pstr.as_str_from(0),
|
||||
has_tail,
|
||||
)
|
||||
}
|
||||
&HeapCellValue::Stream(ref stream) => {
|
||||
write!(f, "$stream({})", stream.as_ptr() as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,15 +199,21 @@ impl fmt::Display for DBRef {
|
||||
impl fmt::Display for Addr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Addr::Char(c) => write!(f, "Addr::Char({})", c),
|
||||
&Addr::CharCode(c) => write!(f, "Addr::CharCode({})", c),
|
||||
&Addr::EmptyList => write!(f, "Addr::EmptyList"),
|
||||
&Addr::Fixnum(n) => write!(f, "Addr::Fixnum({})", n),
|
||||
&Addr::Float(fl) => write!(f, "Addr::Float({})", fl),
|
||||
&Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp),
|
||||
&Addr::Con(ref c) => write!(f, "Addr::Con({})", c),
|
||||
&Addr::DBRef(ref db_ref) => write!(f, "Addr::DBRef({})", db_ref),
|
||||
&Addr::Lis(l) => write!(f, "Addr::Lis({})", l),
|
||||
&Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h),
|
||||
&Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
|
||||
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
|
||||
&Addr::Str(s) => write!(f, "Addr::Str({})", s),
|
||||
&Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n),
|
||||
&Addr::PStrTail(h, n) => write!(f, "Addr::PStrTail({}, {})", h, n),
|
||||
&Addr::Stream(stream) => write!(f, "Addr::Stream({})", stream),
|
||||
&Addr::Usize(cp) => write!(f, "Addr::Usize({})", cp),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,14 +289,18 @@ impl fmt::Display for IndexingInstruction {
|
||||
impl fmt::Display for SessionError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&SessionError::CannotOverwriteBuiltIn(ref msg) => write!(f, "cannot overwrite {}", msg),
|
||||
&SessionError::ExistenceError(ref err) => {
|
||||
write!(f, "{}", err)
|
||||
}
|
||||
&SessionError::CannotOverwriteBuiltIn(ref msg) => {
|
||||
write!(f, "cannot overwrite {}", msg)
|
||||
}
|
||||
&SessionError::CannotOverwriteImport(ref msg) => {
|
||||
write!(f, "cannot overwrite import {}", msg)
|
||||
}
|
||||
&SessionError::InvalidFileName(ref filename) => {
|
||||
write!(f, "filename {} is invalid", filename)
|
||||
}
|
||||
&SessionError::ModuleNotFound => write!(f, "module not found."),
|
||||
&SessionError::ModuleDoesNotContainExport(ref module, ref key) => {
|
||||
write!(
|
||||
f,
|
||||
@@ -282,7 +316,44 @@ impl fmt::Display for SessionError {
|
||||
&SessionError::NamelessEntry => {
|
||||
write!(f, "the predicate head is not an atom or clause.")
|
||||
}
|
||||
&SessionError::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()),
|
||||
&SessionError::ParserError(ref e) => {
|
||||
write!(f, "syntax_error({})", e.as_str())
|
||||
}
|
||||
&SessionError::QueryCannotBeDefinedAsFact => {
|
||||
write!(f, "queries cannot be defined as facts.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ExistenceError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ExistenceError::Module(ref module_name) => {
|
||||
write!(f, "the module {} does not exist", module_name)
|
||||
}
|
||||
&ExistenceError::Procedure(ref name, arity) => {
|
||||
write!(f, "the procedure {}/{} does not exist", name, arity)
|
||||
}
|
||||
&ExistenceError::SourceSink(ref module_source) => {
|
||||
write!(f, "the source/sink {} does not exist", module_source)
|
||||
}
|
||||
&ExistenceError::Stream(ref addr) => {
|
||||
write!(f, "the stream at {} does not exist", addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ModuleSource {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ModuleSource::File(ref file) => {
|
||||
write!(f, "at the file {}", file)
|
||||
}
|
||||
&ModuleSource::Library(ref library) => {
|
||||
write!(f, "at library({})", library)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -305,6 +376,7 @@ impl fmt::Display for Line {
|
||||
impl fmt::Display for Number {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Number::Fixnum(n) => write!(f, "{}", n),
|
||||
&Number::Float(fl) => write!(f, "{}", fl),
|
||||
&Number::Integer(ref bi) => write!(f, "{}", bi),
|
||||
&Number::Rational(ref r) => write!(f, "{}", r),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
:- module(tests_on_builtins, []).
|
||||
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(non_iso)).
|
||||
:- use_module(library(iso_ext)).
|
||||
|
||||
test_queries_on_builtins :-
|
||||
\+ atom(_),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
:- module(tests_on_call_with_inference_limit, []).
|
||||
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(non_iso)).
|
||||
:- use_module(library(iso_ext)).
|
||||
|
||||
:- dynamic(f/1).
|
||||
:- dynamic(g/1).
|
||||
|
||||
@@ -62,4 +62,3 @@ cleanup :- abolish(p/3),
|
||||
abolish(h/1).
|
||||
|
||||
:- initialization(test_queries_on_rules).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
:- module(test_on_setup_call_cleanup, []).
|
||||
|
||||
:- use_module(library(non_iso)).
|
||||
:- use_module(library(iso_ext)).
|
||||
|
||||
test_queries_on_setup_call_cleanup :-
|
||||
\+ setup_call_cleanup(false, _, _),
|
||||
|
||||
Reference in New Issue
Block a user