Compare commits
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb1980d286 | ||
|
|
424af312e5 | ||
|
|
a2a4c78c9a | ||
|
|
0457b38e41 | ||
|
|
617f803355 | ||
|
|
d3da2683cb | ||
|
|
d97c670fcd | ||
|
|
8902bcb5ab | ||
|
|
5f51e264f2 | ||
|
|
1c4e2c0ed6 | ||
|
|
5a6333129b | ||
|
|
969bd8f82c | ||
|
|
a732bc9dc4 | ||
|
|
1b5cf493d6 | ||
|
|
0be8abd38c | ||
|
|
b71e8082d2 | ||
|
|
034af296ff | ||
|
|
554b08a7d2 | ||
|
|
00b38549f5 | ||
|
|
62b41ddb93 | ||
|
|
d83c5cf5f1 | ||
|
|
740bd528c4 | ||
|
|
668c9489c9 | ||
|
|
dcf2eadcf2 | ||
|
|
9c1064c1a3 | ||
|
|
40bf5bc75f | ||
|
|
6be2d8ccf2 | ||
|
|
9958ad6f34 | ||
|
|
728be8c259 | ||
|
|
9a80d398e8 | ||
|
|
242c47bb92 | ||
|
|
85e37a9977 | ||
|
|
dded56af78 | ||
|
|
3bf1cbbe6c | ||
|
|
4ef8ab6e76 | ||
|
|
837ae4cb17 | ||
|
|
a4e352ba0d | ||
|
|
02d8b1441d | ||
|
|
196784bd09 | ||
|
|
b0fa45cd33 | ||
|
|
923c9d4ad8 | ||
|
|
2be7070e1a | ||
|
|
f16c2a6e99 | ||
|
|
d6e75110a5 | ||
|
|
3d2c4f0801 | ||
|
|
5ccd334555 | ||
|
|
90e1c990e5 | ||
|
|
018b076835 | ||
|
|
9ae029b04d | ||
|
|
43b39538ff | ||
|
|
738ea59e23 | ||
|
|
33c60d3434 | ||
|
|
607673ddcb | ||
|
|
fc8e55c582 | ||
|
|
943e5eeb35 | ||
|
|
52488b875a | ||
|
|
c362cc6d34 | ||
|
|
406d3520f1 | ||
|
|
9b71866b54 | ||
|
|
e48f87fcf0 | ||
|
|
77e83a390c | ||
|
|
27b659c401 | ||
|
|
a4cacaeab2 | ||
|
|
0eb20a5d8e | ||
|
|
3e49db1a29 | ||
|
|
2d719ab6b7 | ||
|
|
34745f6242 | ||
|
|
9c9c484ee4 | ||
|
|
335202b9d9 | ||
|
|
f998d6a99f | ||
|
|
5723edd765 | ||
|
|
7eb0de7f52 | ||
|
|
9ae901bd0d | ||
|
|
1dec482e22 | ||
|
|
0a665b79f2 | ||
|
|
c3c53017f9 | ||
|
|
834c57466f | ||
|
|
4e887e3a87 | ||
|
|
7bf6a230f3 | ||
|
|
24ffdc2724 | ||
|
|
6899f051ac | ||
|
|
d9d77b3022 | ||
|
|
b31b23e41c | ||
|
|
16418a47a8 | ||
|
|
1139b3b4c1 | ||
|
|
3277ecd13d | ||
|
|
37ff4a821c | ||
|
|
f82c6f3fed | ||
|
|
d3842bb070 | ||
|
|
2ab745016a | ||
|
|
5aaba8534f | ||
|
|
2b625b1094 | ||
|
|
17f9695ab2 | ||
|
|
c0a49b6a66 | ||
|
|
66bebff01e | ||
|
|
6f9477f0bb | ||
|
|
de88fdc4dc | ||
|
|
c219d9ad5f | ||
|
|
15927d7054 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,3 @@
|
|||||||
target/
|
target/
|
||||||
Cargo.lock
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ matrix:
|
|||||||
script:
|
script:
|
||||||
- cargo build --verbose --all
|
- cargo build --verbose --all
|
||||||
- cargo test --verbose --all
|
- cargo test --verbose --all
|
||||||
|
- cargo test --verbose --all --no-default-features --features num
|
||||||
|
|||||||
647
Cargo.lock
generated
Normal file
647
Cargo.lock
generated
Normal file
@@ -0,0 +1,647 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "arrayref"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.4.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
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)",
|
||||||
|
"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)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace-sys"
|
||||||
|
version = "0.1.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blake2b_simd"
|
||||||
|
version = "0.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
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)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "constant_time_eq"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
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)",
|
||||||
|
"lazy_static 1.4.0 (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)",
|
||||||
|
"dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
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)",
|
||||||
|
"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)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "downcast"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "failure"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "failure_derive"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuchsia-cprng"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gmp-mpfr-sys"
|
||||||
|
version = "1.1.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"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)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
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)",
|
||||||
|
"lexical-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
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)",
|
||||||
|
"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)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.62"
|
||||||
|
source = "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)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "maybe-uninit"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.2.1"
|
||||||
|
source = "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)",
|
||||||
|
"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)",
|
||||||
|
"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)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
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)",
|
||||||
|
"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)",
|
||||||
|
"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)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nodrop"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rug-adapter"
|
||||||
|
version = "0.1.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)",
|
||||||
|
"num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ordered-float"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "0.4.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prolog_parser"
|
||||||
|
version = "0.8.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"lexical 2.1.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)",
|
||||||
|
"rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode_reader 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "0.6.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_os"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rdrand 0.4.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 = "rdrand"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
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"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ref_thread_local"
|
||||||
|
version = "0.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rug"
|
||||||
|
version = "1.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"gmp-mpfr-sys 1.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-argon2"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustyline"
|
||||||
|
version = "5.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"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)",
|
||||||
|
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scryer-prolog"
|
||||||
|
version = "0.8.118"
|
||||||
|
dependencies = [
|
||||||
|
"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)",
|
||||||
|
"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)",
|
||||||
|
"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)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "0.6.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stackvector"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "0.15.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "synstructure"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"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"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode_reader"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unreachable"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "void"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"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 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 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 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 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 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 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 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"
|
||||||
|
"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a"
|
||||||
|
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
|
||||||
|
"checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454"
|
||||||
|
"checksum num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab3f405f69d14cdcf0ca44599eb074093633a53ec3d402be0bf1e57709c7502"
|
||||||
|
"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 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 quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||||
|
"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 ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||||
|
"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
|
||||||
|
"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 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_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.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||||
|
"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"
|
||||||
15
Cargo.toml
15
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "scryer-prolog"
|
name = "scryer-prolog"
|
||||||
version = "0.8.116"
|
version = "0.8.118"
|
||||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
repository = "https://github.com/mthom/scryer-prolog"
|
repository = "https://github.com/mthom/scryer-prolog"
|
||||||
@@ -11,6 +11,10 @@ edition = "2018"
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
indexmap = "1.0.2"
|
indexmap = "1.0.2"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["rug", "prolog_parser/rug"]
|
||||||
|
num = ["num-rug-adapter", "prolog_parser/num"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dirs = "2.0.2"
|
dirs = "2.0.2"
|
||||||
downcast = "0.10.0"
|
downcast = "0.10.0"
|
||||||
@@ -18,11 +22,10 @@ indexmap = "1.0.2"
|
|||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
libc = "0.2.62"
|
libc = "0.2.62"
|
||||||
nix = "0.15.0"
|
nix = "0.15.0"
|
||||||
|
num-rug-adapter = { optional = true, version = "0.1.1" }
|
||||||
ordered-float = "0.5.0"
|
ordered-float = "0.5.0"
|
||||||
prolog_parser = "0.8.34"
|
prolog_parser = { version = "0.8.40", default-features = false }
|
||||||
ref_thread_local = "0.0.0"
|
ref_thread_local = "0.0.0"
|
||||||
rug = "1.4.0"
|
rug = { version = "1.4.0", optional = true }
|
||||||
rustyline = "5.0.3"
|
rustyline = "5.0.3"
|
||||||
|
termion = "1.4.0"
|
||||||
[dependencies.termion]
|
|
||||||
version = "1.4.0"
|
|
||||||
|
|||||||
170
README.md
170
README.md
@@ -30,10 +30,8 @@ Extend Scryer Prolog to include the following, among other features:
|
|||||||
- [x] Built-in predicates for list processing and top-level declarative
|
- [x] Built-in predicates for list processing and top-level declarative
|
||||||
control (`setup_call_cleanup/3`, `call_with_inference_limit/3`,
|
control (`setup_call_cleanup/3`, `call_with_inference_limit/3`,
|
||||||
etc.)
|
etc.)
|
||||||
- [x] Default representation of strings as list of chars, using a packed
|
- [x] ~~Default representation of strings as list of chars, using a packed
|
||||||
internal representation.
|
internal representation.~~
|
||||||
- A representation of 'partial strings' as difference lists
|
|
||||||
of characters.
|
|
||||||
- [x] `term_expansion/2` and `goal_expansion/2`.
|
- [x] `term_expansion/2` and `goal_expansion/2`.
|
||||||
- [x] Definite Clause Grammars.
|
- [x] Definite Clause Grammars.
|
||||||
- [x] Attributed variables using the SICStus Prolog interface and
|
- [x] Attributed variables using the SICStus Prolog interface and
|
||||||
@@ -50,7 +48,13 @@ Extend Scryer Prolog to include the following, among other features:
|
|||||||
- [x] Backtrackable and non-backtrackable global variables via `bb_get/2`
|
- [x] Backtrackable and non-backtrackable global variables via `bb_get/2`
|
||||||
`bb_put/2` (non-backtrackable) and `bb_b_put/2`
|
`bb_put/2` (non-backtrackable) and `bb_b_put/2`
|
||||||
(backtrackable).
|
(backtrackable).
|
||||||
- [ ] clp(B) and clp($\mathbb{Z}$) as builtin libraries (_in progress_).
|
- [x] Delimited continuations based on reset/3, shift/1 (documented in
|
||||||
|
"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_).
|
||||||
- [ ] Streams and predicates for stream control (_in progress_).
|
- [ ] Streams and predicates for stream control (_in progress_).
|
||||||
- [ ] An incremental compacting garbage collector satisfying the five
|
- [ ] An incremental compacting garbage collector satisfying the five
|
||||||
properties of "Precise Garbage Collection in Prolog."
|
properties of "Precise Garbage Collection in Prolog."
|
||||||
@@ -79,15 +83,10 @@ Programming?"
|
|||||||
unum implementation or an ad hoc one. Unums are described in
|
unum implementation or an ad hoc one. Unums are described in
|
||||||
Gustafson's book "The End of Error."
|
Gustafson's book "The End of Error."
|
||||||
|
|
||||||
3. Add support for shift/reset delimited continuations, see "Delimited
|
3. Add concurrent tables to manage shared references to atoms and
|
||||||
Continuations for Prolog."
|
|
||||||
|
|
||||||
4. Add concurrent tables to manage shared references to atoms and
|
|
||||||
strings.
|
strings.
|
||||||
|
|
||||||
5. Add optional SLG resolution for fast memoization of predicates.
|
4. Add some form of JIT predicate indexing.
|
||||||
|
|
||||||
6. Add some form of JIT predicate indexing.
|
|
||||||
|
|
||||||
## Installing Scryer Prolog
|
## Installing Scryer Prolog
|
||||||
|
|
||||||
@@ -123,125 +122,6 @@ and BSD variants on which Rust runs. Windows support hinges on
|
|||||||
rustyline and Termion being functional in that environment, which to
|
rustyline and Termion being functional in that environment, which to
|
||||||
my knowledge is not presently the case.
|
my knowledge is not presently the case.
|
||||||
|
|
||||||
## Built-in predicates
|
|
||||||
|
|
||||||
The following predicates are built-in to Scryer.
|
|
||||||
|
|
||||||
* Arithmetic support:
|
|
||||||
* `is/2` works for `(+)/{1,2}`, `(-)/{1,2}`, `(*)/2`, `(//)/2`, `(**)/2`,
|
|
||||||
`(^)/2`, `(div)/2`, `(/)/2`, `(rdiv)/2`, `(xor)/2`, `(rem)/2`,
|
|
||||||
`(mod)/2`, `(/\)/2`, `(\/)/2`, `(>>)/2`,`(<<)/2`, `(\)/1`,
|
|
||||||
`abs/1`, `sin/1`, `cos/1`, `tan/1`, `asin/1`, `acos/1`,
|
|
||||||
`atan/1`, `atan2/2`, `log/1`, `exp/1`, `sqrt/1`, `float/1`,
|
|
||||||
`truncate/1`, `round/1`, `floor/1`, `ceiling/1`, `pi/0`,
|
|
||||||
`min/1`, `max/1`, `gcd/2`, `sign/1`
|
|
||||||
* Comparison operators: `>`, `<`, `=<`, `>=`, `=:=`, `=\=`.
|
|
||||||
* `(:)/2`
|
|
||||||
* `(@>)/2`
|
|
||||||
* `(@>=)/2`
|
|
||||||
* `(@=<)/2`
|
|
||||||
* `(@<)/2`
|
|
||||||
* `(\+)/1`
|
|
||||||
* `(==)/2`
|
|
||||||
* `(\==)/2`
|
|
||||||
* `(=)/2`
|
|
||||||
* `(\=)/2`
|
|
||||||
* `(=..)/2`
|
|
||||||
* `(->)/2`
|
|
||||||
* `(;)/2`
|
|
||||||
* `abolish/1`
|
|
||||||
* `acyclic_term/2`
|
|
||||||
* `append/3`
|
|
||||||
* `arg/3`
|
|
||||||
* `asserta/1`
|
|
||||||
* `assertz/1`
|
|
||||||
* `atom/1`
|
|
||||||
* `atomic/1`
|
|
||||||
* `atom_chars/2`
|
|
||||||
* `atom_codes/2`
|
|
||||||
* `atom_concat/3`
|
|
||||||
* `atom_length/2`
|
|
||||||
* `bagof/3`
|
|
||||||
* `bb_b_put/2`
|
|
||||||
* `bb_get/2`
|
|
||||||
* `bb_put/2`
|
|
||||||
* `between/3`
|
|
||||||
* `call/1..62`
|
|
||||||
* `call_cleanup/2`
|
|
||||||
* `call_with_inference_limit/3`
|
|
||||||
* `call_residue_vars/2`
|
|
||||||
* `can_be/2`
|
|
||||||
* `catch/3`
|
|
||||||
* `clause/2`
|
|
||||||
* `compare/3`
|
|
||||||
* `compound/1`
|
|
||||||
* `copy_term/2`
|
|
||||||
* `current_predicate/1`
|
|
||||||
* `current_op/3`
|
|
||||||
* `cyclic_term/1`
|
|
||||||
* `dif/2`
|
|
||||||
* `expand_goal/2`
|
|
||||||
* `expand_term/2`
|
|
||||||
* `fail/0`
|
|
||||||
* `false/0`
|
|
||||||
* `findall/{3,4}`
|
|
||||||
* `float/1`
|
|
||||||
* `forall/2`
|
|
||||||
* `freeze/2`
|
|
||||||
* `functor/3`
|
|
||||||
* `gen_int/1`
|
|
||||||
* `gen_nat/1`
|
|
||||||
* `get_char/1`
|
|
||||||
* `goal_expansion/2`
|
|
||||||
* `ground/1`
|
|
||||||
* `halt/0`
|
|
||||||
* `integer/1`
|
|
||||||
* `is_list/1`
|
|
||||||
* `is_partial_string/1`
|
|
||||||
* `keysort/2`
|
|
||||||
* `length/2`
|
|
||||||
* `maplist/2..9`
|
|
||||||
* `member/2`
|
|
||||||
* `memberchk/2`
|
|
||||||
* `must_be/2`
|
|
||||||
* `nl/0`
|
|
||||||
* `nonvar/1`
|
|
||||||
* `number_chars/2`
|
|
||||||
* `number_codes/2`
|
|
||||||
* `numbervars/2`
|
|
||||||
* `numlist/{2,3}`
|
|
||||||
* `once/1`
|
|
||||||
* `op/3`
|
|
||||||
* `partial_string/2`
|
|
||||||
* `phrase/{2,3}`
|
|
||||||
* `rational/1`
|
|
||||||
* `read/1`
|
|
||||||
* `repeat/{0,1}`
|
|
||||||
* `retract/1`
|
|
||||||
* `reverse/2`
|
|
||||||
* `select/3`
|
|
||||||
* `setof/3`
|
|
||||||
* `setup_call_cleanup/3`
|
|
||||||
* `sort/2`
|
|
||||||
* `string/1`
|
|
||||||
* `sub_atom/5`
|
|
||||||
* `subsumes_term/2`
|
|
||||||
* `term_expansion/2`
|
|
||||||
* `term_variables/2`
|
|
||||||
* `throw/1`
|
|
||||||
* `true/0`
|
|
||||||
* `unify_with_occurs_check/2`
|
|
||||||
* `use_module/{1,2}`
|
|
||||||
* `user:goal_expansion/2`
|
|
||||||
* `user:term_expansion/2`
|
|
||||||
* `var/1`
|
|
||||||
* `variant/2`
|
|
||||||
* `wam_instructions/2`
|
|
||||||
* `write/1`
|
|
||||||
* `write_canonical/1`
|
|
||||||
* `writeq/1`
|
|
||||||
* `write_term/2`
|
|
||||||
|
|
||||||
## Tutorial
|
## Tutorial
|
||||||
To enter a multi-clause predicate, the directive "[user]" is used.
|
To enter a multi-clause predicate, the directive "[user]" is used.
|
||||||
|
|
||||||
@@ -319,22 +199,26 @@ New operators can be defined using the `op` declaration.
|
|||||||
|
|
||||||
### Partial strings
|
### Partial strings
|
||||||
|
|
||||||
Scryer has two specialized, non-ISO builtin predicates for handling
|
Scryer has three specialized non-ISO predicates for handling so-called
|
||||||
so-called "partial strings". Partial strings imitate difference lists
|
"partial strings." Partial strings imitate difference lists of
|
||||||
of characters, but are much more space efficient. This efficiency
|
characters, but their characters are packed in UTF-8 format, a much
|
||||||
comes at the cost of full generality -- you cannot unify the tail
|
more efficient alternative to how lists of characters are represented
|
||||||
variables of two distinct partial strings, because their buffers will
|
in many other Prologs.
|
||||||
always be distinct.
|
|
||||||
|
To use partial strings, the `non_iso` library must be loaded:
|
||||||
|
|
||||||
|
`?- use_module(library(non_iso)).`
|
||||||
|
|
||||||
If `X` is a free variable, the query
|
If `X` is a free variable, the query
|
||||||
|
|
||||||
`?- partial_string("abc", X), X = [a, b, c | Y], is_partial_string(X),
|
`?- partial_string("abc", X, _), X = [a, b, c | Y], partial_string(X),
|
||||||
is_partial_string(Y).`
|
partial_string_tail(X, Tail), Tail == Y.`
|
||||||
|
|
||||||
will succeed. Further, if `Y` a free variable, unifying `Y` against
|
will succeed, posting:
|
||||||
another string, "def" in this case, produces the equations
|
|
||||||
|
|
||||||
`X = [a, b, c, d, e, f], Y = [d, e, f].`
|
`Tail = Y, X = [a,b,c|Y].`
|
||||||
|
|
||||||
|
By all appearances, partial strings are plain Prolog lists.
|
||||||
|
|
||||||
### Modules
|
### Modules
|
||||||
|
|
||||||
@@ -388,4 +272,4 @@ local_member(X, Xs) :- member(X, Xs).
|
|||||||
```
|
```
|
||||||
|
|
||||||
The user listing can also be terminated by placing `end_of_file.` at
|
The user listing can also be terminated by placing `end_of_file.` at
|
||||||
the end of the stream.
|
the end of the stream.
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
use std::cell::{Cell};
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
pub type Var = String;
|
|
||||||
|
|
||||||
pub type Atom = String;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Term),
|
|
||||||
Query(Term)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<usize>, Atom),
|
|
||||||
Clause(Cell<usize>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<usize>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Atom, usize, usize),
|
|
||||||
UnifyVariable(usize),
|
|
||||||
UnifyValue(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
PutStructure(Atom, usize, usize),
|
|
||||||
SetVariable(usize),
|
|
||||||
SetValue(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
RegNum(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn set_cell(&self, cell_num: usize) {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(ref cell, _) => cell.set(cell_num),
|
|
||||||
&Term::Clause(ref cell, _, _) => cell.set(cell_num),
|
|
||||||
&Term::Var(ref cell, _) => cell.set(cell_num)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
use l0::ast::{Atom, Term, FactInstruction, QueryInstruction, Var};
|
|
||||||
use l0::iterators::{BreadthFirstIterator, PostOrderIterator};
|
|
||||||
|
|
||||||
use std::collections::{HashSet};
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::PutStructure(ref a, ref s, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, X{}", a, s, r),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable X{}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value X{}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(ref a, ref s, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, X{}", a, s, r),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable X{}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value X{}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=&'a Term>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self;
|
|
||||||
fn to_value(cell_num: usize) -> Self;
|
|
||||||
fn to_variable(cell_num: usize) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
|
||||||
type Iterator = BreadthFirstIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.breadth_first_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self {
|
|
||||||
FactInstruction::GetStructure(name, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_value(cell_num: usize) -> Self {
|
|
||||||
FactInstruction::UnifyValue(cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_variable(cell_num: usize) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(cell_num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|
||||||
type Iterator = PostOrderIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.post_order_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::PutStructure(name, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_value(cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::SetValue(cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_variable(cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::SetVariable(cell_num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<'a, Target>(subterm: &'a Term,
|
|
||||||
bindings: &mut HashSet<&'a Var>)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell_num, _) =>
|
|
||||||
Target::to_value(cell_num.get()),
|
|
||||||
&Term::Var(ref cell_num, ref atom) if bindings.contains(atom) =>
|
|
||||||
Target::to_value(cell_num.get()),
|
|
||||||
&Term::Var(ref cell_num, ref atom) => {
|
|
||||||
bindings.insert(atom);
|
|
||||||
Target::to_variable(cell_num.get())
|
|
||||||
},
|
|
||||||
&Term::Clause(ref cell_num, _, _) =>
|
|
||||||
Target::to_value(cell_num.get())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_target<'a, Target>(term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let mut iter = Target::iter(term);
|
|
||||||
let mut target = Vec::<Target>::new();
|
|
||||||
let mut bindings = HashSet::new();
|
|
||||||
|
|
||||||
while let Some(term) = iter.next() {
|
|
||||||
match term {
|
|
||||||
&Term::Atom(ref cell_num, ref atom) =>
|
|
||||||
target.push(Target::to_structure(atom.clone(), 0, cell_num.get())),
|
|
||||||
&Term::Clause(ref cell_num, ref atom, ref terms) => {
|
|
||||||
target.push(Target::to_structure(atom.clone(), 0, cell_num.get()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(subterm_to_instr(subterm.as_ref(), &mut bindings));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
use l0::ast::{Term};
|
|
||||||
|
|
||||||
use std::collections::{VecDeque};
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
enum DepthFirstIteratorState<'a> {
|
|
||||||
// child no., the containing clause, its vector.
|
|
||||||
Clause(usize, &'a Term, &'a Vec<Box<Term>>),
|
|
||||||
NonClause(&'a Term)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PostOrderIterator<'a> {
|
|
||||||
state_stack: Vec<DepthFirstIteratorState<'a>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PostOrderIterator<'a> {
|
|
||||||
fn push_clause(&mut self,
|
|
||||||
child_num: usize,
|
|
||||||
term: &'a Term,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(DepthFirstIteratorState::Clause(child_num,
|
|
||||||
term,
|
|
||||||
child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_new_state(term: &'a Term) -> DepthFirstIteratorState<'a> {
|
|
||||||
match term {
|
|
||||||
&Term::Clause(_, _, ref child_terms) =>
|
|
||||||
DepthFirstIteratorState::Clause(0, term, child_terms),
|
|
||||||
_ => DepthFirstIteratorState::NonClause(term)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_term(&mut self, term: &'a Term) {
|
|
||||||
self.state_stack.push(Self::render_new_state(term));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for PostOrderIterator<'a> {
|
|
||||||
type Item = &'a Term;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
|
||||||
match iter_state {
|
|
||||||
DepthFirstIteratorState::Clause(child_num, term, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return Some(term);
|
|
||||||
} else {
|
|
||||||
self.push_clause(child_num + 1, term, child_terms);
|
|
||||||
self.push_term(child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DepthFirstIteratorState::NonClause(term) => return Some(term),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BreadthFirstIterator<'a> {
|
|
||||||
state_queue : VecDeque<&'a Term>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for BreadthFirstIterator<'a> {
|
|
||||||
type Item = &'a Term;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if let Some(term) = self.state_queue.pop_front() {
|
|
||||||
if let &Term::Clause(_, _, ref child_terms) = term {
|
|
||||||
for term in child_terms {
|
|
||||||
self.state_queue.push_back(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Term {
|
|
||||||
pub fn post_order_iter(&'a self) -> PostOrderIterator<'a> {
|
|
||||||
let initial_state = PostOrderIterator::render_new_state(self);
|
|
||||||
PostOrderIterator { state_stack: vec![initial_state] }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breadth_first_iter(&'a self) -> BreadthFirstIterator<'a> {
|
|
||||||
let mut queue = VecDeque::new();
|
|
||||||
queue.push_back(self);
|
|
||||||
|
|
||||||
BreadthFirstIterator { state_queue: queue }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
use std::cell::{Cell};
|
|
||||||
use l0::ast::{Atom, Term, TopLevel, Var};
|
|
||||||
|
|
||||||
grammar;
|
|
||||||
|
|
||||||
pub TopLevel: TopLevel = {
|
|
||||||
"?-" <t:Term> "." => TopLevel::Query(t),
|
|
||||||
<t:Term> "." => TopLevel::Fact(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Atom : Atom = {
|
|
||||||
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Var : Var = {
|
|
||||||
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
BoxedTerm : Box<Term> = {
|
|
||||||
<t:Term> => Box::new(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Term : Term = {
|
|
||||||
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
|
||||||
let mut ts = ts;
|
|
||||||
ts.push(t);
|
|
||||||
Term::Clause(Cell::new(0), a, ts)
|
|
||||||
},
|
|
||||||
<Atom> => Term::Atom(Cell::new(0), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(0), <>),
|
|
||||||
};
|
|
||||||
1595
src/l0/l0_parser.rs
1595
src/l0/l0_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,238 +0,0 @@
|
|||||||
use l0::ast::{Addr, Atom, CompiledFact, FactInstruction, QueryInstruction};
|
|
||||||
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
enum HeapCell {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(usize),
|
|
||||||
Str(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
type Heap = Vec<HeapCell>;
|
|
||||||
|
|
||||||
type Registers = Vec<HeapCell>;
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
h : usize,
|
|
||||||
s : usize,
|
|
||||||
pub fail : bool,
|
|
||||||
heap : Heap,
|
|
||||||
mode : MachineMode,
|
|
||||||
pub program : Option<CompiledFact>,
|
|
||||||
registers : Registers
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Machine {
|
|
||||||
Machine { h : 0,
|
|
||||||
s : 0,
|
|
||||||
fail : false,
|
|
||||||
heap : Vec::with_capacity(256),
|
|
||||||
mode : MachineMode::Write,
|
|
||||||
program : None,
|
|
||||||
registers : vec![HeapCell::Ref(0); 33] }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&self, a: Addr) -> &HeapCell {
|
|
||||||
match a {
|
|
||||||
Addr::HeapCell(hc) => &self.heap[hc],
|
|
||||||
Addr::RegNum(reg) => &self.registers[reg]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deref(&self, a: Addr) -> Addr {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if let &HeapCell::Ref(value) = self.lookup(a) {
|
|
||||||
if let Addr::HeapCell(av) = a {
|
|
||||||
if value != av {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_unbound(hc: &HeapCell, index: usize) -> bool {
|
|
||||||
match hc {
|
|
||||||
&HeapCell::Ref(r) => r == index,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: try to compress this function. currently it is dog shit.
|
|
||||||
fn bind(&mut self, a: Addr, val: usize) {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match a {
|
|
||||||
Addr::RegNum(reg) => {
|
|
||||||
if let HeapCell::Ref(hc) = self.registers[reg] {
|
|
||||||
a = Addr::HeapCell(hc);
|
|
||||||
} else if Machine::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = self.registers[reg].clone();
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[hc], hc) => {
|
|
||||||
self.heap[hc] = HeapCell::Ref(val);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[val], val) => {
|
|
||||||
self.heap[val] = HeapCell::Ref(hc);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unify(&mut self, a1: Addr, a2: Addr) {
|
|
||||||
let mut pdl : Vec<Addr> = vec![a1, a2];
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
|
|
||||||
while !(pdl.is_empty() || self.fail) {
|
|
||||||
let d1 = self.deref(pdl.pop().unwrap());
|
|
||||||
let d2 = self.deref(pdl.pop().unwrap());
|
|
||||||
|
|
||||||
if d1 != d2 {
|
|
||||||
match (self.lookup(d1), self.lookup(d2)) {
|
|
||||||
(&HeapCell::Ref(hc), _) =>
|
|
||||||
self.bind(d2, hc),
|
|
||||||
(_, &HeapCell::Ref(hc)) =>
|
|
||||||
self.bind(d1, hc),
|
|
||||||
(&HeapCell::Str(a1), &HeapCell::Str(a2)) => {
|
|
||||||
let r1 = &self.heap[a1];
|
|
||||||
let r2 = &self.heap[a2];
|
|
||||||
|
|
||||||
if let &HeapCell::NamedStr(n1, ref f1) = r1 {
|
|
||||||
if let &HeapCell::NamedStr(n2, ref f2) = r2 {
|
|
||||||
if n1 == n2 && *f1 == *f2 {
|
|
||||||
for i in 1 .. n1 {
|
|
||||||
pdl.push(Addr::HeapCell(a1 + i));
|
|
||||||
pdl.push(Addr::HeapCell(a2 + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fail = true;
|
|
||||||
},
|
|
||||||
_ => self.fail = true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_query_instr<'a, 'b : 'a>(&'a mut self, instr: &'b QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::PutStructure(ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCell::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCell::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetVariable(reg) => {
|
|
||||||
self.heap.push(HeapCell::Ref(self.h));
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_fact_instr<'a, 'b : 'a>(&'a mut self, instr: &'b FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
&FactInstruction::GetStructure(ref name, arity, reg) => {
|
|
||||||
let addr = self.deref(Addr::RegNum(reg));
|
|
||||||
|
|
||||||
match self.lookup(addr) {
|
|
||||||
&HeapCell::Str(a) => {
|
|
||||||
let result = &self.heap[a];
|
|
||||||
|
|
||||||
if let &HeapCell::NamedStr(named_arity, ref named_str) = result {
|
|
||||||
if arity == named_arity && *name == *named_str {
|
|
||||||
self.s = a + 1;
|
|
||||||
self.mode = MachineMode::Read;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&HeapCell::Ref(r) => {
|
|
||||||
self.heap.push(HeapCell::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCell::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
let h = self.h;
|
|
||||||
|
|
||||||
self.bind(Addr::HeapCell(r), h);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyVariable(reg) => {
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => self.registers[reg] = self.heap[self.s].clone(),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCell::Ref(self.h));
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyValue(reg) => {
|
|
||||||
let s = self.s;
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => self.unify(Addr::RegNum(reg), Addr::HeapCell(s)),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_heap(&mut self) {
|
|
||||||
let program = self.program.take();
|
|
||||||
|
|
||||||
*self = Machine::new();
|
|
||||||
self.program = program;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
mod l0_parser;
|
|
||||||
|
|
||||||
pub mod ast;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod machine;
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
use l0::ast::{Term, TopLevel, Var};
|
|
||||||
use l0::l0_parser::{parse_TopLevel};
|
|
||||||
|
|
||||||
use std::collections::{HashMap};
|
|
||||||
|
|
||||||
extern crate lalrpop_util as __lalrpop_util;
|
|
||||||
|
|
||||||
pub type ParseResult<'a> =
|
|
||||||
Result<TopLevel, __lalrpop_util::ParseError<usize,(usize, &'a str),()>>;
|
|
||||||
|
|
||||||
pub fn parse_top_level<'a>(input: &'a str) -> ParseResult {
|
|
||||||
let result = parse_TopLevel(&*input);
|
|
||||||
|
|
||||||
if let Ok(result) = result {
|
|
||||||
return Ok(mark_cells(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn mark_cells(tl: TopLevel) -> TopLevel {
|
|
||||||
match tl {
|
|
||||||
TopLevel::Fact(term) => TopLevel::Fact(mark_term_cells(term)),
|
|
||||||
TopLevel::Query(term) => TopLevel::Query(mark_term_cells(term))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_term_cells(term: Term) -> Term {
|
|
||||||
let mut cell_num = 1;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut bindings: HashMap<&Var, usize> = HashMap::new();
|
|
||||||
let mut iter = term.breadth_first_iter();
|
|
||||||
|
|
||||||
while let Some(term) = iter.next() {
|
|
||||||
if let &Term::Var(ref cell, ref var) = term {
|
|
||||||
let cell_num_in_map = bindings.entry(var).or_insert(cell_num);
|
|
||||||
|
|
||||||
if *cell_num_in_map != cell_num {
|
|
||||||
cell.set(*cell_num_in_map);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
term.set_cell(cell_num);
|
|
||||||
cell_num += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
term
|
|
||||||
}
|
|
||||||
123
src/l1/ast.rs
123
src/l1/ast.rs
@@ -1,123 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub type Var = String;
|
|
||||||
|
|
||||||
pub type Atom = String;
|
|
||||||
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Term),
|
|
||||||
Query(Term)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Level {
|
|
||||||
Shallow, Deep
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Level {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&Level::Shallow => write!(f, "A"),
|
|
||||||
&Level::Deep => write!(f, "X")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Reg {
|
|
||||||
ArgAndNorm(usize, usize),
|
|
||||||
Norm(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reg {
|
|
||||||
pub fn has_arg(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
&Reg::ArgAndNorm(_, _) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn norm(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Reg::ArgAndNorm(_, norm) | &Reg::Norm(norm) => norm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<usize>, Atom),
|
|
||||||
Clause(Cell<usize>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<Reg>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TermRef<'a> {
|
|
||||||
Atom(Level, &'a Cell<usize>, &'a Atom),
|
|
||||||
Clause(Level, &'a Cell<usize>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<Reg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Level, Atom, usize, usize),
|
|
||||||
GetValue(usize, usize),
|
|
||||||
GetVariable(usize, usize),
|
|
||||||
Proceed,
|
|
||||||
UnifyVariable(usize),
|
|
||||||
UnifyValue(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
Call(Atom, usize),
|
|
||||||
PutStructure(Level, Atom, usize, usize),
|
|
||||||
PutValue(usize, usize),
|
|
||||||
PutVariable(usize, usize),
|
|
||||||
SetVariable(usize),
|
|
||||||
SetValue(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
RegNum(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum HeapCellValue {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(usize),
|
|
||||||
Str(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Heap = Vec<HeapCellValue>;
|
|
||||||
|
|
||||||
pub type Registers = Vec<HeapCellValue>;
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn subterms(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Clause(_, _, ref terms) => terms.len(),
|
|
||||||
_ => 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &Atom {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, ref atom)
|
|
||||||
| &Term::Var(_, ref atom)
|
|
||||||
| &Term::Clause(_, ref atom, _) => atom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
|
|
||||||
&Term::Clause(_, _, ref child_terms) => child_terms.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
use l1::ast::{Atom, CompiledFact, CompiledQuery, FactInstruction,
|
|
||||||
Level, QueryInstruction, Reg, Term, TermRef, Var};
|
|
||||||
use l1::iterators::{FactIterator, QueryIterator};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::Call(ref name, ref arity) =>
|
|
||||||
write!(f, "call {}/{}", name, arity),
|
|
||||||
&QueryInstruction::PutStructure(ref lvl, ref a, ref s, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, {}{}", a, s, lvl, r),
|
|
||||||
&QueryInstruction::PutValue(ref a, ref x) =>
|
|
||||||
write!(f, "put_value X{}, A{}", x, a),
|
|
||||||
&QueryInstruction::PutVariable(ref a, ref x) =>
|
|
||||||
write!(f, "put_variable X{}, A{}", x, a),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable X{}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value X{}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(ref lvl, ref a, ref s, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, {}{}", a, s, lvl, r),
|
|
||||||
&FactInstruction::GetValue(ref a, ref x) =>
|
|
||||||
write!(f, "get_value X{}, A{}", x, a),
|
|
||||||
&FactInstruction::GetVariable(ref a, ref x) =>
|
|
||||||
write!(f, "get_variable X{}, A{}", x, a),
|
|
||||||
&FactInstruction::Proceed =>
|
|
||||||
write!(f, "proceed"),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable X{}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value X{}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TermMarker<'a> {
|
|
||||||
bindings: HashMap<&'a Var, Reg>,
|
|
||||||
arg_c: usize,
|
|
||||||
norm_c: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TermMarker<'a> {
|
|
||||||
fn new(term: &'a Term) -> TermMarker<'a> {
|
|
||||||
TermMarker { bindings: HashMap::new(),
|
|
||||||
arg_c: 1,
|
|
||||||
norm_c: term.subterms() + 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_var(&self, var: &'a Var) -> bool {
|
|
||||||
self.bindings.contains_key(var)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, var: &'a Var) -> Reg {
|
|
||||||
*self.bindings.get(var).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(&mut self, var: &'a Var, r: Reg) {
|
|
||||||
self.bindings.insert(var, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<usize>) {
|
|
||||||
if cell.get() == 0 {
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => {
|
|
||||||
let norm = self.norm_c;
|
|
||||||
self.norm_c += 1;
|
|
||||||
cell.set(norm);
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(arg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_var(&mut self, lvl: Level, var: &'a Var) -> Reg {
|
|
||||||
if self.contains_var(var) {
|
|
||||||
let reg = self.get(var);
|
|
||||||
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => Reg::Norm(reg.norm()),
|
|
||||||
Level::Shallow if reg.has_arg() => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
|
|
||||||
Reg::ArgAndNorm(arg, reg.norm())
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let norm = reg.norm();
|
|
||||||
let reg = Reg::ArgAndNorm(self.arg_c, norm);
|
|
||||||
|
|
||||||
self.arg_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = match lvl {
|
|
||||||
Level::Deep => Reg::Norm(self.norm_c),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = Reg::ArgAndNorm(self.arg_c, self.norm_c);
|
|
||||||
self.arg_c += 1;
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.norm_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=TermRef<'a>>;
|
|
||||||
|
|
||||||
fn iter(&'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(Level, Atom, usize, usize) -> Self;
|
|
||||||
|
|
||||||
fn argument_to_variable(usize, usize) -> Self;
|
|
||||||
fn argument_to_value(usize, usize) -> Self;
|
|
||||||
fn subterm_to_variable(usize) -> Self;
|
|
||||||
fn subterm_to_value(usize) -> Self;
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(usize) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
|
||||||
type Iterator = FactIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.breadth_first_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, cell_num: usize) -> Self {
|
|
||||||
FactInstruction::GetStructure(lvl, atom, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: usize, val: usize) -> Self {
|
|
||||||
FactInstruction::GetVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: usize, val: usize) -> Self {
|
|
||||||
FactInstruction::GetValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: usize) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: usize) -> Self {
|
|
||||||
FactInstruction::UnifyValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: usize) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|
||||||
type Iterator = QueryIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.post_order_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::PutStructure(lvl, atom, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: usize, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: usize, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: usize) -> Self {
|
|
||||||
QueryInstruction::SetVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: usize) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: usize) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure<'a, Target>(tm: &mut TermMarker<'a>,
|
|
||||||
lvl: Level,
|
|
||||||
name: &'a Atom,
|
|
||||||
cell: &'a Cell<usize>,
|
|
||||||
arity: usize)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
tm.mark_non_var(lvl, cell);
|
|
||||||
Target::to_structure(lvl, name.clone(), arity, cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn non_var_subterm<'a, Target>(tm: &mut TermMarker<'a>, cell: &'a Cell<usize>)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
tm.mark_non_var(Level::Deep, cell);
|
|
||||||
Target::clause_arg_to_instr(cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn var_term<'a, Target>(tm: &mut TermMarker<'a>,
|
|
||||||
lvl: Level,
|
|
||||||
cell: &'a Cell<Reg>,
|
|
||||||
var: &'a Var)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
if !tm.contains_var(var) {
|
|
||||||
let reg = tm.mark_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
Reg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_variable(arg, norm),
|
|
||||||
Reg::Norm(norm) =>
|
|
||||||
Target::subterm_to_variable(norm)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = tm.mark_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
Reg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_value(arg, norm),
|
|
||||||
Reg::Norm(norm) =>
|
|
||||||
Target::subterm_to_value(norm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<'a, Target>(tm: &mut TermMarker<'a>, subterm: &'a Term)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
|
|
||||||
non_var_subterm(tm, cell),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
var_term(tm, Level::Deep, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_target<'a, Target>(term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let iter = Target::iter(term);
|
|
||||||
let mut target = Vec::<Target>::new();
|
|
||||||
let mut marker = TermMarker::new(term);
|
|
||||||
|
|
||||||
for term in iter {
|
|
||||||
match term {
|
|
||||||
TermRef::Atom(lvl, term, atom) =>
|
|
||||||
target.push(to_structure(&mut marker, lvl, atom, term, 0)),
|
|
||||||
TermRef::Clause(lvl, term, atom, terms) => {
|
|
||||||
target.push(to_structure(&mut marker, lvl, atom, term, terms.len()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(subterm_to_instr(&mut marker, subterm.as_ref()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
|
|
||||||
target.push(var_term(&mut marker, lvl, cell, var)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_fact(term: &Term) -> CompiledFact {
|
|
||||||
let mut compiled_fact = compile_target(term);
|
|
||||||
|
|
||||||
compiled_fact.push(FactInstruction::Proceed);
|
|
||||||
compiled_fact
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_query<'a>(term: &'a Term) -> CompiledQuery {
|
|
||||||
let mut compiled_query = compile_target(term);
|
|
||||||
|
|
||||||
if let &Term::Clause(_, ref atom, ref terms) = term {
|
|
||||||
compiled_query.push(QueryInstruction::Call(atom.clone(), terms.len()));
|
|
||||||
}
|
|
||||||
|
|
||||||
compiled_query
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
use l1::ast::{Atom, Level, Reg, Term, TermRef, Var};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
enum IteratorState<'a> {
|
|
||||||
Atom(Level, &'a Cell<usize>, &'a Atom),
|
|
||||||
Clause(Level, usize, &'a Cell<usize>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
IsolatedAtom(&'a Cell<usize>, &'a Atom),
|
|
||||||
IsolatedVar(&'a Cell<Reg>, &'a Var),
|
|
||||||
RootClause(usize, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<Reg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IteratorState<'a> {
|
|
||||||
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a>
|
|
||||||
{
|
|
||||||
match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::Atom(lvl, cell, atom),
|
|
||||||
&Term::Clause(ref cell, ref atom, ref child_terms) =>
|
|
||||||
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::Var(lvl, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct QueryIterator<'a> {
|
|
||||||
state_stack: Vec<IteratorState<'a>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> QueryIterator<'a> {
|
|
||||||
fn push_clause(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
child_num: usize,
|
|
||||||
cell: &'a Cell<usize>,
|
|
||||||
name: &'a Atom,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::Clause(lvl,
|
|
||||||
child_num,
|
|
||||||
cell,
|
|
||||||
name,
|
|
||||||
child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_root_clause(&mut self,
|
|
||||||
child_num: usize,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_stack.push(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> QueryIterator<'a> {
|
|
||||||
let state = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::IsolatedAtom(cell, atom),
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
IteratorState::RootClause(0, terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::IsolatedVar(cell, var)
|
|
||||||
};
|
|
||||||
|
|
||||||
QueryIterator { state_stack: vec![state] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for QueryIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
|
||||||
match iter_state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
} else {
|
|
||||||
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
|
|
||||||
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(child_num, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
self.push_root_clause(child_num + 1, child_terms);
|
|
||||||
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FactIterator<'a> {
|
|
||||||
state_queue: VecDeque<IteratorState<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FactIterator<'a> {
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_queue.push_back(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> FactIterator<'a> {
|
|
||||||
let states = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
vec![IteratorState::IsolatedAtom(cell, atom)],
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
vec![IteratorState::RootClause(0, terms)],
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
vec![IteratorState::IsolatedVar(cell, var)]
|
|
||||||
};
|
|
||||||
|
|
||||||
FactIterator { state_queue: VecDeque::from(states) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for FactIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(state) = self.state_queue.pop_front() {
|
|
||||||
match state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Deep, child_term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(_, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Shallow, child_term);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn post_order_iter(&self) -> QueryIterator {
|
|
||||||
QueryIterator::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breadth_first_iter(&self) -> FactIterator {
|
|
||||||
FactIterator::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
use l1::ast::{Atom, Reg, Term, TopLevel, Var};
|
|
||||||
|
|
||||||
grammar;
|
|
||||||
|
|
||||||
pub TopLevel: TopLevel = {
|
|
||||||
"?-" <t:Term> "." => TopLevel::Query(t),
|
|
||||||
<t:Term> "." => TopLevel::Fact(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Atom : Atom = {
|
|
||||||
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Var : Var = {
|
|
||||||
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
BoxedTerm : Box<Term> = {
|
|
||||||
<t:Term> => Box::new(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Term : Term = {
|
|
||||||
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
|
||||||
let mut ts = ts;
|
|
||||||
ts.push(t);
|
|
||||||
Term::Clause(Cell::new(0), a, ts)
|
|
||||||
},
|
|
||||||
<Atom> => Term::Atom(Cell::new(0), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(Reg::Norm(0)), <>)
|
|
||||||
};
|
|
||||||
1595
src/l1/l1_parser.rs
1595
src/l1/l1_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,309 +0,0 @@
|
|||||||
use l1::ast::{Addr, Atom, CompiledFact, CompiledQuery,
|
|
||||||
FactInstruction, Heap, HeapCellValue, QueryInstruction,
|
|
||||||
Registers};
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
h : usize,
|
|
||||||
s : usize,
|
|
||||||
p : usize,
|
|
||||||
code : CompiledFact,
|
|
||||||
code_dir : HashMap<(Atom, usize), usize>,
|
|
||||||
fail : bool,
|
|
||||||
heap : Heap,
|
|
||||||
mode : MachineMode,
|
|
||||||
registers : Registers
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Machine {
|
|
||||||
Machine { h : 0,
|
|
||||||
s : 0,
|
|
||||||
p : 0,
|
|
||||||
code : Vec::new(),
|
|
||||||
code_dir : HashMap::new(),
|
|
||||||
fail : false,
|
|
||||||
heap : Vec::with_capacity(256),
|
|
||||||
mode : MachineMode::Write,
|
|
||||||
registers : vec![HeapCellValue::Ref(0); 32] }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_fact(&mut self, mut fact: CompiledFact, name: Atom, arity: usize)
|
|
||||||
{
|
|
||||||
let index = self.code.len();
|
|
||||||
|
|
||||||
self.code.append(&mut fact);
|
|
||||||
self.code_dir.insert((name, arity), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn failed(&self) -> bool {
|
|
||||||
self.fail
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&self, a: Addr) -> &HeapCellValue {
|
|
||||||
match a {
|
|
||||||
Addr::HeapCell(hc) => &self.heap[hc],
|
|
||||||
Addr::RegNum(reg) => &self.registers[reg]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deref(&self, a: Addr) -> Addr {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if let &HeapCellValue::Ref(value) = self.lookup(a) {
|
|
||||||
if let Addr::HeapCell(av) = a {
|
|
||||||
if value != av {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_unbound(hc: &HeapCellValue, index: usize) -> bool {
|
|
||||||
match hc {
|
|
||||||
&HeapCellValue::Ref(r) => r == index,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: try to compress this function.
|
|
||||||
fn bind(&mut self, a: Addr, val: usize) {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match a {
|
|
||||||
Addr::RegNum(reg) => {
|
|
||||||
if let HeapCellValue::Ref(hc) = self.registers[reg] {
|
|
||||||
a = Addr::HeapCell(hc);
|
|
||||||
} else if Machine::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = self.registers[reg].clone();
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[hc], hc) => {
|
|
||||||
self.heap[hc] = HeapCellValue::Ref(val);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[val], val) => {
|
|
||||||
self.heap[val] = HeapCellValue::Ref(hc);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unify(&mut self, a1: Addr, a2: Addr) {
|
|
||||||
let mut pdl = vec![a1, a2];
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
|
|
||||||
while !(pdl.is_empty() || self.fail) {
|
|
||||||
let d1 = self.deref(pdl.pop().unwrap());
|
|
||||||
let d2 = self.deref(pdl.pop().unwrap());
|
|
||||||
|
|
||||||
if d1 != d2 {
|
|
||||||
match (self.lookup(d1), self.lookup(d2)) {
|
|
||||||
(&HeapCellValue::Ref(hc), _) =>
|
|
||||||
self.bind(d2, hc),
|
|
||||||
(_, &HeapCellValue::Ref(hc)) =>
|
|
||||||
self.bind(d1, hc),
|
|
||||||
(&HeapCellValue::Str(a1), &HeapCellValue::Str(a2)) => {
|
|
||||||
let r1 = &self.heap[a1];
|
|
||||||
let r2 = &self.heap[a2];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
|
|
||||||
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
|
|
||||||
if n1 == n2 && *f1 == *f2 {
|
|
||||||
for i in 1 .. n1 {
|
|
||||||
pdl.push(Addr::HeapCell(a1 + i));
|
|
||||||
pdl.push(Addr::HeapCell(a2 + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fail = true;
|
|
||||||
},
|
|
||||||
_ => self.fail = true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_fact(&mut self) {
|
|
||||||
loop {
|
|
||||||
if let &FactInstruction::Proceed = &self.code[self.p] {
|
|
||||||
break;
|
|
||||||
} else if self.fail {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fact_instr = self.code[self.p].clone();
|
|
||||||
self.execute_fact_instr(fact_instr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_query(&mut self, query: &CompiledQuery) {
|
|
||||||
for instr in query {
|
|
||||||
self.execute_query_instr(instr);
|
|
||||||
|
|
||||||
if self.fail {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_query_instr<'a, 'b: 'a>(&'a mut self, instr: &'b QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::Call(ref name, arity) => {
|
|
||||||
// why is Option<&T> not Deref?!?!?
|
|
||||||
// is it because if the value is None, there's nothing to
|
|
||||||
// dereference?
|
|
||||||
let compiled_fact_index =
|
|
||||||
self.code_dir.get(&(name.clone(), arity))
|
|
||||||
.map(|index| *index);
|
|
||||||
|
|
||||||
match compiled_fact_index {
|
|
||||||
Some(compiled_fact_index) => {
|
|
||||||
self.p = compiled_fact_index;
|
|
||||||
self.execute_fact();
|
|
||||||
},
|
|
||||||
None => self.fail = true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutValue(arg, norm) =>
|
|
||||||
self.registers[arg] = self.registers[norm].clone(),
|
|
||||||
&QueryInstruction::PutVariable(arg, norm) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
|
|
||||||
self.registers[norm] = self.heap[self.h].clone();
|
|
||||||
self.registers[arg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetVariable(reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_fact_instr(&mut self, instr: FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
FactInstruction::Proceed => return,
|
|
||||||
FactInstruction::GetStructure(_, name, arity, reg) => {
|
|
||||||
let addr = self.deref(Addr::RegNum(reg));
|
|
||||||
|
|
||||||
match self.lookup(addr) {
|
|
||||||
&HeapCellValue::Str(a) => {
|
|
||||||
let result = &self.heap[a];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(named_arity, ref named_str) = result {
|
|
||||||
if arity == named_arity && *name == *named_str {
|
|
||||||
self.s = a + 1;
|
|
||||||
self.mode = MachineMode::Read;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&HeapCellValue::Ref(r) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name));
|
|
||||||
|
|
||||||
let h = self.h;
|
|
||||||
|
|
||||||
self.bind(Addr::HeapCell(r), h);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
FactInstruction::GetVariable(arg, norm) =>
|
|
||||||
self.registers[norm] = self.registers[arg].clone(),
|
|
||||||
FactInstruction::GetValue(arg, norm) =>
|
|
||||||
self.unify(Addr::RegNum(norm), Addr::RegNum(arg)),
|
|
||||||
FactInstruction::UnifyVariable(reg) => {
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => self.registers[reg] = self.heap[self.s].clone(),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
},
|
|
||||||
FactInstruction::UnifyValue(reg) => {
|
|
||||||
let s = self.s;
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => self.unify(Addr::RegNum(reg), Addr::HeapCell(s)),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.p += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_machine_state(&mut self) {
|
|
||||||
self.h = 0;
|
|
||||||
self.s = 0;
|
|
||||||
self.p = 0;
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
self.heap = Vec::with_capacity(256);
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
self.registers = vec![HeapCellValue::Ref(0); 32];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
pub mod ast;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod l1_parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod machine;
|
|
||||||
253
src/l2/ast.rs
253
src/l2/ast.rs
@@ -1,253 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::fmt;
|
|
||||||
use std::ops::{Add, AddAssign};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub type Var = String;
|
|
||||||
|
|
||||||
pub type Atom = String;
|
|
||||||
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Term),
|
|
||||||
Rule(Rule),
|
|
||||||
Query(Term)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Level {
|
|
||||||
Shallow, Deep
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Level {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&Level::Shallow => write!(f, "A"),
|
|
||||||
&Level::Deep => write!(f, "X")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum RegType {
|
|
||||||
Perm(usize),
|
|
||||||
Temp(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegType {
|
|
||||||
pub fn reg_num(self) -> usize {
|
|
||||||
match self {
|
|
||||||
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_perm(self) -> bool {
|
|
||||||
match self {
|
|
||||||
RegType::Perm(_) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for VarReg {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
|
|
||||||
&VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
|
|
||||||
&VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
|
|
||||||
write!(f, "Y{} A{}", reg, arg),
|
|
||||||
&VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
|
|
||||||
write!(f, "X{} A{}", reg, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RegType> for Addr {
|
|
||||||
fn from(reg: RegType) -> Addr {
|
|
||||||
match reg {
|
|
||||||
RegType::Perm(reg) => Addr::StackCell(reg),
|
|
||||||
RegType::Temp(reg) => Addr::RegNum(reg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for RegType {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&RegType::Perm(val) => write!(f, "Y{}", val),
|
|
||||||
&RegType::Temp(val) => write!(f, "X{}", val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum VarReg {
|
|
||||||
ArgAndNorm(RegType, usize),
|
|
||||||
Norm(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VarReg {
|
|
||||||
pub fn norm(self) -> RegType {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_register(self) -> usize {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(_, root) => root,
|
|
||||||
VarReg::Norm(root) => root.reg_num()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<RegType>, Atom),
|
|
||||||
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<VarReg>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Rule {
|
|
||||||
pub head: (Term, Term),
|
|
||||||
pub clauses: Vec<Term>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TermRef<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Level, Atom, usize, RegType),
|
|
||||||
GetValue(RegType, usize),
|
|
||||||
GetVariable(RegType, usize),
|
|
||||||
UnifyVariable(RegType),
|
|
||||||
UnifyValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
PutStructure(Level, Atom, usize, RegType),
|
|
||||||
PutValue(RegType, usize),
|
|
||||||
PutVariable(RegType, usize),
|
|
||||||
SetVariable(RegType),
|
|
||||||
SetValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ControlInstruction {
|
|
||||||
Allocate(usize),
|
|
||||||
Call(Atom, usize),
|
|
||||||
Deallocate,
|
|
||||||
Proceed
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
pub enum Line {
|
|
||||||
Control(ControlInstruction),
|
|
||||||
Fact(CompiledFact),
|
|
||||||
Query(CompiledQuery)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Code = Vec<Line>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
RegNum(usize),
|
|
||||||
StackCell(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
pub enum HeapCellValue {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(usize),
|
|
||||||
Str(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HeapCellValue {
|
|
||||||
pub fn as_ref(&self, focus: usize) -> HeapCellRef {
|
|
||||||
match self {
|
|
||||||
&HeapCellValue::Ref(r) => HeapCellRef::Ref(r),
|
|
||||||
&HeapCellValue::Str(s) => HeapCellRef::Str(s),
|
|
||||||
&HeapCellValue::NamedStr(_, _) => HeapCellRef::Str(focus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum HeapCellRef {
|
|
||||||
Ref(usize),
|
|
||||||
Str(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HeapCellRef {
|
|
||||||
pub fn heap_offset(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&HeapCellRef::Ref(r) | &HeapCellRef::Str(r) => r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<HeapCellRef> for HeapCellValue {
|
|
||||||
fn from(hcr: HeapCellRef) -> HeapCellValue {
|
|
||||||
match hcr {
|
|
||||||
HeapCellRef::Ref(r) => HeapCellValue::Ref(r),
|
|
||||||
HeapCellRef::Str(s) => HeapCellValue::Str(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum CodePtr {
|
|
||||||
DirEntry(usize),
|
|
||||||
TopLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<usize> for CodePtr {
|
|
||||||
type Output = CodePtr;
|
|
||||||
fn add(self, rhs: usize) -> Self::Output {
|
|
||||||
match self {
|
|
||||||
CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
|
|
||||||
CodePtr::TopLevel => CodePtr::TopLevel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddAssign<usize> for CodePtr {
|
|
||||||
fn add_assign(&mut self, rhs: usize) {
|
|
||||||
match self {
|
|
||||||
&mut CodePtr::DirEntry(ref mut p) => *p += rhs,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Heap = Vec<HeapCellValue>;
|
|
||||||
|
|
||||||
pub type Registers = Vec<HeapCellRef>;
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn subterms(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Clause(_, _, ref terms) => terms.len(),
|
|
||||||
_ => 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &Atom {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, ref atom)
|
|
||||||
| &Term::Var(_, ref atom)
|
|
||||||
| &Term::Clause(_, ref atom, _) => atom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
|
|
||||||
&Term::Clause(_, _, ref child_terms) => child_terms.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,469 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
use l2::iterators::{FactIterator, QueryIterator};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::cmp::max;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, {}", name, arity, r),
|
|
||||||
&FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
|
|
||||||
&FactInstruction::GetValue(ref x, ref a) =>
|
|
||||||
write!(f, "get_value {}, A{}", x, a),
|
|
||||||
&FactInstruction::GetVariable(ref x, ref a) =>
|
|
||||||
write!(f, "get_variable {}, A{}", x, a),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable {}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value {}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
|
|
||||||
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, {}", name, arity, r),
|
|
||||||
&QueryInstruction::PutValue(ref x, ref a) =>
|
|
||||||
write!(f, "put_value {}, A{}", x, a),
|
|
||||||
&QueryInstruction::PutVariable(ref x, ref a) =>
|
|
||||||
write!(f, "put_variable {}, A{}", x, a),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable {}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value {}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ControlInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&ControlInstruction::Allocate(num_cells) =>
|
|
||||||
write!(f, "allocate {}", num_cells),
|
|
||||||
&ControlInstruction::Call(ref name, ref arity) =>
|
|
||||||
write!(f, "call {}/{}", name, arity),
|
|
||||||
&ControlInstruction::Deallocate =>
|
|
||||||
write!(f, "deallocate"),
|
|
||||||
&ControlInstruction::Proceed =>
|
|
||||||
write!(f, "proceed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=TermRef<'a>>;
|
|
||||||
|
|
||||||
fn iter(&'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(Level, Atom, usize, RegType) -> Self;
|
|
||||||
|
|
||||||
fn argument_to_variable(RegType, usize) -> Self;
|
|
||||||
fn argument_to_value(RegType, usize) -> Self;
|
|
||||||
fn subterm_to_variable(RegType) -> Self;
|
|
||||||
fn subterm_to_value(RegType) -> Self;
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(RegType) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
|
||||||
type Iterator = FactIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.breadth_first_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
|
||||||
FactInstruction::GetStructure(lvl, atom, arity, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
|
||||||
FactInstruction::GetVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
|
||||||
FactInstruction::GetValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|
||||||
type Iterator = QueryIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.post_order_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
|
||||||
QueryInstruction::PutStructure(lvl, atom, arity, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TermMarker<'a> {
|
|
||||||
bindings: HashMap<&'a Var, VarReg>,
|
|
||||||
arg_c: usize,
|
|
||||||
perm_c: usize,
|
|
||||||
temp_c: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TermMarker<'a> {
|
|
||||||
fn new() -> TermMarker<'a> {
|
|
||||||
TermMarker { bindings: HashMap::new(),
|
|
||||||
arg_c: 1,
|
|
||||||
perm_c: 1,
|
|
||||||
temp_c: 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_var(&self, var: &'a Var) -> bool {
|
|
||||||
self.bindings.contains_key(var)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, var: &'a Var) -> VarReg {
|
|
||||||
*self.bindings.get(var).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(&mut self, var: &'a Var, r: VarReg) {
|
|
||||||
self.bindings.insert(var, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
|
|
||||||
let reg_type = cell.get();
|
|
||||||
|
|
||||||
if reg_type.reg_num() == 0 {
|
|
||||||
match lvl {
|
|
||||||
Level::Deep if reg_type.is_perm() => {
|
|
||||||
let perm = self.perm_c;
|
|
||||||
self.perm_c += 1;
|
|
||||||
cell.set(RegType::Perm(perm));
|
|
||||||
},
|
|
||||||
Level::Deep => {
|
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
|
||||||
cell.set(RegType::Temp(temp));
|
|
||||||
},
|
|
||||||
Level::Shallow if reg_type.is_perm() => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Perm(arg));
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Temp(arg));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
|
|
||||||
{
|
|
||||||
let reg = self.get(var);
|
|
||||||
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(reg.norm()),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c);
|
|
||||||
|
|
||||||
self.arg_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
|
|
||||||
{
|
|
||||||
let inner_reg = if reg.is_perm() {
|
|
||||||
let perm = self.perm_c;
|
|
||||||
self.perm_c += 1;
|
|
||||||
RegType::Perm(perm)
|
|
||||||
} else {
|
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
|
||||||
RegType::Temp(temp)
|
|
||||||
};
|
|
||||||
|
|
||||||
let reg = match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(inner_reg),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
|
|
||||||
self.arg_c += 1;
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.insert(var, reg);
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance_at_header(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = max(term.subterms(), self.temp_c) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = term.subterms() + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum TermStatus {
|
|
||||||
New, Old, Recurrent
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGenerator<'a> {
|
|
||||||
marker: TermMarker<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
type VariableFixture<'a> = (TermStatus, Vec<&'a Cell<VarReg>>);
|
|
||||||
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
|
|
||||||
|
|
||||||
impl<'a> CodeGenerator<'a> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CodeGenerator { marker: TermMarker::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vars(&self) -> &HashMap<&Var, VarReg> {
|
|
||||||
&self.marker.bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
name: &'a Atom,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
arity: usize)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(lvl, cell);
|
|
||||||
Target::to_structure(lvl, name.clone(), arity, cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn var_term<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
cell: &'a Cell<VarReg>,
|
|
||||||
var: &'a Var)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
if !self.marker.contains_var(var) {
|
|
||||||
let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_variable(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_variable(norm)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = self.marker.mark_old_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_value(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_value(norm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(Level::Deep, cell);
|
|
||||||
Target::clause_arg_to_instr(cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
|
|
||||||
self.non_var_subterm(cell),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
self.var_term(Level::Deep, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let iter = Target::iter(term);
|
|
||||||
let mut target = Vec::new();
|
|
||||||
|
|
||||||
for term in iter {
|
|
||||||
match term {
|
|
||||||
TermRef::Atom(lvl, term, atom) =>
|
|
||||||
target.push(self.to_structure(lvl, atom, term, 0)),
|
|
||||||
TermRef::Clause(lvl, term, atom, terms) => {
|
|
||||||
target.push(self.to_structure(lvl, atom, term, terms.len()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(self.subterm_to_instr(subterm.as_ref()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
|
|
||||||
target.push(self.var_term(lvl, cell, var)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
|
|
||||||
where Iter : Iterator<Item=TermRef<'a>>
|
|
||||||
{
|
|
||||||
for term in iter {
|
|
||||||
if let TermRef::Var(_, reg_cell, var) = term {
|
|
||||||
let mut status = vs.entry(var)
|
|
||||||
.or_insert((TermStatus::New, Vec::new()));
|
|
||||||
|
|
||||||
status.1.push(reg_cell);
|
|
||||||
|
|
||||||
match status.0 {
|
|
||||||
TermStatus::Old => status.0 = TermStatus::Recurrent,
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
|
|
||||||
match *term_status {
|
|
||||||
TermStatus::New => *term_status = TermStatus::Old,
|
|
||||||
TermStatus::Recurrent => {
|
|
||||||
for cell_reg in cb.drain(0..) {
|
|
||||||
cell_reg.set(VarReg::Norm(RegType::Perm(0)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut vfs = HashMap::new();
|
|
||||||
|
|
||||||
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
|
||||||
|
|
||||||
Self::mark_vars_in_term(iter, &mut vfs);
|
|
||||||
|
|
||||||
for term in clauses {
|
|
||||||
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfs
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
|
|
||||||
match term {
|
|
||||||
&Term::Atom(_, ref atom) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), 0);
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
&Term::Clause(_, ref atom, ref terms) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), terms.len());
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
|
|
||||||
let vfs = Self::mark_perm_vars(&rule);
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut perm_vars = 0;
|
|
||||||
|
|
||||||
for &(term_status, _) in vfs.values() {
|
|
||||||
if let TermStatus::Recurrent = term_status {
|
|
||||||
perm_vars += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut body = Vec::new();
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
|
|
||||||
|
|
||||||
self.marker.advance(p0);
|
|
||||||
body.push(Line::Fact(self.compile_target(p0)));
|
|
||||||
|
|
||||||
self.marker.advance_at_header(p1);
|
|
||||||
body.push(Line::Query(self.compile_target(p1)));
|
|
||||||
Self::add_conditional_call(&mut body, p1);
|
|
||||||
|
|
||||||
body = clauses.iter()
|
|
||||||
.map(|ref term| self.compile_query(term))
|
|
||||||
.fold(body, |mut body, ref mut cqs| {
|
|
||||||
body.append(cqs);
|
|
||||||
body
|
|
||||||
});
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Deallocate));
|
|
||||||
|
|
||||||
body
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
|
|
||||||
let proceed = Line::Control(ControlInstruction::Proceed);
|
|
||||||
|
|
||||||
compiled_fact.push(proceed);
|
|
||||||
compiled_fact
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_query(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
|
|
||||||
Self::add_conditional_call(&mut compiled_query, term);
|
|
||||||
|
|
||||||
compiled_query
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum HeapCellView<'a> {
|
|
||||||
Str(usize, &'a Atom),
|
|
||||||
Var(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HeapCellViewer<'a> {
|
|
||||||
heap: &'a Heap,
|
|
||||||
state_stack: Vec<(usize, &'a HeapCellValue)>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> HeapCellViewer<'a> {
|
|
||||||
pub fn new(heap: &'a Heap, focus: usize) -> Self {
|
|
||||||
HeapCellViewer {
|
|
||||||
heap: heap,
|
|
||||||
state_stack: vec![(focus, &heap[focus])]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn follow(&self, value: &'a HeapCellValue) -> &'a HeapCellValue {
|
|
||||||
match value {
|
|
||||||
&HeapCellValue::NamedStr(_, _) => value,
|
|
||||||
&HeapCellValue::Ref(cell_num) | &HeapCellValue::Str(cell_num) =>
|
|
||||||
&self.heap[cell_num],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for HeapCellViewer<'a> {
|
|
||||||
type Item = HeapCellView<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(hcv) = self.state_stack.pop() {
|
|
||||||
match hcv {
|
|
||||||
(focus, &HeapCellValue::NamedStr(arity, ref name)) => {
|
|
||||||
for i in (1 .. arity + 1).rev() {
|
|
||||||
self.state_stack.push((focus + i, &self.heap[focus + i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(HeapCellView::Str(arity, name));
|
|
||||||
},
|
|
||||||
(_, &HeapCellValue::Ref(cell_num)) => {
|
|
||||||
let new_hcv = self.follow(hcv.1);
|
|
||||||
|
|
||||||
if hcv.1 == new_hcv {
|
|
||||||
return Some(HeapCellView::Var(cell_num));
|
|
||||||
} else {
|
|
||||||
self.state_stack.push((cell_num, new_hcv));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(_, &HeapCellValue::Str(cell_num)) => {
|
|
||||||
let new_hcv = self.follow(hcv.1);
|
|
||||||
self.state_stack.push((cell_num, new_hcv));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
enum IteratorState<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, usize, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
IsolatedAtom(&'a Cell<RegType>, &'a Atom),
|
|
||||||
IsolatedVar(&'a Cell<VarReg>, &'a Var),
|
|
||||||
RootClause(usize, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IteratorState<'a> {
|
|
||||||
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a>
|
|
||||||
{
|
|
||||||
match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::Atom(lvl, cell, atom),
|
|
||||||
&Term::Clause(ref cell, ref atom, ref child_terms) =>
|
|
||||||
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::Var(lvl, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct QueryIterator<'a> {
|
|
||||||
state_stack: Vec<IteratorState<'a>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> QueryIterator<'a> {
|
|
||||||
fn push_clause(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
child_num: usize,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
name: &'a Atom,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::Clause(lvl,
|
|
||||||
child_num,
|
|
||||||
cell,
|
|
||||||
name,
|
|
||||||
child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_root_clause(&mut self,
|
|
||||||
child_num: usize,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_stack.push(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> QueryIterator<'a> {
|
|
||||||
let state = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::IsolatedAtom(cell, atom),
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
IteratorState::RootClause(0, terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::IsolatedVar(cell, var)
|
|
||||||
};
|
|
||||||
|
|
||||||
QueryIterator { state_stack: vec![state] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for QueryIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
|
||||||
match iter_state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
} else {
|
|
||||||
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
|
|
||||||
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(child_num, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
self.push_root_clause(child_num + 1, child_terms);
|
|
||||||
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FactIterator<'a> {
|
|
||||||
state_queue: VecDeque<IteratorState<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FactIterator<'a> {
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_queue.push_back(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> FactIterator<'a> {
|
|
||||||
let states = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
vec![IteratorState::IsolatedAtom(cell, atom)],
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
vec![IteratorState::RootClause(0, terms)],
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
vec![IteratorState::IsolatedVar(cell, var)]
|
|
||||||
};
|
|
||||||
|
|
||||||
FactIterator { state_queue: VecDeque::from(states) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for FactIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(state) = self.state_queue.pop_front() {
|
|
||||||
match state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Deep, child_term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(_, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Shallow, child_term);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn post_order_iter(&self) -> QueryIterator {
|
|
||||||
QueryIterator::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breadth_first_iter(&self) -> FactIterator {
|
|
||||||
FactIterator::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
grammar;
|
|
||||||
|
|
||||||
pub TopLevel: TopLevel = {
|
|
||||||
"?-" <t:Term> "." => TopLevel::Query(t),
|
|
||||||
<r:Rule> "." => TopLevel::Rule(r),
|
|
||||||
<t:Term> "." => TopLevel::Fact(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Atom : Atom = {
|
|
||||||
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
BoxedTerm : Box<Term> = {
|
|
||||||
<t:Term> => Box::new(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Clause : Term = {
|
|
||||||
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
|
||||||
let mut ts = ts;
|
|
||||||
ts.push(t);
|
|
||||||
Term::Clause(Cell::new(RegType::Temp(0)), a, ts)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Rule : Rule = {
|
|
||||||
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (c, h), clauses: cs },
|
|
||||||
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (Term::Atom(Cell::new(RegType::Temp(0)), a), h),
|
|
||||||
clauses: cs }
|
|
||||||
};
|
|
||||||
|
|
||||||
Term : Term = {
|
|
||||||
<Clause> => <>,
|
|
||||||
<Atom> => Term::Atom(Cell::new(RegType::Temp(0)), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), <>),
|
|
||||||
};
|
|
||||||
|
|
||||||
Var : Var = {
|
|
||||||
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
1883
src/l2/l2_parser.rs
1883
src/l2/l2_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,456 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
use l2::codegen::*;
|
|
||||||
use l2::heapview::*;
|
|
||||||
use l2::stack::*;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MachineState {
|
|
||||||
h: usize,
|
|
||||||
s: usize,
|
|
||||||
p: CodePtr,
|
|
||||||
cp: CodePtr,
|
|
||||||
fail: bool,
|
|
||||||
heap: Heap,
|
|
||||||
mode: MachineMode,
|
|
||||||
stack: Stack,
|
|
||||||
registers: Registers
|
|
||||||
}
|
|
||||||
|
|
||||||
type CodeDir = HashMap<(Atom, usize), usize>;
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
ms: MachineState,
|
|
||||||
code: Code,
|
|
||||||
code_dir: CodeDir
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Machine {
|
|
||||||
ms: MachineState::new(),
|
|
||||||
code: Vec::new(),
|
|
||||||
code_dir: HashMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn failed(&self) -> bool {
|
|
||||||
self.ms.fail
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = fact.name().clone();
|
|
||||||
let arity = fact.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_rule(&mut self, rule: &Rule, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = rule.head.0.name().clone();
|
|
||||||
let arity = rule.head.0.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_instr(&mut self, instr: &Line) -> bool {
|
|
||||||
let mut instr = instr;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match instr {
|
|
||||||
&Line::Fact(ref fact) => {
|
|
||||||
for fact_instr in fact {
|
|
||||||
self.ms.execute_fact_instr(&fact_instr);
|
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Query(ref query) => {
|
|
||||||
for query_instr in query {
|
|
||||||
self.ms.execute_query_instr(&query_instr);
|
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Control(ref control_instr) =>
|
|
||||||
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.failed() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.ms.p {
|
|
||||||
CodePtr::DirEntry(p) if p < self.code.len() =>
|
|
||||||
instr = &self.code[p],
|
|
||||||
_ => break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn heap_view(&self, var_dir: HashMap<&Var, HeapCellRef>) -> String {
|
|
||||||
let mut result = String::new();
|
|
||||||
|
|
||||||
for (var, hcr) in var_dir {
|
|
||||||
let mut arities = Vec::new();
|
|
||||||
let viewer = HeapCellViewer::new(&self.ms.heap, hcr.heap_offset());
|
|
||||||
|
|
||||||
if result != "" {
|
|
||||||
result += "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
result += var.as_str();
|
|
||||||
result += " = ";
|
|
||||||
|
|
||||||
for view in viewer {
|
|
||||||
match arities.pop() {
|
|
||||||
Some(n) => arities.push(n-1),
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(arities.is_empty() || result.ends_with("(")) {
|
|
||||||
result += ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
match view {
|
|
||||||
HeapCellView::Str(arity, ref name) => {
|
|
||||||
result += name.as_str();
|
|
||||||
|
|
||||||
if arity > 0 {
|
|
||||||
arities.push(arity);
|
|
||||||
result += "(";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
HeapCellView::Var(cell_num) => {
|
|
||||||
result += "_";
|
|
||||||
result += cell_num.to_string().as_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(&0) = arities.last() {
|
|
||||||
result += ")";
|
|
||||||
arities.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_query(&mut self, code: Code, cg: &CodeGenerator) -> Option<String>
|
|
||||||
{
|
|
||||||
let mut succeeded = true;
|
|
||||||
|
|
||||||
for instr in code.iter().take(1) {
|
|
||||||
succeeded = self.execute_instr(&instr);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut heap_locs = HashMap::new();
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
for (var, vr) in cg.vars() {
|
|
||||||
let hcr = self.ms.registers[vr.root_register()];
|
|
||||||
heap_locs.insert(*var, hcr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for instr in code.iter().skip(1) {
|
|
||||||
succeeded = self.execute_instr(&instr);
|
|
||||||
if !succeeded {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
Some(self.heap_view(heap_locs))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.ms.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MachineState {
|
|
||||||
fn new() -> MachineState {
|
|
||||||
MachineState { h: 0,
|
|
||||||
s: 0,
|
|
||||||
p: CodePtr::TopLevel,
|
|
||||||
cp: CodePtr::TopLevel,
|
|
||||||
fail: false,
|
|
||||||
heap: Vec::with_capacity(256),
|
|
||||||
mode: MachineMode::Write,
|
|
||||||
stack: Stack::new(),
|
|
||||||
registers: vec![HeapCellRef::Ref(0); 32] }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_mut(&mut self, r: RegType) -> &mut HeapCellRef {
|
|
||||||
match r {
|
|
||||||
RegType::Temp(r) => &mut self.registers[r],
|
|
||||||
RegType::Perm(r) => &mut self.stack[r]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&self, a: Addr) -> HeapCellRef {
|
|
||||||
match a {
|
|
||||||
Addr::HeapCell(r) => self.heap[r].as_ref(r),
|
|
||||||
Addr::RegNum(r) => self.registers[r],
|
|
||||||
Addr::StackCell(s) => self.stack[s]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deref(&self, a: Addr) -> Addr {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if let HeapCellRef::Ref(value) = self.lookup(a) {
|
|
||||||
if let Addr::HeapCell(av) = a {
|
|
||||||
if value != av {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_unbound(hc: &HeapCellValue, index: usize) -> bool {
|
|
||||||
match hc {
|
|
||||||
&HeapCellValue::Ref(r) => r == index,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bind(&mut self, a: Addr, val: usize) {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match a {
|
|
||||||
addr @ Addr::RegNum(_) | addr @ Addr::StackCell(_) => {
|
|
||||||
if let HeapCellRef::Ref(hc) = self.lookup(addr) {
|
|
||||||
a = Addr::HeapCell(hc);
|
|
||||||
} else if Self::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = HeapCellValue::from(self.lookup(addr));
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) => {
|
|
||||||
if Self::is_unbound(&self.heap[hc], hc) {
|
|
||||||
self.heap[hc] = HeapCellValue::Ref(val);
|
|
||||||
break;
|
|
||||||
} else if Self::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = HeapCellValue::Ref(hc);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unify(&mut self, a1: Addr, a2: Addr) {
|
|
||||||
let mut pdl = vec![a1, a2];
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
|
|
||||||
while !(pdl.is_empty() || self.fail) {
|
|
||||||
let d1 = self.deref(pdl.pop().unwrap());
|
|
||||||
let d2 = self.deref(pdl.pop().unwrap());
|
|
||||||
|
|
||||||
if d1 != d2 {
|
|
||||||
match (self.lookup(d1), self.lookup(d2)) {
|
|
||||||
(HeapCellRef::Ref(hc), _) =>
|
|
||||||
self.bind(d2, hc),
|
|
||||||
(_, HeapCellRef::Ref(hc)) =>
|
|
||||||
self.bind(d1, hc),
|
|
||||||
(HeapCellRef::Str(a1), HeapCellRef::Str(a2)) => {
|
|
||||||
let r1 = &self.heap[a1];
|
|
||||||
let r2 = &self.heap[a2];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
|
|
||||||
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
|
|
||||||
if n1 == n2 && *f1 == *f2 {
|
|
||||||
for i in 1 .. n1 + 1 {
|
|
||||||
pdl.push(Addr::HeapCell(a1 + i));
|
|
||||||
pdl.push(Addr::HeapCell(a2 + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fail = true;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
*self.register_mut(reg) = HeapCellRef::Str(self.h + 1);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutValue(norm, arg) =>
|
|
||||||
self.registers[arg] = match norm {
|
|
||||||
RegType::Temp(reg) => self.registers[reg],
|
|
||||||
RegType::Perm(reg) => self.stack[reg]
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutVariable(norm, arg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
|
|
||||||
*self.register_mut(norm) = HeapCellRef::Ref(self.h);
|
|
||||||
self.registers[arg] = HeapCellRef::Ref(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetVariable(reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
*self.register_mut(reg) = HeapCellRef::Ref(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
let heap_val = self.lookup(Addr::from(reg));
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
|
|
||||||
let addr = self.deref(Addr::from(reg));
|
|
||||||
|
|
||||||
match self.lookup(addr) {
|
|
||||||
HeapCellRef::Str(a) => {
|
|
||||||
let result = &self.heap[a];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(narity, ref str) = result {
|
|
||||||
if narity == arity && *name == *str {
|
|
||||||
self.s = a + 1;
|
|
||||||
self.mode = MachineMode::Read;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
HeapCellRef::Ref(_) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
let h = self.h;
|
|
||||||
|
|
||||||
self.bind(addr, h);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&FactInstruction::GetVariable(norm, arg) =>
|
|
||||||
*self.register_mut(norm) = self.registers[arg],
|
|
||||||
&FactInstruction::GetValue(norm, arg) =>
|
|
||||||
self.unify(Addr::from(norm), Addr::RegNum(arg)),
|
|
||||||
&FactInstruction::UnifyVariable(reg) => {
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read =>
|
|
||||||
*self.register_mut(reg) = self.heap[self.s].as_ref(self.s),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
*self.register_mut(reg) = HeapCellRef::Ref(self.h);
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyValue(reg) => {
|
|
||||||
let s = self.s;
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read =>
|
|
||||||
self.unify(Addr::from(reg), Addr::HeapCell(s)),
|
|
||||||
MachineMode::Write => {
|
|
||||||
let heap_val = self.lookup(Addr::from(reg));
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
|
||||||
{
|
|
||||||
match instr {
|
|
||||||
&ControlInstruction::Allocate(num_cells) => {
|
|
||||||
self.stack.push(self.cp, num_cells);
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ControlInstruction::Call(ref name, arity) => {
|
|
||||||
let compiled_tl_index = code_dir.get(&(name.clone(), arity))
|
|
||||||
.map(|index| *index);
|
|
||||||
|
|
||||||
match compiled_tl_index {
|
|
||||||
Some(compiled_tl_index) => {
|
|
||||||
self.cp = self.p + 1;
|
|
||||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
|
||||||
},
|
|
||||||
None => self.fail = true
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&ControlInstruction::Deallocate => {
|
|
||||||
self.p = self.stack.get_cp();
|
|
||||||
self.stack.pop();
|
|
||||||
},
|
|
||||||
&ControlInstruction::Proceed =>
|
|
||||||
self.p = self.cp,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.h = 0;
|
|
||||||
self.s = 0;
|
|
||||||
self.p = CodePtr::TopLevel;
|
|
||||||
self.cp = CodePtr::TopLevel;
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
self.heap.clear();
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
self.stack = Stack::new();
|
|
||||||
self.registers = vec![HeapCellRef::Ref(0); 32];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
pub mod ast;
|
|
||||||
pub mod heapview;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod l2_parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod machine;
|
|
||||||
pub mod stack;
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
struct Frame {
|
|
||||||
cp: CodePtr,
|
|
||||||
perms: Vec<HeapCellRef>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(cp: CodePtr, n: usize) -> Self {
|
|
||||||
Frame {
|
|
||||||
cp: cp,
|
|
||||||
perms: vec![HeapCellRef::Ref(0); n]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_pv(&self, i: usize) -> &HeapCellRef {
|
|
||||||
self.perms.index(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_pv_mut(&mut self, i: usize) -> &mut HeapCellRef {
|
|
||||||
self.perms.index_mut(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Stack(Vec<Frame>);
|
|
||||||
|
|
||||||
impl Stack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Stack(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, cp: CodePtr, n: usize) {
|
|
||||||
self.0.push(Frame::new(cp, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_cp(&self) -> CodePtr {
|
|
||||||
self.0.last().unwrap().cp
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self) {
|
|
||||||
self.0.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Stack {
|
|
||||||
type Output = HeapCellRef;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.0.last().unwrap().read_pv(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Stack {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.0.last_mut().unwrap().read_pv_mut(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub struct Frame {
|
|
||||||
pub global_index: usize,
|
|
||||||
pub e: usize,
|
|
||||||
pub cp: CodePtr,
|
|
||||||
perms: Vec<Addr>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(global_index: usize, e: usize, cp: CodePtr, n: usize) -> Self {
|
|
||||||
Frame {
|
|
||||||
global_index: global_index,
|
|
||||||
e: e,
|
|
||||||
cp: cp,
|
|
||||||
perms: vec![Addr::HeapCell(0); n]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AndStack(Vec<Frame>);
|
|
||||||
|
|
||||||
impl AndStack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
AndStack(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) {
|
|
||||||
self.0.push(Frame::new(global_index, e, cp, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn top(&self) -> Option<&Frame> {
|
|
||||||
self.0.last()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.0.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
// drop the last n frames.
|
|
||||||
pub fn drop_frames(&mut self, n: usize) {
|
|
||||||
let len = self.0.len();
|
|
||||||
self.0.truncate(len - n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for AndStack {
|
|
||||||
type Output = Frame;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.0.index(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for AndStack {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.0.index_mut(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Frame {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.perms.index(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Frame {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.perms.index_mut(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
303
src/l3/ast.rs
303
src/l3/ast.rs
@@ -1,303 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ops::{Add, AddAssign};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub type Var = String;
|
|
||||||
|
|
||||||
pub type Atom = String;
|
|
||||||
|
|
||||||
pub enum PredicateClause {
|
|
||||||
Fact(Term),
|
|
||||||
Rule(Rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PredicateClause {
|
|
||||||
pub fn name(&self) -> &Atom {
|
|
||||||
match self {
|
|
||||||
&PredicateClause::Fact(ref t) => t.name(),
|
|
||||||
&PredicateClause::Rule(ref rule) => rule.head.0.name()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&PredicateClause::Fact(ref t) => t.arity(),
|
|
||||||
&PredicateClause::Rule(ref rule) => rule.head.0.arity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Term),
|
|
||||||
Predicate(Vec<PredicateClause>),
|
|
||||||
Query(Term),
|
|
||||||
Rule(Rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Level {
|
|
||||||
Deep, Shallow
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum RegType {
|
|
||||||
Perm(usize),
|
|
||||||
Temp(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegType {
|
|
||||||
pub fn reg_num(self) -> usize {
|
|
||||||
match self {
|
|
||||||
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_perm(self) -> bool {
|
|
||||||
match self {
|
|
||||||
RegType::Perm(_) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum VarReg {
|
|
||||||
ArgAndNorm(RegType, usize),
|
|
||||||
Norm(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VarReg {
|
|
||||||
pub fn norm(self) -> RegType {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_register(self) -> usize {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(_, root) => root,
|
|
||||||
VarReg::Norm(root) => root.reg_num()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<RegType>, Atom),
|
|
||||||
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<VarReg>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Rule {
|
|
||||||
pub head: (Term, Term),
|
|
||||||
pub clauses: Vec<Term>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TermRef<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Level, Atom, usize, RegType),
|
|
||||||
GetValue(RegType, usize),
|
|
||||||
GetVariable(RegType, usize),
|
|
||||||
UnifyVariable(RegType),
|
|
||||||
UnifyValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
PutStructure(Level, Atom, usize, RegType),
|
|
||||||
PutValue(RegType, usize),
|
|
||||||
PutVariable(RegType, usize),
|
|
||||||
SetVariable(RegType),
|
|
||||||
SetValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ChoiceInstruction {
|
|
||||||
RetryMeElse(usize),
|
|
||||||
TrustMe,
|
|
||||||
TryMeElse(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ControlInstruction {
|
|
||||||
Allocate(usize),
|
|
||||||
Call(Atom, usize),
|
|
||||||
Deallocate,
|
|
||||||
Proceed
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
pub enum Line {
|
|
||||||
Choice(ChoiceInstruction),
|
|
||||||
Control(ControlInstruction),
|
|
||||||
Fact(CompiledFact),
|
|
||||||
Query(CompiledQuery)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum LineOrCodeOffset<'a> {
|
|
||||||
Instruction(&'a Line),
|
|
||||||
Offset(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a Line> for LineOrCodeOffset<'a> {
|
|
||||||
fn from(line: &'a Line) -> Self {
|
|
||||||
LineOrCodeOffset::Instruction(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Code = Vec<Line>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
StackCell(usize, usize),
|
|
||||||
Str(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Addr {
|
|
||||||
pub fn is_ref(self) -> bool {
|
|
||||||
match self {
|
|
||||||
Addr::HeapCell(_) | Addr::StackCell(_, _) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ref(self) -> Option<Ref> {
|
|
||||||
match self {
|
|
||||||
Addr::HeapCell(hc) => Some(Ref::HeapCell(hc)),
|
|
||||||
Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Ref> for Addr {
|
|
||||||
fn from(r: Ref) -> Self {
|
|
||||||
match r {
|
|
||||||
Ref::HeapCell(hc) => Addr::HeapCell(hc),
|
|
||||||
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Ref {
|
|
||||||
HeapCell(usize),
|
|
||||||
StackCell(usize, usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
pub enum HeapCellValue {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(Ref),
|
|
||||||
Str(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Addr> for HeapCellValue {
|
|
||||||
fn from(addr: Addr) -> HeapCellValue {
|
|
||||||
match addr {
|
|
||||||
Addr::HeapCell(hc) =>
|
|
||||||
HeapCellValue::Ref(Ref::HeapCell(hc)),
|
|
||||||
Addr::StackCell(fr, sc) =>
|
|
||||||
HeapCellValue::Ref(Ref::StackCell(fr, sc)),
|
|
||||||
Addr::Str(hc) =>
|
|
||||||
HeapCellValue::Str(hc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HeapCellValue {
|
|
||||||
pub fn as_addr(&self, focus: usize) -> Addr {
|
|
||||||
match self {
|
|
||||||
&HeapCellValue::Ref(r) => Addr::from(r),
|
|
||||||
&HeapCellValue::Str(s) => Addr::Str(s),
|
|
||||||
&HeapCellValue::NamedStr(_, _) => Addr::Str(focus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum CodePtr {
|
|
||||||
DirEntry(usize),
|
|
||||||
TopLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for CodePtr {
|
|
||||||
fn default() -> Self {
|
|
||||||
CodePtr::TopLevel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<usize> for CodePtr {
|
|
||||||
type Output = CodePtr;
|
|
||||||
|
|
||||||
fn add(self, rhs: usize) -> Self::Output {
|
|
||||||
match self {
|
|
||||||
CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
|
|
||||||
CodePtr::TopLevel => CodePtr::TopLevel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddAssign<usize> for CodePtr {
|
|
||||||
fn add_assign(&mut self, rhs: usize) {
|
|
||||||
match self {
|
|
||||||
&mut CodePtr::DirEntry(ref mut p) => *p += rhs,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Heap = Vec<HeapCellValue>;
|
|
||||||
|
|
||||||
pub type Registers = Vec<Addr>;
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn subterms(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Clause(_, _, ref terms) => terms.len(),
|
|
||||||
_ => 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &Atom {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, ref atom)
|
|
||||||
| &Term::Var(_, ref atom)
|
|
||||||
| &Term::Clause(_, ref atom, _) => atom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
|
|
||||||
&Term::Clause(_, _, ref child_terms) => child_terms.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type HeapVarDict = HashMap<Var, Addr>;
|
|
||||||
|
|
||||||
pub enum EvalResult {
|
|
||||||
EntryFailure,
|
|
||||||
EntrySuccess,
|
|
||||||
InitialQuerySuccess(HeapVarDict),
|
|
||||||
QueryFailure,
|
|
||||||
SubsequentQuerySuccess,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EvalResult {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn failed_query(&self) -> bool {
|
|
||||||
if let &EvalResult::QueryFailure = self {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,447 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
use l3::iterators::{FactIterator, QueryIterator};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::cmp::max;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=TermRef<'a>>;
|
|
||||||
|
|
||||||
fn iter(&'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(Level, Atom, usize, RegType) -> Self;
|
|
||||||
|
|
||||||
fn argument_to_variable(RegType, usize) -> Self;
|
|
||||||
fn argument_to_value(RegType, usize) -> Self;
|
|
||||||
fn subterm_to_variable(RegType) -> Self;
|
|
||||||
fn subterm_to_value(RegType) -> Self;
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(RegType) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
|
||||||
type Iterator = FactIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.breadth_first_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
|
||||||
FactInstruction::GetStructure(lvl, atom, arity, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
|
||||||
FactInstruction::GetVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
|
||||||
FactInstruction::GetValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|
||||||
type Iterator = QueryIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.post_order_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
|
||||||
QueryInstruction::PutStructure(lvl, atom, arity, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TermMarker<'a> {
|
|
||||||
bindings: HashMap<&'a Var, VarReg>,
|
|
||||||
arg_c: usize,
|
|
||||||
perm_c: usize,
|
|
||||||
temp_c: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TermMarker<'a> {
|
|
||||||
fn new() -> TermMarker<'a> {
|
|
||||||
TermMarker { bindings: HashMap::new(),
|
|
||||||
arg_c: 1,
|
|
||||||
perm_c: 1,
|
|
||||||
temp_c: 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.bindings.clear();
|
|
||||||
self.perm_c = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_var(&self, var: &'a Var) -> bool {
|
|
||||||
self.bindings.contains_key(var)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, var: &'a Var) -> VarReg {
|
|
||||||
*self.bindings.get(var).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(&mut self, var: &'a Var, r: VarReg) {
|
|
||||||
self.bindings.insert(var, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
|
|
||||||
let reg_type = cell.get();
|
|
||||||
|
|
||||||
if reg_type.reg_num() == 0 {
|
|
||||||
match lvl {
|
|
||||||
Level::Deep if reg_type.is_perm() => {
|
|
||||||
let perm = self.perm_c;
|
|
||||||
self.perm_c += 1;
|
|
||||||
cell.set(RegType::Perm(perm));
|
|
||||||
},
|
|
||||||
Level::Deep => {
|
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
|
||||||
cell.set(RegType::Temp(temp));
|
|
||||||
},
|
|
||||||
Level::Shallow if reg_type.is_perm() => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Perm(arg));
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Temp(arg));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
|
|
||||||
{
|
|
||||||
let reg = self.get(var);
|
|
||||||
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(reg.norm()),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c);
|
|
||||||
|
|
||||||
self.arg_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
|
|
||||||
{
|
|
||||||
let inner_reg = if reg.is_perm() {
|
|
||||||
let perm = self.perm_c;
|
|
||||||
self.perm_c += 1;
|
|
||||||
RegType::Perm(perm)
|
|
||||||
} else {
|
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
|
||||||
RegType::Temp(temp)
|
|
||||||
};
|
|
||||||
|
|
||||||
let reg = match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(inner_reg),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
|
|
||||||
self.arg_c += 1;
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.insert(var, reg);
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance_at_head(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = max(term.subterms(), self.temp_c) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = term.subterms() + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum TermStatus {
|
|
||||||
New, Old, Recurrent
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGenerator<'a> {
|
|
||||||
marker: TermMarker<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
type VariableFixture<'a> = (TermStatus, Vec<&'a Cell<VarReg>>);
|
|
||||||
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
|
|
||||||
|
|
||||||
impl<'a> CodeGenerator<'a> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CodeGenerator { marker: TermMarker::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vars(&self) -> &HashMap<&Var, VarReg> {
|
|
||||||
&self.marker.bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
name: &'a Atom,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
arity: usize)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(lvl, cell);
|
|
||||||
Target::to_structure(lvl, name.clone(), arity, cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn var_term<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
cell: &'a Cell<VarReg>,
|
|
||||||
var: &'a Var)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
if !self.marker.contains_var(var) {
|
|
||||||
let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_variable(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_variable(norm)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = self.marker.mark_old_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_value(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_value(norm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(Level::Deep, cell);
|
|
||||||
Target::clause_arg_to_instr(cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
|
|
||||||
self.non_var_subterm(cell),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
self.var_term(Level::Deep, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let iter = Target::iter(term);
|
|
||||||
let mut target = Vec::new();
|
|
||||||
|
|
||||||
for term in iter {
|
|
||||||
match term {
|
|
||||||
TermRef::Atom(lvl, term, atom) =>
|
|
||||||
target.push(self.to_structure(lvl, atom, term, 0)),
|
|
||||||
TermRef::Clause(lvl, term, atom, terms) => {
|
|
||||||
target.push(self.to_structure(lvl, atom, term, terms.len()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(self.subterm_to_instr(subterm.as_ref()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
|
|
||||||
target.push(self.var_term(lvl, cell, var)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
|
|
||||||
where Iter : Iterator<Item=TermRef<'a>>
|
|
||||||
{
|
|
||||||
for term in iter {
|
|
||||||
if let TermRef::Var(_, reg_cell, var) = term {
|
|
||||||
let mut status = vs.entry(var)
|
|
||||||
.or_insert((TermStatus::New, Vec::new()));
|
|
||||||
|
|
||||||
status.1.push(reg_cell);
|
|
||||||
|
|
||||||
match status.0 {
|
|
||||||
TermStatus::Old => status.0 = TermStatus::Recurrent,
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
|
|
||||||
match *term_status {
|
|
||||||
TermStatus::New => *term_status = TermStatus::Old,
|
|
||||||
TermStatus::Recurrent => {
|
|
||||||
for cell_reg in cb.drain(0..) {
|
|
||||||
cell_reg.set(VarReg::Norm(RegType::Perm(0)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut vfs = HashMap::new();
|
|
||||||
|
|
||||||
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
|
||||||
|
|
||||||
Self::mark_vars_in_term(iter, &mut vfs);
|
|
||||||
|
|
||||||
for term in clauses {
|
|
||||||
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfs
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
|
|
||||||
match term {
|
|
||||||
&Term::Atom(_, ref atom) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), 0);
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
&Term::Clause(_, ref atom, ref terms) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), terms.len());
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
|
|
||||||
let vfs = Self::mark_perm_vars(&rule);
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut perm_vars = 0;
|
|
||||||
|
|
||||||
for &(term_status, _) in vfs.values() {
|
|
||||||
if let TermStatus::Recurrent = term_status {
|
|
||||||
perm_vars += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut body = Vec::new();
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
|
|
||||||
|
|
||||||
self.marker.advance(p0);
|
|
||||||
body.push(Line::Fact(self.compile_target(p0)));
|
|
||||||
|
|
||||||
self.marker.advance_at_head(p1);
|
|
||||||
body.push(Line::Query(self.compile_target(p1)));
|
|
||||||
|
|
||||||
Self::add_conditional_call(&mut body, p1);
|
|
||||||
|
|
||||||
body = clauses.iter()
|
|
||||||
.map(|ref term| self.compile_query(term))
|
|
||||||
.fold(body, |mut body, ref mut cqs| {
|
|
||||||
body.append(cqs);
|
|
||||||
body
|
|
||||||
});
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Deallocate));
|
|
||||||
body
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
|
|
||||||
let proceed = Line::Control(ControlInstruction::Proceed);
|
|
||||||
|
|
||||||
compiled_fact.push(proceed);
|
|
||||||
compiled_fact
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_query(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
|
|
||||||
Self::add_conditional_call(&mut compiled_query, term);
|
|
||||||
|
|
||||||
compiled_query
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_predicate(&mut self, clauses: &'a Vec<PredicateClause>) -> Code
|
|
||||||
{
|
|
||||||
let mut code = Vec::new();
|
|
||||||
|
|
||||||
for (i, clause) in clauses.iter().enumerate() {
|
|
||||||
self.marker.reset();
|
|
||||||
|
|
||||||
let mut clause_code = match clause {
|
|
||||||
&PredicateClause::Fact(ref fact) =>
|
|
||||||
self.compile_fact(fact),
|
|
||||||
&PredicateClause::Rule(ref rule) =>
|
|
||||||
self.compile_rule(rule)
|
|
||||||
};
|
|
||||||
|
|
||||||
let choice = match i {
|
|
||||||
0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
|
|
||||||
_ if i == clauses.len() - 1 => ChoiceInstruction::TrustMe,
|
|
||||||
_ => ChoiceInstruction::RetryMeElse(clause_code.len() + 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
code.push(Line::Choice(choice));
|
|
||||||
code.append(&mut clause_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
use l3::and_stack::*;
|
|
||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum HeapCellView<'a> {
|
|
||||||
Str(usize, &'a Atom),
|
|
||||||
HeapVar(usize),
|
|
||||||
StackVar(usize, usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HeapCellViewer<'a> {
|
|
||||||
heap: &'a Heap,
|
|
||||||
and_stack: &'a AndStack,
|
|
||||||
state_stack: Vec<Addr>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> HeapCellViewer<'a> {
|
|
||||||
pub fn new(heap: &'a Heap, and_stack: &'a AndStack, focus: Addr) -> Self {
|
|
||||||
HeapCellViewer {
|
|
||||||
heap: heap,
|
|
||||||
and_stack: and_stack,
|
|
||||||
state_stack: vec![focus]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn follow_stack_ref(&mut self, mut fr: usize, mut sc: usize) -> HeapCellView<'a>
|
|
||||||
{
|
|
||||||
loop {
|
|
||||||
match self.and_stack[fr][sc] {
|
|
||||||
Addr::HeapCell(hc) | Addr::Str(hc) =>
|
|
||||||
return self.follow_heap_ref(hc),
|
|
||||||
Addr::StackCell(fr1, sc1) => {
|
|
||||||
if fr1 == fr && sc1 == sc {
|
|
||||||
return HeapCellView::StackVar(fr, sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fr = fr1; sc = sc1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn follow_heap_ref(&mut self, mut focus: usize) -> HeapCellView<'a> {
|
|
||||||
loop {
|
|
||||||
match &self.heap[focus] {
|
|
||||||
&HeapCellValue::NamedStr(arity, ref name) => {
|
|
||||||
for i in (1 .. arity + 1).rev() {
|
|
||||||
self.state_stack.push(Addr::HeapCell(focus + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
return HeapCellView::Str(arity, name);
|
|
||||||
},
|
|
||||||
&HeapCellValue::Ref(Ref::HeapCell(hc)) => {
|
|
||||||
if focus == hc {
|
|
||||||
return HeapCellView::HeapVar(hc);
|
|
||||||
} else {
|
|
||||||
focus = hc;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&HeapCellValue::Ref(Ref::StackCell(fr, sc)) =>
|
|
||||||
return self.follow_stack_ref(fr, sc),
|
|
||||||
&HeapCellValue::Str(cell_num) =>
|
|
||||||
focus = cell_num,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for HeapCellViewer<'a> {
|
|
||||||
type Item = HeapCellView<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if let Some(addr) = self.state_stack.pop() {
|
|
||||||
match addr {
|
|
||||||
Addr::HeapCell(hc) | Addr::Str(hc) =>
|
|
||||||
return Some(self.follow_heap_ref(hc)),
|
|
||||||
Addr::StackCell(fr, sc) =>
|
|
||||||
return Some(self.follow_stack_ref(fr, sc))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
255
src/l3/io.rs
255
src/l3/io.rs
@@ -1,255 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
use l3::codegen::*;
|
|
||||||
use l3::l3_parser::*;
|
|
||||||
use l3::machine::*;
|
|
||||||
|
|
||||||
use termion::raw::IntoRawMode;
|
|
||||||
use termion::input::TermRead;
|
|
||||||
use termion::event::Key;
|
|
||||||
|
|
||||||
use std::io::{Write, stdin, stdout};
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, {}", name, arity, r),
|
|
||||||
&FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
|
|
||||||
&FactInstruction::GetValue(ref x, ref a) =>
|
|
||||||
write!(f, "get_value {}, A{}", x, a),
|
|
||||||
&FactInstruction::GetVariable(ref x, ref a) =>
|
|
||||||
write!(f, "get_variable {}, A{}", x, a),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable {}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value {}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, {}", name, arity, r.reg_num()),
|
|
||||||
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
|
|
||||||
&QueryInstruction::PutValue(ref x, ref a) =>
|
|
||||||
write!(f, "put_value {}, A{}", x, a),
|
|
||||||
&QueryInstruction::PutVariable(ref x, ref a) =>
|
|
||||||
write!(f, "put_variable {}, A{}", x, a),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable {}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value {}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ControlInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&ControlInstruction::Allocate(num_cells) =>
|
|
||||||
write!(f, "allocate {}", num_cells),
|
|
||||||
&ControlInstruction::Call(ref name, ref arity) =>
|
|
||||||
write!(f, "call {}/{}", name, arity),
|
|
||||||
&ControlInstruction::Deallocate =>
|
|
||||||
write!(f, "deallocate"),
|
|
||||||
&ControlInstruction::Proceed =>
|
|
||||||
write!(f, "proceed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ChoiceInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&ChoiceInstruction::TryMeElse(offset) =>
|
|
||||||
write!(f, "try_me_else {}", offset),
|
|
||||||
&ChoiceInstruction::RetryMeElse(offset) =>
|
|
||||||
write!(f, "retry_me_else {}", offset),
|
|
||||||
&ChoiceInstruction::TrustMe =>
|
|
||||||
write!(f, "trust_me")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Level {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&Level::Shallow => write!(f, "A"),
|
|
||||||
&Level::Deep => write!(f, "X")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for VarReg {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
|
|
||||||
&VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
|
|
||||||
&VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
|
|
||||||
write!(f, "Y{} A{}", reg, arg),
|
|
||||||
&VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
|
|
||||||
write!(f, "X{} A{}", reg, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for RegType {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&RegType::Perm(val) => write!(f, "Y{}", val),
|
|
||||||
&RegType::Temp(val) => write!(f, "X{}", val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn is_consistent(predicate: &Vec<PredicateClause>) -> bool {
|
|
||||||
let name = predicate.first().unwrap().name();
|
|
||||||
let arity = predicate.first().unwrap().arity();
|
|
||||||
|
|
||||||
for clause in predicate.iter().skip(1) {
|
|
||||||
if !(name == clause.name() && arity == clause.arity()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn print_code(code: &Code) {
|
|
||||||
for clause in code {
|
|
||||||
match clause {
|
|
||||||
&Line::Fact(ref fact) =>
|
|
||||||
for fact_instr in fact {
|
|
||||||
println!("{}", fact_instr);
|
|
||||||
},
|
|
||||||
&Line::Choice(ref choice) =>
|
|
||||||
println!("{}", choice),
|
|
||||||
&Line::Control(ref control) =>
|
|
||||||
println!("{}", control),
|
|
||||||
&Line::Query(ref query) =>
|
|
||||||
for query_instr in query {
|
|
||||||
println!("{}", query_instr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read() -> String {
|
|
||||||
let _ = stdout().flush();
|
|
||||||
|
|
||||||
let mut buffer = String::new();
|
|
||||||
let mut result = String::new();
|
|
||||||
|
|
||||||
let stdin = stdin();
|
|
||||||
stdin.read_line(&mut buffer).unwrap();
|
|
||||||
|
|
||||||
if &*buffer.trim() == ":{" {
|
|
||||||
buffer.clear();
|
|
||||||
|
|
||||||
stdin.read_line(&mut buffer).unwrap();
|
|
||||||
|
|
||||||
while &*buffer.trim() != "}:" {
|
|
||||||
result += buffer.as_str();
|
|
||||||
buffer.clear();
|
|
||||||
stdin.read_line(&mut buffer).unwrap();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult
|
|
||||||
{
|
|
||||||
let result = parse_TopLevel(buffer);
|
|
||||||
let mut cg = CodeGenerator::new();
|
|
||||||
|
|
||||||
match &result {
|
|
||||||
&Ok(TopLevel::Predicate(ref clauses)) => {
|
|
||||||
if is_consistent(clauses) {
|
|
||||||
let compiled_pred = cg.compile_predicate(clauses);
|
|
||||||
wam.add_predicate(clauses, compiled_pred);
|
|
||||||
|
|
||||||
EvalResult::EntrySuccess
|
|
||||||
} else {
|
|
||||||
let msg = r"Error: predicate is inconsistent.
|
|
||||||
Each predicate must have the same name and arity.";
|
|
||||||
|
|
||||||
println!("{}", msg);
|
|
||||||
EvalResult::EntryFailure
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&Ok(TopLevel::Fact(ref fact)) => {
|
|
||||||
let compiled_fact = cg.compile_fact(&fact);
|
|
||||||
wam.add_fact(fact, compiled_fact);
|
|
||||||
EvalResult::EntrySuccess
|
|
||||||
},
|
|
||||||
&Ok(TopLevel::Rule(ref rule)) => {
|
|
||||||
let compiled_rule = cg.compile_rule(&rule);
|
|
||||||
wam.add_rule(rule, compiled_rule);
|
|
||||||
EvalResult::EntrySuccess
|
|
||||||
},
|
|
||||||
&Ok(TopLevel::Query(ref query)) => {
|
|
||||||
let compiled_query = cg.compile_query(&query);
|
|
||||||
wam.run_query(compiled_query, &cg)
|
|
||||||
},
|
|
||||||
&Err(_) => {
|
|
||||||
println!("Grammatical error of some kind!");
|
|
||||||
EvalResult::EntryFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print(wam: &mut Machine, result: EvalResult) {
|
|
||||||
match result {
|
|
||||||
EvalResult::InitialQuerySuccess(heap_locs) => {
|
|
||||||
println!("yes");
|
|
||||||
|
|
||||||
'outer: loop {
|
|
||||||
let mut result = EvalResult::QueryFailure;
|
|
||||||
let bindings = wam.heap_view(&heap_locs);
|
|
||||||
|
|
||||||
let stdin = stdin();
|
|
||||||
let mut stdout = stdout().into_raw_mode().unwrap();
|
|
||||||
|
|
||||||
write!(stdout, "{}\n\r", bindings).unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
|
|
||||||
if !wam.or_stack_is_empty() {
|
|
||||||
write!(stdout, "Press ; to continue or A to abort.\n\r").unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
|
|
||||||
for c in stdin.keys() {
|
|
||||||
match c.unwrap() {
|
|
||||||
Key::Char(';') => {
|
|
||||||
result = wam.continue_query();
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Key::Char('a') | Key::Char('A') =>
|
|
||||||
break 'outer,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let &EvalResult::QueryFailure = &result {
|
|
||||||
write!(stdout, "no\n\r").unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
EvalResult::QueryFailure => println!("no"),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
enum IteratorState<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, usize, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
IsolatedAtom(&'a Cell<RegType>, &'a Atom),
|
|
||||||
IsolatedVar(&'a Cell<VarReg>, &'a Var),
|
|
||||||
RootClause(usize, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IteratorState<'a> {
|
|
||||||
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a>
|
|
||||||
{
|
|
||||||
match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::Atom(lvl, cell, atom),
|
|
||||||
&Term::Clause(ref cell, ref atom, ref child_terms) =>
|
|
||||||
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::Var(lvl, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct QueryIterator<'a> {
|
|
||||||
state_stack: Vec<IteratorState<'a>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> QueryIterator<'a> {
|
|
||||||
fn push_clause(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
child_num: usize,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
name: &'a Atom,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::Clause(lvl,
|
|
||||||
child_num,
|
|
||||||
cell,
|
|
||||||
name,
|
|
||||||
child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_root_clause(&mut self,
|
|
||||||
child_num: usize,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_stack.push(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> QueryIterator<'a> {
|
|
||||||
let state = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::IsolatedAtom(cell, atom),
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
IteratorState::RootClause(0, terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::IsolatedVar(cell, var)
|
|
||||||
};
|
|
||||||
|
|
||||||
QueryIterator { state_stack: vec![state] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for QueryIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
|
||||||
match iter_state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
} else {
|
|
||||||
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
|
|
||||||
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(child_num, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
self.push_root_clause(child_num + 1, child_terms);
|
|
||||||
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FactIterator<'a> {
|
|
||||||
state_queue: VecDeque<IteratorState<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FactIterator<'a> {
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_queue.push_back(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> FactIterator<'a> {
|
|
||||||
let states = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
vec![IteratorState::IsolatedAtom(cell, atom)],
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
vec![IteratorState::RootClause(0, terms)],
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
vec![IteratorState::IsolatedVar(cell, var)]
|
|
||||||
};
|
|
||||||
|
|
||||||
FactIterator { state_queue: VecDeque::from(states) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for FactIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(state) = self.state_queue.pop_front() {
|
|
||||||
match state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Deep, child_term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(_, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Shallow, child_term);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn post_order_iter(&self) -> QueryIterator {
|
|
||||||
QueryIterator::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breadth_first_iter(&self) -> FactIterator {
|
|
||||||
FactIterator::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
grammar;
|
|
||||||
|
|
||||||
pub TopLevel: TopLevel = {
|
|
||||||
"?-" <t:Term> "." => TopLevel::Query(t),
|
|
||||||
<Predicate> => TopLevel::Predicate(<>),
|
|
||||||
<Rule> "." => TopLevel::Rule(<>),
|
|
||||||
<Term> "." => TopLevel::Fact(<>)
|
|
||||||
};
|
|
||||||
|
|
||||||
Atom : Atom = {
|
|
||||||
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
BoxedTerm : Box<Term> = {
|
|
||||||
<t:Term> => Box::new(t)
|
|
||||||
};
|
|
||||||
|
|
||||||
Clause : Term = {
|
|
||||||
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
|
||||||
let mut ts = ts;
|
|
||||||
ts.push(t);
|
|
||||||
Term::Clause(Cell::new(RegType::Temp(0)), a, ts)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Predicate : Vec<PredicateClause> = {
|
|
||||||
<pcs: (<PredicateClause>)+> <pc: PredicateClause> => {
|
|
||||||
let mut pcs = pcs;
|
|
||||||
pcs.push(pc);
|
|
||||||
pcs
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PredicateClause : PredicateClause = {
|
|
||||||
<Rule> "." => PredicateClause::Rule(<>),
|
|
||||||
<Term> "." => PredicateClause::Fact(<>)
|
|
||||||
};
|
|
||||||
|
|
||||||
Rule : Rule = {
|
|
||||||
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (c, h), clauses: cs },
|
|
||||||
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (Term::Atom(Cell::new(RegType::Temp(0)), a), h),
|
|
||||||
clauses: cs }
|
|
||||||
};
|
|
||||||
|
|
||||||
Term : Term = {
|
|
||||||
<Clause> => <>,
|
|
||||||
<Atom> => Term::Atom(Cell::new(RegType::Temp(0)), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), <>)
|
|
||||||
};
|
|
||||||
|
|
||||||
Var : Var = {
|
|
||||||
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
2177
src/l3/l3_parser.rs
2177
src/l3/l3_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,677 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
use l3::codegen::*;
|
|
||||||
use l3::heapview::*;
|
|
||||||
use l3::and_stack::*;
|
|
||||||
use l3::or_stack::*;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MachineState {
|
|
||||||
h: usize,
|
|
||||||
s: usize,
|
|
||||||
p: CodePtr,
|
|
||||||
b: usize,
|
|
||||||
e: usize,
|
|
||||||
num_of_args: usize,
|
|
||||||
cp: CodePtr,
|
|
||||||
fail: bool,
|
|
||||||
heap: Heap,
|
|
||||||
mode: MachineMode,
|
|
||||||
and_stack: AndStack,
|
|
||||||
or_stack: OrStack,
|
|
||||||
registers: Registers,
|
|
||||||
trail: Vec<Ref>,
|
|
||||||
tr: usize,
|
|
||||||
hb: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
type CodeDir = HashMap<(Atom, usize), usize>;
|
|
||||||
|
|
||||||
impl Index<RegType> for MachineState {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, reg: RegType) -> &Self::Output {
|
|
||||||
match reg {
|
|
||||||
RegType::Temp(temp) => &self.registers[temp],
|
|
||||||
RegType::Perm(perm) => {
|
|
||||||
let e = self.e;
|
|
||||||
&self.and_stack[e][perm]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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::Perm(perm) => {
|
|
||||||
let e = self.e;
|
|
||||||
&mut self.and_stack[e][perm]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
ms: MachineState,
|
|
||||||
code: Code,
|
|
||||||
code_dir: CodeDir
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Machine {
|
|
||||||
ms: MachineState::new(),
|
|
||||||
code: Vec::new(),
|
|
||||||
code_dir: HashMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn failed(&self) -> bool {
|
|
||||||
self.ms.fail
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = fact.name().clone();
|
|
||||||
let arity = fact.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_rule(&mut self, rule: &Rule, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = rule.head.0.name().clone();
|
|
||||||
let arity = rule.head.0.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_predicate(&mut self, pred: &Vec<PredicateClause>, mut code: Code)
|
|
||||||
{
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = pred.first().unwrap().name().clone();
|
|
||||||
let arity = pred.first().unwrap().arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_instr<'a>(&mut self, instr_src: LineOrCodeOffset<'a>) -> bool
|
|
||||||
{
|
|
||||||
let mut instr = match instr_src {
|
|
||||||
LineOrCodeOffset::Instruction(instr) => instr,
|
|
||||||
LineOrCodeOffset::Offset(p) => &self.code[p]
|
|
||||||
};
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match instr {
|
|
||||||
&Line::Choice(ref choice_instr) =>
|
|
||||||
self.ms.execute_choice_instr(choice_instr),
|
|
||||||
&Line::Fact(ref fact) => {
|
|
||||||
for fact_instr in fact {
|
|
||||||
self.ms.execute_fact_instr(&fact_instr);
|
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Query(ref query) => {
|
|
||||||
for query_instr in query {
|
|
||||||
self.ms.execute_query_instr(&query_instr);
|
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Control(ref control_instr) =>
|
|
||||||
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.failed() {
|
|
||||||
let p = self.ms
|
|
||||||
.or_stack
|
|
||||||
.top()
|
|
||||||
.map(|fr| fr.bp)
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
if let CodePtr::TopLevel = p {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
self.ms.fail = false;
|
|
||||||
self.ms.p = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.ms.p {
|
|
||||||
CodePtr::DirEntry(p) if p < self.code.len() =>
|
|
||||||
instr = &self.code[p],
|
|
||||||
_ => break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn heap_view(&self, var_dir: &HeapVarDict) -> String {
|
|
||||||
let mut result = String::new();
|
|
||||||
|
|
||||||
for (var, addr) in var_dir {
|
|
||||||
let mut arities = Vec::new();
|
|
||||||
let viewer = HeapCellViewer::new(&self.ms.heap,
|
|
||||||
&self.ms.and_stack,
|
|
||||||
*addr);
|
|
||||||
|
|
||||||
if result != "" {
|
|
||||||
result += "\n\r";
|
|
||||||
}
|
|
||||||
|
|
||||||
result += var.as_str();
|
|
||||||
result += " = ";
|
|
||||||
|
|
||||||
for view in viewer {
|
|
||||||
match arities.pop() {
|
|
||||||
Some(n) => arities.push(n-1),
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(arities.is_empty() || result.ends_with("(")) {
|
|
||||||
result += ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
match view {
|
|
||||||
HeapCellView::Str(arity, ref name) => {
|
|
||||||
result += name.as_str();
|
|
||||||
|
|
||||||
if arity > 0 {
|
|
||||||
arities.push(arity);
|
|
||||||
result += "(";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
HeapCellView::HeapVar(cell_num) => {
|
|
||||||
result += "_";
|
|
||||||
result += cell_num.to_string().as_str();
|
|
||||||
},
|
|
||||||
HeapCellView::StackVar(fr, sc) => {
|
|
||||||
result += "_s_";
|
|
||||||
result += fr.to_string().as_str();
|
|
||||||
result += "_";
|
|
||||||
result += sc.to_string().as_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(&0) = arities.last() {
|
|
||||||
result += ")";
|
|
||||||
arities.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_query(&mut self, code: Code, cg: &CodeGenerator) -> EvalResult
|
|
||||||
{
|
|
||||||
let mut succeeded = true;
|
|
||||||
let mut heap_locs = HashMap::new();
|
|
||||||
|
|
||||||
for instr in code.iter().take(1) {
|
|
||||||
succeeded = self.execute_instr(LineOrCodeOffset::from(instr));
|
|
||||||
}
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
for (var, vr) in cg.vars() {
|
|
||||||
let addr = self.ms.registers[vr.root_register()];
|
|
||||||
heap_locs.insert((*var).clone(), addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for instr in code.iter().skip(1) {
|
|
||||||
succeeded = self.execute_instr(LineOrCodeOffset::from(instr));
|
|
||||||
if !succeeded {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
EvalResult::InitialQuerySuccess(heap_locs)
|
|
||||||
} else {
|
|
||||||
EvalResult::QueryFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn or_stack_is_empty(&self) -> bool {
|
|
||||||
self.ms.or_stack.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn continue_query(&mut self) -> EvalResult
|
|
||||||
{
|
|
||||||
if !self.or_stack_is_empty() {
|
|
||||||
let b = self.ms.b;
|
|
||||||
self.ms.p = self.ms.or_stack[b].bp;
|
|
||||||
|
|
||||||
let succeeded = if let CodePtr::DirEntry(p) = self.ms.p {
|
|
||||||
self.execute_instr(LineOrCodeOffset::Offset(p))
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
EvalResult::SubsequentQuerySuccess
|
|
||||||
} else {
|
|
||||||
EvalResult::QueryFailure
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
EvalResult::QueryFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.ms.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MachineState {
|
|
||||||
fn new() -> MachineState {
|
|
||||||
MachineState { h: 0,
|
|
||||||
s: 0,
|
|
||||||
p: CodePtr::TopLevel,
|
|
||||||
b: 0,
|
|
||||||
e: 0,
|
|
||||||
num_of_args: 0,
|
|
||||||
cp: CodePtr::TopLevel,
|
|
||||||
fail: false,
|
|
||||||
heap: Vec::with_capacity(256),
|
|
||||||
mode: MachineMode::Write,
|
|
||||||
and_stack: AndStack::new(),
|
|
||||||
or_stack: OrStack::new(),
|
|
||||||
registers: vec![Addr::HeapCell(0); 32],
|
|
||||||
trail: Vec::new(),
|
|
||||||
tr: 0,
|
|
||||||
hb: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn num_frames(&self) -> usize {
|
|
||||||
self.and_stack.len() + self.or_stack.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn store(&self, a: Addr) -> Addr {
|
|
||||||
match a {
|
|
||||||
Addr::HeapCell(r) => self.heap[r].as_addr(r),
|
|
||||||
Addr::StackCell(fr, sc) => self.and_stack[fr][sc],
|
|
||||||
addr => addr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deref(&self, a: Addr) -> Addr {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let value = self.store(a);
|
|
||||||
|
|
||||||
if value.is_ref() && value != a {
|
|
||||||
a = value;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bind(&mut self, r1: Ref, a2: Addr) {
|
|
||||||
let t2 = self.store(a2);
|
|
||||||
|
|
||||||
match r1 {
|
|
||||||
Ref::StackCell(fr, sc) =>
|
|
||||||
self.and_stack[fr][sc] = t2,
|
|
||||||
Ref::HeapCell(hc) =>
|
|
||||||
self.heap[hc] = HeapCellValue::from(t2)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.trail(r1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unify(&mut self, a1: Addr, a2: Addr) {
|
|
||||||
let mut pdl = vec![a1, a2];
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
|
|
||||||
while !(pdl.is_empty() || self.fail) {
|
|
||||||
let d1 = self.deref(pdl.pop().unwrap());
|
|
||||||
let d2 = self.deref(pdl.pop().unwrap());
|
|
||||||
|
|
||||||
if d1 != d2 {
|
|
||||||
match (self.store(d1), self.store(d2)) {
|
|
||||||
(Addr::HeapCell(hc), _) =>
|
|
||||||
self.bind(Ref::HeapCell(hc), d2),
|
|
||||||
(_, Addr::HeapCell(hc)) =>
|
|
||||||
self.bind(Ref::HeapCell(hc), d1),
|
|
||||||
(Addr::StackCell(fr, sc), _) =>
|
|
||||||
self.bind(Ref::StackCell(fr, sc), d2),
|
|
||||||
(_, Addr::StackCell(fr, sc)) =>
|
|
||||||
self.bind(Ref::StackCell(fr, sc), d1),
|
|
||||||
(Addr::Str(a1), Addr::Str(a2)) => {
|
|
||||||
let r1 = &self.heap[a1];
|
|
||||||
let r2 = &self.heap[a2];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
|
|
||||||
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
|
|
||||||
if n1 == n2 && *f1 == *f2 {
|
|
||||||
for i in 1 .. n1 + 1 {
|
|
||||||
pdl.push(Addr::HeapCell(a1 + i));
|
|
||||||
pdl.push(Addr::HeapCell(a2 + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trail(&mut self, r: Ref) {
|
|
||||||
match r {
|
|
||||||
Ref::HeapCell(hc) => {
|
|
||||||
if hc < self.hb {
|
|
||||||
self.trail.push(r);
|
|
||||||
self.tr += 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Ref::StackCell(fr, _) => {
|
|
||||||
let fr_gi = self.and_stack[fr].global_index;
|
|
||||||
let b_gi = if !self.or_stack.is_empty() {
|
|
||||||
self.or_stack[self.b].global_index
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
if fr_gi < b_gi {
|
|
||||||
self.trail.push(r);
|
|
||||||
self.tr += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unwind_trail(&mut self, a1: usize, a2: usize) {
|
|
||||||
for i in a1 .. a2 {
|
|
||||||
match self.trail[i] {
|
|
||||||
Ref::HeapCell(r) =>
|
|
||||||
self.heap[r] = HeapCellValue::Ref(self.trail[i]),
|
|
||||||
Ref::StackCell(fr, sc) =>
|
|
||||||
self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
self[reg] = Addr::Str(self.h + 1);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutValue(norm, arg) =>
|
|
||||||
self.registers[arg] = self[norm],
|
|
||||||
&QueryInstruction::PutVariable(norm, arg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
|
|
||||||
|
|
||||||
self[norm] = Addr::HeapCell(self.h);
|
|
||||||
self.registers[arg] = Addr::HeapCell(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetVariable(reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
|
|
||||||
self[reg] = Addr::HeapCell(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
let heap_val = self[reg];
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
|
|
||||||
let addr = self.deref(self[reg]);
|
|
||||||
|
|
||||||
match self.store(addr) {
|
|
||||||
Addr::Str(a) => {
|
|
||||||
let result = &self.heap[a];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(narity, ref str) = result {
|
|
||||||
if narity == arity && *name == *str {
|
|
||||||
self.s = a + 1;
|
|
||||||
self.mode = MachineMode::Read;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
let h = self.h;
|
|
||||||
|
|
||||||
self.bind(addr.as_ref().unwrap(), Addr::HeapCell(h));
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&FactInstruction::GetVariable(norm, arg) =>
|
|
||||||
self[norm] = self.registers[arg],
|
|
||||||
&FactInstruction::GetValue(norm, arg) => {
|
|
||||||
let norm_addr = self[norm];
|
|
||||||
let reg_addr = self.registers[arg];
|
|
||||||
|
|
||||||
self.unify(norm_addr, reg_addr);
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyVariable(reg) => {
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read =>
|
|
||||||
self[reg] = self.heap[self.s].as_addr(self.s),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
|
|
||||||
self[reg] = Addr::HeapCell(self.h);
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyValue(reg) => {
|
|
||||||
let s = self.s;
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => {
|
|
||||||
let reg_addr = self[reg];
|
|
||||||
self.unify(reg_addr, Addr::HeapCell(s));
|
|
||||||
},
|
|
||||||
MachineMode::Write => {
|
|
||||||
let heap_val = self.store(self[reg]);
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
|
||||||
{
|
|
||||||
match instr {
|
|
||||||
&ControlInstruction::Allocate(num_cells) => {
|
|
||||||
let num_frames = self.num_frames();
|
|
||||||
|
|
||||||
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
|
|
||||||
|
|
||||||
self.e = self.and_stack.len() - 1;
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ControlInstruction::Call(ref name, arity) => {
|
|
||||||
let compiled_tl_index = code_dir.get(&(name.clone(), arity))
|
|
||||||
.map(|index| *index);
|
|
||||||
|
|
||||||
match compiled_tl_index {
|
|
||||||
Some(compiled_tl_index) => {
|
|
||||||
self.cp = self.p + 1;
|
|
||||||
self.num_of_args = arity;
|
|
||||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
|
||||||
},
|
|
||||||
None => self.fail = true
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&ControlInstruction::Deallocate => {
|
|
||||||
let e = self.e;
|
|
||||||
|
|
||||||
let num_frame_e = self.and_stack.top().unwrap().global_index;
|
|
||||||
let num_frame_b = self.or_stack
|
|
||||||
.top()
|
|
||||||
.map(|fr| fr.global_index)
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
self.p = self.and_stack[e].cp;
|
|
||||||
self.e = self.and_stack[e].e;
|
|
||||||
|
|
||||||
if num_frame_e > num_frame_b {
|
|
||||||
let top_e = self.and_stack.top().unwrap().e;
|
|
||||||
self.and_stack.drop_frames(top_e - self.e + 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&ControlInstruction::Proceed =>
|
|
||||||
self.p = self.cp,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_choice_instr(&mut self, instr: &ChoiceInstruction)
|
|
||||||
{
|
|
||||||
match instr {
|
|
||||||
&ChoiceInstruction::TryMeElse(offset) => {
|
|
||||||
let n = self.num_of_args;
|
|
||||||
let num_frames = self.num_frames();
|
|
||||||
|
|
||||||
self.or_stack.push(num_frames + 1,
|
|
||||||
self.e,
|
|
||||||
self.cp,
|
|
||||||
self.b,
|
|
||||||
self.p + offset,
|
|
||||||
self.tr,
|
|
||||||
self.h,
|
|
||||||
self.num_of_args);
|
|
||||||
|
|
||||||
self.b = self.or_stack.len() - 1;
|
|
||||||
let b = self.b;
|
|
||||||
|
|
||||||
for i in 1 .. n + 1 {
|
|
||||||
self.or_stack[b][i] = self.registers[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.hb = self.h;
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ChoiceInstruction::RetryMeElse(offset) => {
|
|
||||||
let b = self.b;
|
|
||||||
let n = self.or_stack[b].num_args();
|
|
||||||
|
|
||||||
for i in 1 .. n + 1 {
|
|
||||||
self.registers[i] = self.or_stack[b][i];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.e = self.or_stack[b].e;
|
|
||||||
self.cp = self.or_stack[b].cp;
|
|
||||||
|
|
||||||
self.or_stack[b].bp = self.p + offset;
|
|
||||||
|
|
||||||
let old_tr = self.or_stack[b].tr;
|
|
||||||
let curr_tr = self.tr;
|
|
||||||
|
|
||||||
self.unwind_trail(old_tr, curr_tr);
|
|
||||||
self.tr = self.or_stack[b].tr;
|
|
||||||
|
|
||||||
self.trail.truncate(self.tr);
|
|
||||||
self.heap.truncate(self.or_stack[b].h);
|
|
||||||
|
|
||||||
self.h = self.or_stack[b].h;
|
|
||||||
self.hb = self.h;
|
|
||||||
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ChoiceInstruction::TrustMe => {
|
|
||||||
let b = self.b;
|
|
||||||
let n = self.or_stack[b].num_args();
|
|
||||||
|
|
||||||
for i in 1 .. n + 1 {
|
|
||||||
self.registers[i] = self.or_stack[b][i];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.e = self.or_stack[b].e;
|
|
||||||
self.cp = self.or_stack[b].cp;
|
|
||||||
|
|
||||||
let old_tr = self.or_stack[b].tr;
|
|
||||||
let curr_tr = self.tr;
|
|
||||||
|
|
||||||
self.unwind_trail(old_tr, curr_tr);
|
|
||||||
|
|
||||||
self.tr = self.or_stack[b].tr;
|
|
||||||
self.trail.truncate(self.tr);
|
|
||||||
|
|
||||||
self.h = self.or_stack[b].h;
|
|
||||||
self.heap.truncate(self.h);
|
|
||||||
|
|
||||||
self.b = self.or_stack[b].b;
|
|
||||||
|
|
||||||
self.or_stack.pop();
|
|
||||||
|
|
||||||
self.hb = self.h;
|
|
||||||
self.p += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.h = 0;
|
|
||||||
self.hb = 0;
|
|
||||||
self.e = 0;
|
|
||||||
self.b = 0;
|
|
||||||
self.s = 0;
|
|
||||||
self.tr = 0;
|
|
||||||
self.p = CodePtr::TopLevel;
|
|
||||||
self.cp = CodePtr::TopLevel;
|
|
||||||
self.num_of_args = 0;
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
self.trail.clear();
|
|
||||||
self.heap.clear();
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
self.and_stack.clear();
|
|
||||||
self.or_stack.clear();
|
|
||||||
self.registers = vec![Addr::HeapCell(0); 32];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
pub mod and_stack;
|
|
||||||
pub mod ast;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod heapview;
|
|
||||||
pub mod io;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod l3_parser;
|
|
||||||
pub mod machine;
|
|
||||||
pub mod or_stack;
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub struct Frame {
|
|
||||||
pub global_index: usize,
|
|
||||||
pub e: usize,
|
|
||||||
pub cp: CodePtr,
|
|
||||||
pub b: usize,
|
|
||||||
pub bp: CodePtr,
|
|
||||||
pub tr: usize,
|
|
||||||
pub h: usize,
|
|
||||||
args: Vec<Addr>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(global_index: usize,
|
|
||||||
e: usize,
|
|
||||||
cp: CodePtr,
|
|
||||||
b: usize,
|
|
||||||
bp: CodePtr,
|
|
||||||
tr: usize,
|
|
||||||
h: usize,
|
|
||||||
n: usize)
|
|
||||||
-> Self
|
|
||||||
{
|
|
||||||
Frame {
|
|
||||||
global_index: global_index,
|
|
||||||
e: e,
|
|
||||||
cp: cp,
|
|
||||||
b: b,
|
|
||||||
bp: bp,
|
|
||||||
tr: tr,
|
|
||||||
h: h,
|
|
||||||
args: vec![Addr::HeapCell(0); n]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn num_args(&self) -> usize {
|
|
||||||
self.args.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OrStack(Vec<Frame>);
|
|
||||||
|
|
||||||
impl OrStack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
OrStack(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self,
|
|
||||||
global_index: usize,
|
|
||||||
e: usize,
|
|
||||||
cp: CodePtr,
|
|
||||||
b: usize,
|
|
||||||
bp: CodePtr,
|
|
||||||
tr: usize,
|
|
||||||
h: usize,
|
|
||||||
n: usize)
|
|
||||||
{
|
|
||||||
self.0.push(Frame::new(global_index, e, cp, b, bp, tr, h, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.0.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn top(&self) -> Option<&Frame> {
|
|
||||||
self.0.last()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self) {
|
|
||||||
self.0.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.0.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for OrStack {
|
|
||||||
type Output = Frame;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.0.index(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for OrStack {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.0.index_mut(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Frame {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.args.index(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Frame {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.args.index_mut(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,9 +20,6 @@ use crate::prolog::read::*;
|
|||||||
|
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests;
|
|
||||||
|
|
||||||
extern fn handle_sigint(signal: libc::c_int) {
|
extern fn handle_sigint(signal: libc::c_int) {
|
||||||
let signal = signal::Signal::from_c_int(signal).unwrap();
|
let signal = signal::Signal::from_c_int(signal).unwrap();
|
||||||
if signal == signal::Signal::SIGINT {
|
if signal == signal::Signal::SIGINT {
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ pub enum InlinedClauseType {
|
|||||||
IsString(RegType),
|
IsString(RegType),
|
||||||
IsFloat(RegType),
|
IsFloat(RegType),
|
||||||
IsNonVar(RegType),
|
IsNonVar(RegType),
|
||||||
IsPartialString(RegType),
|
|
||||||
IsVar(RegType),
|
IsVar(RegType),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +108,6 @@ ref_thread_local! {
|
|||||||
m.insert(("string", 1), ClauseType::Inlined(InlinedClauseType::IsString(r1)));
|
m.insert(("string", 1), ClauseType::Inlined(InlinedClauseType::IsString(r1)));
|
||||||
m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1)));
|
m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1)));
|
||||||
m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1)));
|
m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1)));
|
||||||
m.insert(("is_partial_string", 1), ClauseType::Inlined(InlinedClauseType::IsPartialString(r1)));
|
|
||||||
m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1)));
|
m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1)));
|
||||||
m.insert(("acyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm));
|
m.insert(("acyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm));
|
||||||
m.insert(("arg", 3), ClauseType::BuiltIn(BuiltInClauseType::Arg));
|
m.insert(("arg", 3), ClauseType::BuiltIn(BuiltInClauseType::Arg));
|
||||||
@@ -127,7 +125,6 @@ ref_thread_local! {
|
|||||||
m.insert(("keysort", 2), ClauseType::BuiltIn(BuiltInClauseType::KeySort));
|
m.insert(("keysort", 2), ClauseType::BuiltIn(BuiltInClauseType::KeySort));
|
||||||
m.insert(("nl", 0), ClauseType::BuiltIn(BuiltInClauseType::Nl));
|
m.insert(("nl", 0), ClauseType::BuiltIn(BuiltInClauseType::Nl));
|
||||||
m.insert(("\\==", 2), ClauseType::BuiltIn(BuiltInClauseType::NotEq));
|
m.insert(("\\==", 2), ClauseType::BuiltIn(BuiltInClauseType::NotEq));
|
||||||
m.insert(("partial_string", 2), ClauseType::BuiltIn(BuiltInClauseType::PartialString));
|
|
||||||
m.insert(("read", 1), ClauseType::BuiltIn(BuiltInClauseType::Read));
|
m.insert(("read", 1), ClauseType::BuiltIn(BuiltInClauseType::Read));
|
||||||
m.insert(("sort", 2), ClauseType::BuiltIn(BuiltInClauseType::Sort));
|
m.insert(("sort", 2), ClauseType::BuiltIn(BuiltInClauseType::Sort));
|
||||||
|
|
||||||
@@ -147,7 +144,6 @@ impl InlinedClauseType {
|
|||||||
&InlinedClauseType::IsString(..) => "string",
|
&InlinedClauseType::IsString(..) => "string",
|
||||||
&InlinedClauseType::IsFloat(..) => "float",
|
&InlinedClauseType::IsFloat(..) => "float",
|
||||||
&InlinedClauseType::IsNonVar(..) => "nonvar",
|
&InlinedClauseType::IsNonVar(..) => "nonvar",
|
||||||
&InlinedClauseType::IsPartialString(..) => "is_partial_string",
|
|
||||||
&InlinedClauseType::IsVar(..) => "var",
|
&InlinedClauseType::IsVar(..) => "var",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,18 +155,26 @@ pub enum SystemClauseType {
|
|||||||
AbolishModuleClause,
|
AbolishModuleClause,
|
||||||
AssertDynamicPredicateToBack,
|
AssertDynamicPredicateToBack,
|
||||||
AssertDynamicPredicateToFront,
|
AssertDynamicPredicateToFront,
|
||||||
|
AtEndOfExpansion,
|
||||||
AtomChars,
|
AtomChars,
|
||||||
AtomCodes,
|
AtomCodes,
|
||||||
AtomLength,
|
AtomLength,
|
||||||
|
BindFromRegister,
|
||||||
CallAttributeGoals,
|
CallAttributeGoals,
|
||||||
|
CallContinuation,
|
||||||
CharCode,
|
CharCode,
|
||||||
CharsToNumber,
|
CharsToNumber,
|
||||||
|
ClearAttrVarBindings,
|
||||||
|
ClearAttributeGoals,
|
||||||
|
CloneAttributeGoals,
|
||||||
CodesToNumber,
|
CodesToNumber,
|
||||||
|
CopyTermWithoutAttrVars,
|
||||||
CheckCutPoint,
|
CheckCutPoint,
|
||||||
CopyToLiftedHeap,
|
CopyToLiftedHeap,
|
||||||
|
CreatePartialString,
|
||||||
DeleteAttribute,
|
DeleteAttribute,
|
||||||
DeleteHeadAttribute,
|
DeleteHeadAttribute,
|
||||||
DynamicModuleResolution,
|
DynamicModuleResolution(usize),
|
||||||
EnqueueAttributeGoal,
|
EnqueueAttributeGoal,
|
||||||
EnqueueAttributedVar,
|
EnqueueAttributedVar,
|
||||||
ExpandGoal,
|
ExpandGoal,
|
||||||
@@ -179,6 +183,7 @@ pub enum SystemClauseType {
|
|||||||
FetchGlobalVar,
|
FetchGlobalVar,
|
||||||
FetchGlobalVarWithOffset,
|
FetchGlobalVarWithOffset,
|
||||||
GetChar,
|
GetChar,
|
||||||
|
ResetAttrVarState,
|
||||||
TruncateIfNoLiftedHeapGrowthDiff,
|
TruncateIfNoLiftedHeapGrowthDiff,
|
||||||
TruncateIfNoLiftedHeapGrowth,
|
TruncateIfNoLiftedHeapGrowth,
|
||||||
GetAttributedVariableList,
|
GetAttributedVariableList,
|
||||||
@@ -186,9 +191,11 @@ pub enum SystemClauseType {
|
|||||||
GetAttrVarQueueBeyond,
|
GetAttrVarQueueBeyond,
|
||||||
GetBValue,
|
GetBValue,
|
||||||
GetClause,
|
GetClause,
|
||||||
|
GetContinuationChunk,
|
||||||
GetModuleClause,
|
GetModuleClause,
|
||||||
GetNextDBRef,
|
GetNextDBRef,
|
||||||
GetNextOpDBRef,
|
GetNextOpDBRef,
|
||||||
|
IsPartialString,
|
||||||
LookupDBRef,
|
LookupDBRef,
|
||||||
LookupOpDBRef,
|
LookupOpDBRef,
|
||||||
Halt,
|
Halt,
|
||||||
@@ -202,18 +209,23 @@ pub enum SystemClauseType {
|
|||||||
LiftedHeapLength,
|
LiftedHeapLength,
|
||||||
ModuleAssertDynamicPredicateToFront,
|
ModuleAssertDynamicPredicateToFront,
|
||||||
ModuleAssertDynamicPredicateToBack,
|
ModuleAssertDynamicPredicateToBack,
|
||||||
|
ModuleExists,
|
||||||
ModuleOf,
|
ModuleOf,
|
||||||
ModuleRetractClause,
|
ModuleRetractClause,
|
||||||
|
NextEP,
|
||||||
NoSuchPredicate,
|
NoSuchPredicate,
|
||||||
NumberToChars,
|
NumberToChars,
|
||||||
NumberToCodes,
|
NumberToCodes,
|
||||||
OpDeclaration,
|
OpDeclaration,
|
||||||
|
PartialStringTail,
|
||||||
|
PointsToContinuationResetMarker,
|
||||||
REPL(REPLCodePtr),
|
REPL(REPLCodePtr),
|
||||||
ReadQueryTerm,
|
ReadQueryTerm,
|
||||||
ReadTerm,
|
ReadTerm,
|
||||||
RedoAttrVarBindings,
|
RedoAttrVarBinding,
|
||||||
RemoveCallPolicyCheck,
|
RemoveCallPolicyCheck,
|
||||||
RemoveInferenceCounter,
|
RemoveInferenceCounter,
|
||||||
|
ResetContinuationMarker,
|
||||||
ResetGlobalVarAtKey,
|
ResetGlobalVarAtKey,
|
||||||
ResetGlobalVarAtOffset,
|
ResetGlobalVarAtOffset,
|
||||||
RetractClause,
|
RetractClause,
|
||||||
@@ -243,6 +255,7 @@ pub enum SystemClauseType {
|
|||||||
TermVariables,
|
TermVariables,
|
||||||
TruncateLiftedHeapTo,
|
TruncateLiftedHeapTo,
|
||||||
UnifyWithOccursCheck,
|
UnifyWithOccursCheck,
|
||||||
|
UnwindEnvironments,
|
||||||
UnwindStack,
|
UnwindStack,
|
||||||
Variant,
|
Variant,
|
||||||
WAMInstructions,
|
WAMInstructions,
|
||||||
@@ -256,14 +269,21 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"),
|
&SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"),
|
||||||
&SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"),
|
&SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"),
|
||||||
&SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"),
|
&SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"),
|
||||||
|
&SystemClauseType::AtEndOfExpansion => clause_name!("$at_end_of_expansion"),
|
||||||
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
|
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
|
||||||
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
|
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
|
||||||
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
|
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
|
||||||
|
&SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"),
|
||||||
&SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"),
|
&SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"),
|
||||||
|
&SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
|
||||||
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
||||||
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
||||||
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
|
|
||||||
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
||||||
|
&SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"),
|
||||||
|
&SystemClauseType::CloneAttributeGoals => clause_name!("$clone_attribute_goals"),
|
||||||
|
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
|
||||||
|
&SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"),
|
||||||
|
&SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"),
|
||||||
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
|
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
|
||||||
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
|
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
|
||||||
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
|
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
|
||||||
@@ -275,10 +295,11 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
|
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
|
||||||
clause_name!("$use_qualified_module_from_file")
|
clause_name!("$use_qualified_module_from_file")
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::ClearAttrVarBindings => clause_name!("$clear_attr_var_bindings"),
|
||||||
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
|
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
|
||||||
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
|
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
|
||||||
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
|
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
|
||||||
&SystemClauseType::DynamicModuleResolution => clause_name!("$module_call"),
|
&SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"),
|
||||||
&SystemClauseType::EnqueueAttributeGoal => clause_name!("$enqueue_attribute_goal"),
|
&SystemClauseType::EnqueueAttributeGoal => clause_name!("$enqueue_attribute_goal"),
|
||||||
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
|
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
|
||||||
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
|
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
|
||||||
@@ -289,6 +310,7 @@ impl SystemClauseType {
|
|||||||
clause_name!("$fetch_global_var_with_offset")
|
clause_name!("$fetch_global_var_with_offset")
|
||||||
}
|
}
|
||||||
&SystemClauseType::GetChar => clause_name!("$get_char"),
|
&SystemClauseType::GetChar => clause_name!("$get_char"),
|
||||||
|
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
|
||||||
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
|
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
|
||||||
clause_name!("$truncate_if_no_lh_growth")
|
clause_name!("$truncate_if_no_lh_growth")
|
||||||
}
|
}
|
||||||
@@ -300,6 +322,7 @@ impl SystemClauseType {
|
|||||||
clause_name!("$get_attr_var_queue_delim")
|
clause_name!("$get_attr_var_queue_delim")
|
||||||
}
|
}
|
||||||
&SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"),
|
&SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"),
|
||||||
|
&SystemClauseType::GetContinuationChunk => clause_name!("$get_cont_chunk"),
|
||||||
&SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"),
|
&SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"),
|
||||||
&SystemClauseType::GetLiftedHeapFromOffsetDiff => {
|
&SystemClauseType::GetLiftedHeapFromOffsetDiff => {
|
||||||
clause_name!("$get_lh_from_offset_diff")
|
clause_name!("$get_lh_from_offset_diff")
|
||||||
@@ -320,6 +343,8 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::InstallInferenceCounter => {
|
&SystemClauseType::InstallInferenceCounter => {
|
||||||
clause_name!("$install_inference_counter")
|
clause_name!("$install_inference_counter")
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::IsPartialString => clause_name!("$is_partial_string"),
|
||||||
|
&SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"),
|
||||||
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
|
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
|
||||||
&SystemClauseType::Maybe => clause_name!("maybe"),
|
&SystemClauseType::Maybe => clause_name!("maybe"),
|
||||||
&SystemClauseType::ModuleAssertDynamicPredicateToFront => {
|
&SystemClauseType::ModuleAssertDynamicPredicateToFront => {
|
||||||
@@ -329,12 +354,16 @@ impl SystemClauseType {
|
|||||||
clause_name!("$module_assertz")
|
clause_name!("$module_assertz")
|
||||||
}
|
}
|
||||||
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
|
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
|
||||||
|
&SystemClauseType::ModuleExists => clause_name!("$module_exists"),
|
||||||
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
||||||
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
||||||
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
||||||
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
||||||
|
&SystemClauseType::PointsToContinuationResetMarker => {
|
||||||
|
clause_name!("$points_to_cont_reset_marker")
|
||||||
|
}
|
||||||
&SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"),
|
&SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"),
|
||||||
&SystemClauseType::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"),
|
&SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"),
|
||||||
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
||||||
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
||||||
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
|
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
|
||||||
@@ -353,12 +382,14 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
|
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
|
||||||
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
|
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
|
||||||
&SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
|
&SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
|
||||||
|
&SystemClauseType::NextEP => clause_name!("$nextEP"),
|
||||||
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
|
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
|
||||||
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
|
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
|
||||||
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
|
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
|
||||||
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
|
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
|
||||||
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
|
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
|
||||||
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
|
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
|
||||||
|
&SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"),
|
||||||
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
|
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
|
||||||
&SystemClauseType::SetBall => clause_name!("$set_ball"),
|
&SystemClauseType::SetBall => clause_name!("$set_ball"),
|
||||||
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
|
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
|
||||||
@@ -368,6 +399,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::TermVariables => clause_name!("$term_variables"),
|
&SystemClauseType::TermVariables => clause_name!("$term_variables"),
|
||||||
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
|
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
|
||||||
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
|
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
|
||||||
|
&SystemClauseType::UnwindEnvironments => clause_name!("$unwind_environments"),
|
||||||
&SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
|
&SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
|
||||||
&SystemClauseType::Variant => clause_name!("$variant"),
|
&SystemClauseType::Variant => clause_name!("$variant"),
|
||||||
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
|
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
|
||||||
@@ -378,18 +410,26 @@ impl SystemClauseType {
|
|||||||
pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
|
pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
|
||||||
match (name, arity) {
|
match (name, arity) {
|
||||||
("$abolish_clause", 2) => Some(SystemClauseType::AbolishClause),
|
("$abolish_clause", 2) => Some(SystemClauseType::AbolishClause),
|
||||||
|
("$at_end_of_expansion", 0) => Some(SystemClauseType::AtEndOfExpansion),
|
||||||
("$atom_chars", 2) => Some(SystemClauseType::AtomChars),
|
("$atom_chars", 2) => Some(SystemClauseType::AtomChars),
|
||||||
("$atom_codes", 2) => Some(SystemClauseType::AtomCodes),
|
("$atom_codes", 2) => Some(SystemClauseType::AtomCodes),
|
||||||
("$atom_length", 2) => Some(SystemClauseType::AtomLength),
|
("$atom_length", 2) => Some(SystemClauseType::AtomLength),
|
||||||
("$abolish_module_clause", 3) => Some(SystemClauseType::AbolishModuleClause),
|
("$abolish_module_clause", 3) => Some(SystemClauseType::AbolishModuleClause),
|
||||||
|
("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister),
|
||||||
("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront),
|
("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront),
|
||||||
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
|
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
|
||||||
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
|
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
|
||||||
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
||||||
("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals),
|
("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals),
|
||||||
|
("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
|
||||||
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
||||||
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
("$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),
|
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
|
||||||
|
("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars),
|
||||||
|
("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString),
|
||||||
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
||||||
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
|
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
|
||||||
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
||||||
@@ -399,15 +439,21 @@ impl SystemClauseType {
|
|||||||
("$get_next_op_db_ref", 2) => Some(SystemClauseType::GetNextOpDBRef),
|
("$get_next_op_db_ref", 2) => Some(SystemClauseType::GetNextOpDBRef),
|
||||||
("$lookup_db_ref", 3) => Some(SystemClauseType::LookupDBRef),
|
("$lookup_db_ref", 3) => Some(SystemClauseType::LookupDBRef),
|
||||||
("$lookup_op_db_ref", 4) => Some(SystemClauseType::LookupOpDBRef),
|
("$lookup_op_db_ref", 4) => Some(SystemClauseType::LookupOpDBRef),
|
||||||
("$module_call", 2) => Some(SystemClauseType::DynamicModuleResolution),
|
("$module_call", _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)),
|
||||||
("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
|
("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
|
||||||
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
|
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
|
||||||
|
("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail),
|
||||||
|
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
|
||||||
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
|
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
|
||||||
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
|
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
|
||||||
("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals),
|
("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals),
|
||||||
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
||||||
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
||||||
("$get_char", 1) => Some(SystemClauseType::GetChar),
|
("$get_char", 1) => Some(SystemClauseType::GetChar),
|
||||||
|
("$points_to_cont_reset_marker", 1) => {
|
||||||
|
Some(SystemClauseType::PointsToContinuationResetMarker)
|
||||||
|
}
|
||||||
|
("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
|
||||||
("$truncate_if_no_lh_growth", 1) => {
|
("$truncate_if_no_lh_growth", 1) => {
|
||||||
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
|
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
|
||||||
}
|
}
|
||||||
@@ -428,6 +474,7 @@ impl SystemClauseType {
|
|||||||
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
|
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
|
||||||
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
|
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
|
||||||
("$maybe", 0) => Some(SystemClauseType::Maybe),
|
("$maybe", 0) => Some(SystemClauseType::Maybe),
|
||||||
|
("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
|
||||||
("$module_of", 2) => Some(SystemClauseType::ModuleOf),
|
("$module_of", 2) => Some(SystemClauseType::ModuleOf),
|
||||||
("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
|
("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
|
||||||
("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic),
|
("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic),
|
||||||
@@ -435,7 +482,7 @@ impl SystemClauseType {
|
|||||||
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
|
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
|
||||||
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
|
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
|
||||||
("$op", 3) => Some(SystemClauseType::OpDeclaration),
|
("$op", 3) => Some(SystemClauseType::OpDeclaration),
|
||||||
("$redo_attr_var_bindings", 0) => Some(SystemClauseType::RedoAttrVarBindings),
|
("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding),
|
||||||
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
|
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
|
||||||
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
|
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
|
||||||
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
|
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
|
||||||
@@ -447,13 +494,16 @@ impl SystemClauseType {
|
|||||||
("$get_attr_var_queue_beyond", 2) => Some(SystemClauseType::GetAttrVarQueueBeyond),
|
("$get_attr_var_queue_beyond", 2) => Some(SystemClauseType::GetAttrVarQueueBeyond),
|
||||||
("$get_attr_var_queue_delim", 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter),
|
("$get_attr_var_queue_delim", 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter),
|
||||||
("$get_ball", 1) => Some(SystemClauseType::GetBall),
|
("$get_ball", 1) => Some(SystemClauseType::GetBall),
|
||||||
|
("$get_cont_chunk", 3) => Some(SystemClauseType::GetContinuationChunk),
|
||||||
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
||||||
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
||||||
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
||||||
("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar),
|
("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar),
|
||||||
|
("$nextEP", 3) => Some(SystemClauseType::NextEP),
|
||||||
("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
|
("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
|
||||||
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
|
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
|
||||||
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
||||||
|
("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
|
||||||
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
|
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
|
||||||
("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
|
("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
|
||||||
("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
|
("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
|
||||||
@@ -467,6 +517,7 @@ impl SystemClauseType {
|
|||||||
("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset),
|
("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset),
|
||||||
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
|
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
|
||||||
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
||||||
|
("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments),
|
||||||
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
||||||
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
|
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
|
||||||
("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
|
("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
|
||||||
@@ -499,7 +550,6 @@ pub enum BuiltInClauseType {
|
|||||||
KeySort,
|
KeySort,
|
||||||
Nl,
|
Nl,
|
||||||
NotEq,
|
NotEq,
|
||||||
PartialString,
|
|
||||||
Read,
|
Read,
|
||||||
Sort,
|
Sort,
|
||||||
}
|
}
|
||||||
@@ -531,7 +581,6 @@ impl BuiltInClauseType {
|
|||||||
&BuiltInClauseType::KeySort => clause_name!("keysort"),
|
&BuiltInClauseType::KeySort => clause_name!("keysort"),
|
||||||
&BuiltInClauseType::Nl => clause_name!("nl"),
|
&BuiltInClauseType::Nl => clause_name!("nl"),
|
||||||
&BuiltInClauseType::NotEq => clause_name!("\\=="),
|
&BuiltInClauseType::NotEq => clause_name!("\\=="),
|
||||||
&BuiltInClauseType::PartialString => clause_name!("partial_string"),
|
|
||||||
&BuiltInClauseType::Read => clause_name!("read"),
|
&BuiltInClauseType::Read => clause_name!("read"),
|
||||||
&BuiltInClauseType::Sort => clause_name!("sort"),
|
&BuiltInClauseType::Sort => clause_name!("sort"),
|
||||||
}
|
}
|
||||||
@@ -552,7 +601,6 @@ impl BuiltInClauseType {
|
|||||||
&BuiltInClauseType::KeySort => 2,
|
&BuiltInClauseType::KeySort => 2,
|
||||||
&BuiltInClauseType::NotEq => 2,
|
&BuiltInClauseType::NotEq => 2,
|
||||||
&BuiltInClauseType::Nl => 0,
|
&BuiltInClauseType::Nl => 0,
|
||||||
&BuiltInClauseType::PartialString => 1,
|
|
||||||
&BuiltInClauseType::Read => 1,
|
&BuiltInClauseType::Read => 1,
|
||||||
&BuiltInClauseType::Sort => 2,
|
&BuiltInClauseType::Sort => 2,
|
||||||
}
|
}
|
||||||
@@ -574,8 +622,8 @@ impl ClauseType {
|
|||||||
|
|
||||||
pub fn name(&self) -> ClauseName {
|
pub fn name(&self) -> ClauseName {
|
||||||
match self {
|
match self {
|
||||||
&ClauseType::CallN => clause_name!("call"),
|
|
||||||
&ClauseType::BuiltIn(ref built_in) => built_in.name(),
|
&ClauseType::BuiltIn(ref built_in) => built_in.name(),
|
||||||
|
&ClauseType::CallN => clause_name!("call"),
|
||||||
&ClauseType::Hook(ref hook) => hook.name(),
|
&ClauseType::Hook(ref hook) => hook.name(),
|
||||||
&ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()),
|
&ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()),
|
||||||
&ClauseType::Op(ref name, ..) => name.clone(),
|
&ClauseType::Op(ref name, ..) => name.clone(),
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ use std::rc::Rc;
|
|||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
pub struct CodeGenerator<TermMarker> {
|
pub struct CodeGenerator<TermMarker> {
|
||||||
flags: MachineFlags,
|
|
||||||
marker: TermMarker,
|
marker: TermMarker,
|
||||||
pub var_count: IndexMap<Rc<Var>, usize>,
|
pub var_count: IndexMap<Rc<Var>, usize>,
|
||||||
non_counted_bt: bool,
|
non_counted_bt: bool,
|
||||||
@@ -107,12 +106,11 @@ impl<'a> ConjunctInfo<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
||||||
pub fn new(non_counted_bt: bool, flags: MachineFlags) -> Self {
|
pub fn new(non_counted_bt: bool) -> Self {
|
||||||
CodeGenerator {
|
CodeGenerator {
|
||||||
marker: Allocator::new(),
|
marker: Allocator::new(),
|
||||||
var_count: IndexMap::new(),
|
var_count: IndexMap::new(),
|
||||||
non_counted_bt,
|
non_counted_bt,
|
||||||
flags,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,11 +279,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
|
|
||||||
fn collect_var_data(&mut self, mut iter: ChunkedIterator<'a>) -> ConjunctInfo<'a> {
|
fn collect_var_data(&mut self, mut iter: ChunkedIterator<'a>) -> ConjunctInfo<'a> {
|
||||||
let mut vs = VariableFixtures::new();
|
let mut vs = VariableFixtures::new();
|
||||||
|
|
||||||
while let Some((chunk_num, lt_arity, chunked_terms)) = iter.next() {
|
while let Some((chunk_num, lt_arity, chunked_terms)) = iter.next() {
|
||||||
for (i, chunked_term) in chunked_terms.iter().enumerate() {
|
for (i, chunked_term) in chunked_terms.iter().enumerate() {
|
||||||
let term_loc = match chunked_term {
|
let term_loc = match chunked_term {
|
||||||
&ChunkedTerm::HeadClause(..) =>
|
&ChunkedTerm::HeadClause(..) =>
|
||||||
GenContext::Head,
|
GenContext::Head,
|
||||||
&ChunkedTerm::BodyTerm(_) => {
|
&ChunkedTerm::BodyTerm(_) => {
|
||||||
if i < chunked_terms.len() - 1 {
|
if i < chunked_terms.len() - 1 {
|
||||||
@@ -435,7 +433,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
&InlinedClauseType::IsString(..) => match terms[0].as_ref() {
|
&InlinedClauseType::IsString(..) => match terms[0].as_ref() {
|
||||||
&Term::Constant(_, Constant::String(_)) => {
|
&Term::Constant(_, Constant::String(..)) => {
|
||||||
code.push(succeed!());
|
code.push(succeed!());
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
@@ -459,8 +457,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
&InlinedClauseType::IsInteger(..) => match terms[0].as_ref() {
|
&InlinedClauseType::IsInteger(..) => match terms[0].as_ref() {
|
||||||
&Term::Constant(_, Constant::CharCode(_))
|
&Term::Constant(_, Constant::Integer(_)) => {
|
||||||
| &Term::Constant(_, Constant::Integer(_)) => {
|
|
||||||
code.push(succeed!());
|
code.push(succeed!());
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
@@ -483,13 +480,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
code.push(is_var!(r));
|
code.push(is_var!(r));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&InlinedClauseType::IsPartialString(..) => match terms[0].as_ref() {
|
|
||||||
&Term::Var(ref vr, ref name) => {
|
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
|
||||||
code.push(is_partial_string!(r));
|
|
||||||
}
|
|
||||||
_ => code.push(fail!()),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -715,7 +705,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
let iter = ChunkedIterator::from_rule_body(p1, clauses);
|
let iter = ChunkedIterator::from_rule_body(p1, clauses);
|
||||||
self.compile_seq(iter, &conjunct_info, &mut code, false)?;
|
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, &self.marker, &mut code);
|
||||||
|
|
||||||
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
|
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
|
||||||
Ok(code)
|
Ok(code)
|
||||||
@@ -867,7 +857,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
clauses: &'b [PredicateClause],
|
clauses: &'b [PredicateClause],
|
||||||
) -> Result<Code, ParserError> {
|
) -> Result<Code, ParserError> {
|
||||||
let mut code_body = Vec::new();
|
let mut code_body = Vec::new();
|
||||||
let mut code_offsets = CodeOffsets::new(self.flags);
|
let mut code_offsets = CodeOffsets::new();
|
||||||
|
|
||||||
let num_clauses = clauses.len();
|
let num_clauses = clauses.len();
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use indexmap::IndexMap;
|
|||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub type PredicateKey = (ClauseName, usize); // name, arity.
|
pub type PredicateKey = (ClauseName, usize); // name, arity.
|
||||||
@@ -30,26 +31,6 @@ pub enum TopLevel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TopLevel {
|
impl TopLevel {
|
||||||
pub fn name(&self) -> Option<ClauseName> {
|
|
||||||
match self {
|
|
||||||
&TopLevel::Declaration(_) => None,
|
|
||||||
&TopLevel::Fact(ref term, ..) => term.name(),
|
|
||||||
&TopLevel::Predicate(ref clauses) => clauses.0.first().and_then(|ref term| term.name()),
|
|
||||||
&TopLevel::Query(_) => None,
|
|
||||||
&TopLevel::Rule(Rule { ref head, .. }, ..) => Some(head.0.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&TopLevel::Declaration(_) => 0,
|
|
||||||
&TopLevel::Fact(ref term, ..) => term.arity(),
|
|
||||||
&TopLevel::Predicate(ref clauses) => clauses.0.first().map(|t| t.arity()).unwrap_or(0),
|
|
||||||
&TopLevel::Query(_) => 0,
|
|
||||||
&TopLevel::Rule(Rule { ref head, .. }, ..) => head.1.len(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_end_of_file_atom(&self) -> bool {
|
pub fn is_end_of_file_atom(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&TopLevel::Fact(Term::Constant(_, Constant::Atom(ref name, _)), ..) => {
|
&TopLevel::Fact(Term::Constant(_, Constant::Atom(ref name, _)), ..) => {
|
||||||
@@ -132,6 +113,216 @@ impl Predicate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum ListingSource {
|
||||||
|
File(ClauseName, PathBuf), // filename, path
|
||||||
|
User,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ListingSource {
|
||||||
|
pub fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self {
|
||||||
|
ListingSource::File(filename, path_buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> ClauseName {
|
||||||
|
match self {
|
||||||
|
ListingSource::File(ref filename, _) => filename.clone(),
|
||||||
|
ListingSource::User => clause_name!("[user]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(&self) -> PathBuf {
|
||||||
|
match self {
|
||||||
|
ListingSource::File(_, ref path) => path.clone(),
|
||||||
|
ListingSource::User => std::env::current_dir().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolved_term_and_module(term: &Term) -> Option<(ClauseName, ClauseName)>
|
||||||
|
{
|
||||||
|
match term {
|
||||||
|
Term::Clause(_, ref name, ref terms, _) => {
|
||||||
|
if name.as_str() == ":" && terms.len() == 2 {
|
||||||
|
let module_name = match terms[0].as_ref() {
|
||||||
|
&Term::Constant(_, Constant::Atom(ref module_name, _)) => {
|
||||||
|
module_name.clone()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Some((name.owning_module(), name.clone()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match terms[1].as_ref() {
|
||||||
|
Term::Clause(_, ref name, ..)
|
||||||
|
| Term::Constant(_, Constant::Atom(ref name, ..)) => {
|
||||||
|
return Some((module_name, name.clone()));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((name.owning_module(), name.clone()))
|
||||||
|
} else {
|
||||||
|
Some((name.owning_module(), name.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Term::Constant(_, Constant::Atom(ref name, _)) => {
|
||||||
|
Some((name.owning_module(), name.clone()))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolved_term_arity(term: &Term) -> usize
|
||||||
|
{
|
||||||
|
match term {
|
||||||
|
Term::Clause(_, ref name, ref terms, _) => {
|
||||||
|
if name.as_str() == ":" && terms.len() == 2 {
|
||||||
|
match terms[0].as_ref() {
|
||||||
|
&Term::Constant(_, Constant::Atom(..)) => {
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match terms[1].as_ref() {
|
||||||
|
Term::Clause(_, _, ref terms, _) => {
|
||||||
|
terms.len()
|
||||||
|
}
|
||||||
|
Term::Constant(_, Constant::Atom(..)) => {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
terms.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ClauseConsistency {
|
||||||
|
fn is_consistent(&self, clauses: &Vec<PredicateClause>) -> bool {
|
||||||
|
match clauses.first() {
|
||||||
|
Some(ref cl) => {
|
||||||
|
self.name_and_module() == cl.name_and_module() && self.arity() == cl.arity()
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>;
|
||||||
|
fn arity(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Of course '$current_module$' isn't the name of the current
|
||||||
|
* module. It'll do if no module is explicitly specified through
|
||||||
|
* (:)/2.
|
||||||
|
*/
|
||||||
|
impl ClauseConsistency for Term {
|
||||||
|
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Term::Clause(_, ref name, ref terms, _) =>
|
||||||
|
match name.as_str() {
|
||||||
|
":-" => {
|
||||||
|
match terms.len() {
|
||||||
|
1 => None, // a declaration.
|
||||||
|
2 => resolved_term_and_module(&terms[0]),
|
||||||
|
_ => Some((name.owning_module(), clause_name!(":-"))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
resolved_term_and_module(self)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Term::Constant(_, Constant::Atom(ref name, _)) => {
|
||||||
|
Some((name.owning_module(), name.clone()))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arity(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Term::Clause(_, ref name, ref terms, _) =>
|
||||||
|
match name.as_str() {
|
||||||
|
":-" => {
|
||||||
|
match terms.len() {
|
||||||
|
1 => 0,
|
||||||
|
2 => resolved_term_arity(&terms[0]),
|
||||||
|
_ => terms.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
resolved_term_arity(self)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClauseConsistency for Rule {
|
||||||
|
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
|
||||||
|
Some((self.head.0.owning_module(), self.head.0.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arity(&self) -> usize {
|
||||||
|
self.head.1.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClauseConsistency for PredicateClause {
|
||||||
|
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
|
||||||
|
match self {
|
||||||
|
&PredicateClause::Fact(ref term, ..) => {
|
||||||
|
term.name_and_module()
|
||||||
|
.map(|(_, name)| (name.owning_module(), name))
|
||||||
|
}
|
||||||
|
&PredicateClause::Rule(ref rule, ..) => {
|
||||||
|
rule.name_and_module()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arity(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
&PredicateClause::Fact(ref term, ..) => {
|
||||||
|
term.arity()
|
||||||
|
}
|
||||||
|
&PredicateClause::Rule(ref rule, ..) => {
|
||||||
|
rule.arity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClauseConsistency for Predicate {
|
||||||
|
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
|
||||||
|
self.0.first().and_then(|clause| clause.name_and_module())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arity(&self) -> usize {
|
||||||
|
self.0.first().map(|clause| clause.arity()).unwrap_or(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
|
pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -150,8 +341,24 @@ impl PredicateClause {
|
|||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
pub fn arity(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
&PredicateClause::Fact(ref term, ..) => term.arity(),
|
&PredicateClause::Fact(ref term, ..) => {
|
||||||
&PredicateClause::Rule(ref rule, ..) => rule.head.1.len(),
|
term.arity()
|
||||||
|
}
|
||||||
|
&PredicateClause::Rule(ref rule, ..) => {
|
||||||
|
if rule.head.0.as_str() == ":" && rule.head.1.len() == 2 {
|
||||||
|
match (rule.head.1)[0].as_ref() {
|
||||||
|
&Term::Constant(_, Constant::Atom(..)) => {
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(rule.head.1)[1].arity()
|
||||||
|
} else {
|
||||||
|
rule.head.1.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,6 +376,14 @@ pub enum ModuleSource {
|
|||||||
File(ClauseName),
|
File(ClauseName),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum MultiFileIndicator {
|
||||||
|
LocalScoped(ClauseName, usize), // name, arity
|
||||||
|
ModuleScoped(ScopedPredicateKey),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Declaration {
|
pub enum Declaration {
|
||||||
Dynamic(ClauseName, usize), // name, arity
|
Dynamic(ClauseName, usize), // name, arity
|
||||||
@@ -176,10 +391,11 @@ pub enum Declaration {
|
|||||||
Hook(CompileTimeHook, PredicateClause, VecDeque<TopLevel>),
|
Hook(CompileTimeHook, PredicateClause, VecDeque<TopLevel>),
|
||||||
ModuleInitialization(Vec<QueryTerm>, VecDeque<TopLevel>), // goal
|
ModuleInitialization(Vec<QueryTerm>, VecDeque<TopLevel>), // goal
|
||||||
Module(ModuleDecl),
|
Module(ModuleDecl),
|
||||||
|
MultiFile(MultiFileIndicator),
|
||||||
NonCountedBacktracking(ClauseName, usize), // name, arity
|
NonCountedBacktracking(ClauseName, usize), // name, arity
|
||||||
Op(OpDecl),
|
Op(OpDecl),
|
||||||
UseModule(ModuleSource),
|
UseModule(ModuleSource),
|
||||||
UseQualifiedModule(ModuleSource, Vec<PredicateKey>),
|
UseQualifiedModule(ModuleSource, Vec<ModuleExport>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Declaration {
|
impl Declaration {
|
||||||
@@ -216,15 +432,20 @@ impl OpDecl {
|
|||||||
self.insert_into_op_dir(clause_name!(""), op_dir, 0);
|
self.insert_into_op_dir(clause_name!(""), op_dir, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_into_op_dir(&self, module: ClauseName, op_dir: &mut OpDir, prec: usize) {
|
#[inline]
|
||||||
let (spec, name) = (self.1, self.2.clone());
|
pub fn fixity(&self) -> Fixity {
|
||||||
|
match self.1 {
|
||||||
let fixity = match spec {
|
|
||||||
XFY | XFX | YFX => Fixity::In,
|
XFY | XFX | YFX => Fixity::In,
|
||||||
XF | YF => Fixity::Post,
|
XF | YF => Fixity::Post,
|
||||||
FX | FY => Fixity::Pre,
|
FX | FY => Fixity::Pre,
|
||||||
_ => return,
|
_ => unreachable!()
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_into_op_dir(&self, module: ClauseName, op_dir: &mut OpDir, prec: usize) {
|
||||||
|
let (spec, name) = (self.1, self.2.clone());
|
||||||
|
|
||||||
|
let fixity = self.fixity();
|
||||||
|
|
||||||
match op_dir.get(&(name.clone(), fixity)) {
|
match op_dir.get(&(name.clone(), fixity)) {
|
||||||
Some(cell) => {
|
Some(cell) => {
|
||||||
@@ -281,11 +502,11 @@ pub fn fetch_op_spec(
|
|||||||
op_dir: &OpDir,
|
op_dir: &OpDir,
|
||||||
) -> Option<SharedOpDesc> {
|
) -> Option<SharedOpDesc> {
|
||||||
if let Some(ref op_desc) = &spec {
|
if let Some(ref op_desc) = &spec {
|
||||||
if op_desc.arity() != arity {
|
if op_desc.arity() != arity {
|
||||||
/* it's possible to extend operator functors with
|
/* it's possible to extend operator functors with
|
||||||
* additional terms. When that happens,
|
* additional terms. When that happens,
|
||||||
* void the op_spec by returning None. */
|
* void the op_spec by returning None. */
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,10 +543,16 @@ pub fn fetch_op_spec(
|
|||||||
|
|
||||||
pub type ModuleDir = IndexMap<ClauseName, Module>;
|
pub type ModuleDir = IndexMap<ClauseName, Module>;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub enum ModuleExport {
|
||||||
|
OpDecl(OpDecl),
|
||||||
|
PredicateKey(PredicateKey),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ModuleDecl {
|
pub struct ModuleDecl {
|
||||||
pub name: ClauseName,
|
pub name: ClauseName,
|
||||||
pub exports: Vec<PredicateKey>,
|
pub exports: Vec<ModuleExport>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
@@ -333,12 +560,16 @@ pub struct Module {
|
|||||||
pub module_decl: ModuleDecl,
|
pub module_decl: ModuleDecl,
|
||||||
pub code_dir: CodeDir,
|
pub code_dir: CodeDir,
|
||||||
pub op_dir: OpDir,
|
pub op_dir: OpDir,
|
||||||
|
pub term_dir: TermDir, // this contains multifile predicates.
|
||||||
pub term_expansions: (Predicate, VecDeque<TopLevel>),
|
pub term_expansions: (Predicate, VecDeque<TopLevel>),
|
||||||
pub goal_expansions: (Predicate, VecDeque<TopLevel>),
|
pub goal_expansions: (Predicate, VecDeque<TopLevel>),
|
||||||
pub user_term_expansions: (Predicate, VecDeque<TopLevel>), // term expansions inherited from the user scope.
|
pub user_term_expansions: (Predicate, VecDeque<TopLevel>), // term expansions inherited from the user scope.
|
||||||
pub user_goal_expansions: (Predicate, VecDeque<TopLevel>), // same for goal_expansions.
|
pub user_goal_expansions: (Predicate, VecDeque<TopLevel>), // same for goal_expansions.
|
||||||
|
pub local_term_expansions: (Predicate, VecDeque<TopLevel>), // expansions local to the module.
|
||||||
|
pub local_goal_expansions: (Predicate, VecDeque<TopLevel>),
|
||||||
pub inserted_expansions: bool, // has the module been successfully inserted into toplevel??
|
pub inserted_expansions: bool, // has the module been successfully inserted into toplevel??
|
||||||
pub is_impromptu_module: bool,
|
pub is_impromptu_module: bool,
|
||||||
|
pub listing_src: ListingSource,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
|||||||
@@ -28,14 +28,19 @@ impl<'a> HCPreOrderIterator<'a> {
|
|||||||
|
|
||||||
fn follow_heap(&mut self, h: usize) -> Addr {
|
fn follow_heap(&mut self, h: usize) -> Addr {
|
||||||
match &self.machine_st.heap[h] {
|
match &self.machine_st.heap[h] {
|
||||||
&HeapCellValue::NamedStr(arity, _, _) => {
|
HeapCellValue::NamedStr(arity, _, _) => {
|
||||||
for idx in (1..arity + 1).rev() {
|
for idx in (1..arity + 1).rev() {
|
||||||
self.state_stack.push(Addr::HeapCell(h + idx));
|
self.state_stack.push(Addr::HeapCell(h + idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
Addr::HeapCell(h)
|
Addr::Str(h)
|
||||||
|
}
|
||||||
|
HeapCellValue::Addr(ref a) => {
|
||||||
|
self.follow(a.clone())
|
||||||
|
}
|
||||||
|
HeapCellValue::PartialString(_) => {
|
||||||
|
self.follow(Addr::PStrLocation(h, 0))
|
||||||
}
|
}
|
||||||
&HeapCellValue::Addr(ref a) => self.follow(a.clone()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,39 +51,63 @@ impl<'a> HCPreOrderIterator<'a> {
|
|||||||
let da = self.machine_st.store(self.machine_st.deref(addr));
|
let da = self.machine_st.store(self.machine_st.deref(addr));
|
||||||
|
|
||||||
match da {
|
match da {
|
||||||
Addr::Con(Constant::String(ref s)) => {
|
Addr::Con(Constant::String(n, s)) => {
|
||||||
match self.machine_st.machine_flags().double_quotes {
|
if !self.machine_st.machine_flags().double_quotes.is_atom() {
|
||||||
DoubleQuotes::Chars => {
|
if s.len() > n {
|
||||||
if let Some(c) = s.head() {
|
if let Some(c) = s[n ..].chars().next() {
|
||||||
let tail = s.tail();
|
let o = c.len_utf8();
|
||||||
|
|
||||||
self.state_stack.push(Addr::Con(Constant::String(tail)));
|
self.state_stack.push(Addr::Con(Constant::String(n+o, s.clone())));
|
||||||
self.state_stack.push(Addr::Con(Constant::Char(c)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DoubleQuotes::Codes => {
|
|
||||||
if let Some(c) = s.head() {
|
|
||||||
let tail = s.tail();
|
|
||||||
|
|
||||||
self.state_stack.push(Addr::Con(Constant::String(tail)));
|
if self.machine_st.machine_flags().double_quotes.is_codes() {
|
||||||
self.state_stack
|
self.state_stack.push(Addr::Con(Constant::CharCode(c as u32)));
|
||||||
.push(Addr::Con(Constant::CharCode(c as u8)));
|
} else {
|
||||||
|
self.state_stack.push(Addr::Con(Constant::Char(c)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return Addr::Con(Constant::EmptyList);
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Addr::Con(Constant::String(s.clone()))
|
Addr::Con(Constant::String(n, s))
|
||||||
|
}
|
||||||
|
Addr::Con(_) | Addr::DBRef(_) => {
|
||||||
|
da
|
||||||
}
|
}
|
||||||
Addr::Con(_) | Addr::DBRef(_) => da,
|
|
||||||
Addr::Lis(a) => {
|
Addr::Lis(a) => {
|
||||||
self.state_stack.push(Addr::HeapCell(a + 1));
|
self.state_stack.push(Addr::HeapCell(a + 1));
|
||||||
self.state_stack.push(Addr::HeapCell(a));
|
self.state_stack.push(Addr::HeapCell(a));
|
||||||
|
|
||||||
da
|
da
|
||||||
}
|
}
|
||||||
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => da,
|
Addr::PStrLocation(h, n) => {
|
||||||
Addr::Str(s) => self.follow_heap(s), // record terms of structure.
|
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() {
|
||||||
|
self.state_stack.push(Addr::PStrLocation(h, n + c.len_utf8()));
|
||||||
|
} else {
|
||||||
|
self.state_stack.push(Addr::PStrTail(h, n + c.len_utf8()));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state_stack.push(Addr::Con(Constant::Char(c)));
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr::PStrLocation(h, n)
|
||||||
|
}
|
||||||
|
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::PStrTail(..) => {
|
||||||
|
da
|
||||||
|
}
|
||||||
|
Addr::Str(s) => {
|
||||||
|
self.follow_heap(s) // record terms of structure.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,11 +117,39 @@ impl<'a> Iterator for HCPreOrderIterator<'a> {
|
|||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.state_stack.pop().map(|a| match self.follow(a) {
|
self.state_stack.pop().map(|a| match self.follow(a) {
|
||||||
Addr::HeapCell(h) => self.machine_st.heap[h].clone(),
|
Addr::HeapCell(h) => {
|
||||||
Addr::StackCell(fr, sc) => {
|
HeapCellValue::Addr(self.machine_st.heap[h].as_addr(h))
|
||||||
HeapCellValue::Addr(self.machine_st.and_stack[fr][sc].clone())
|
}
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
da => HeapCellValue::Addr(da),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use prolog_parser::ast::*;
|
use prolog_parser::ast::*;
|
||||||
use prolog_parser::string_list::*;
|
|
||||||
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::prolog::clause_types::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::prolog::forms::*;
|
||||||
@@ -12,7 +11,7 @@ use crate::prolog::rug::Integer;
|
|||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::iter::once;
|
use std::iter::{FromIterator, once};
|
||||||
use std::ops::{Range, RangeFrom};
|
use std::ops::{Range, RangeFrom};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@@ -147,7 +146,10 @@ fn char_to_string(c: char) -> String {
|
|||||||
'\u{0c}' => "\\f".to_string(), // UTF-8 form feed
|
'\u{0c}' => "\\f".to_string(), // UTF-8 form feed
|
||||||
'\u{08}' => "\\b".to_string(), // UTF-8 backspace
|
'\u{08}' => "\\b".to_string(), // UTF-8 backspace
|
||||||
'\u{07}' => "\\a".to_string(), // UTF-8 alert
|
'\u{07}' => "\\a".to_string(), // UTF-8 alert
|
||||||
'\x20'..='\x7e' => c.to_string(),
|
'\u{a0}' ..= '\u{d6}' => c.to_string(),
|
||||||
|
'\u{d8}' ..= '\u{f6}' => c.to_string(),
|
||||||
|
'\u{f8}' ..= '\u{74f}' => c.to_string(),
|
||||||
|
'\x20' ..= '\x7e' => c.to_string(),
|
||||||
_ => format!("\\x{:x}\\", c as u32),
|
_ => format!("\\x{:x}\\", c as u32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -614,10 +616,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match addr {
|
match addr {
|
||||||
Addr::AttrVar(h) => Some(format!("_{}", h + 1)),
|
Addr::AttrVar(h) => {
|
||||||
Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) => Some(format!("_{}", h)),
|
Some(format!("_{}", h))
|
||||||
Addr::StackCell(fr, sc) => Some(format!("_s_{}_{}", fr, sc)),
|
}
|
||||||
_ => None,
|
Addr::HeapCell(h) | Addr::Lis(h) | Addr::Str(h) | Addr::PStrTail(h, _) => {
|
||||||
|
Some(format!("_{}", h))
|
||||||
|
}
|
||||||
|
Addr::StackCell(fr, sc) => {
|
||||||
|
Some(format!("_s_{}_{}", fr, sc))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -786,12 +796,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Constant::CharCode(c) => {
|
||||||
|
self.append_str(&format!("{}", c as u32));
|
||||||
|
}
|
||||||
Constant::Char(c) if non_quoted_token(once(c)) => {
|
Constant::Char(c) if non_quoted_token(once(c)) => {
|
||||||
let c = char_to_string(c);
|
let c = char_to_string(c);
|
||||||
|
|
||||||
push_space_if_amb!(self, &c, {
|
push_space_if_amb!(self, &c, {
|
||||||
self.append_str(c.as_str());
|
self.append_str(c.as_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Constant::Char(c) => {
|
Constant::Char(c) => {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
@@ -803,50 +816,38 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
} else {
|
} else {
|
||||||
result += &char_to_string(c);
|
result += &char_to_string(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
push_space_if_amb!(self, &result, {
|
push_space_if_amb!(self, &result, {
|
||||||
self.append_str(result.as_str());
|
self.append_str(result.as_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Constant::CharCode(c) => self.append_str(&format!("{}", c)),
|
Constant::CutPoint(b) => self.append_str(&format!("{}", b)),
|
||||||
Constant::EmptyList => self.append_str("[]"),
|
Constant::EmptyList => self.append_str("[]"),
|
||||||
Constant::Integer(n) => self.print_number(Number::Integer(n), op),
|
Constant::Integer(n) => self.print_number(Number::Integer(n), op),
|
||||||
Constant::Float(n) => self.print_number(Number::Float(n), op),
|
Constant::Float(n) => self.print_number(Number::Float(n), op),
|
||||||
Constant::Rational(n) => self.print_number(Number::Rational(n), op),
|
Constant::Rational(n) => self.print_number(Number::Rational(n), op),
|
||||||
Constant::String(s) => self.print_string(s),
|
Constant::String(n, s) => self.print_string(n, s),
|
||||||
Constant::Usize(i) => self.append_str(&format!("u{}", i)),
|
Constant::Usize(i) => self.append_str(&format!("u{}", i)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_string(&mut self, s: StringList) {
|
fn print_string(&mut self, offset: usize, s: Rc<String>) {
|
||||||
match self.machine_st.machine_flags().double_quotes {
|
if !self.machine_st.machine_flags().double_quotes.is_atom() {
|
||||||
DoubleQuotes::Chars | DoubleQuotes::Codes => {
|
if !s[offset ..].is_empty() {
|
||||||
if !s.is_empty() {
|
if self.ignore_ops {
|
||||||
if self.ignore_ops {
|
self.format_struct(2, clause_name!("."));
|
||||||
self.format_struct(2, clause_name!("."));
|
} else {
|
||||||
} else {
|
self.push_list();
|
||||||
self.push_list();
|
|
||||||
}
|
|
||||||
} else if s.is_expandable() {
|
|
||||||
if !self.at_cdr("|_") {
|
|
||||||
self.push_char('_');
|
|
||||||
}
|
|
||||||
} else if !self.at_cdr("") {
|
|
||||||
self.append_str("[]");
|
|
||||||
}
|
}
|
||||||
|
} else if !self.at_cdr("") {
|
||||||
|
self.append_str("[]");
|
||||||
}
|
}
|
||||||
DoubleQuotes::Atom => {
|
} else {
|
||||||
let borrowed_str = s.borrow();
|
let atom = String::from_iter(s[offset ..].chars().map(char_to_string));
|
||||||
let mut atom = String::new();
|
|
||||||
|
|
||||||
for c in borrowed_str[s.cursor()..].chars() {
|
self.push_char('"');
|
||||||
atom += &char_to_string(c);
|
self.append_str(&atom);
|
||||||
}
|
self.push_char('"');
|
||||||
|
|
||||||
self.push_char('"');
|
|
||||||
self.append_str(&atom);
|
|
||||||
self.push_char('"');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -951,7 +952,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
HeapCellValue::Addr(Addr::Con(c)) => self.print_constant(c, &op),
|
HeapCellValue::Addr(Addr::Con(c)) => self.print_constant(c, &op),
|
||||||
HeapCellValue::Addr(Addr::Lis(_)) => {
|
HeapCellValue::Addr(Addr::Lis(_)) | HeapCellValue::Addr(Addr::PStrLocation(..)) => {
|
||||||
if self.ignore_ops {
|
if self.ignore_ops {
|
||||||
self.format_struct(2, clause_name!("."));
|
self.format_struct(2, clause_name!("."));
|
||||||
} else {
|
} else {
|
||||||
@@ -965,6 +966,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
// This is the partial string case. We never clone a partial string
|
||||||
|
// for printing purposes, so.. this.
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,16 +15,14 @@ enum IntIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct CodeOffsets {
|
pub struct CodeOffsets {
|
||||||
flags: MachineFlags,
|
|
||||||
pub constants: IndexMap<Constant, ThirdLevelIndex>,
|
pub constants: IndexMap<Constant, ThirdLevelIndex>,
|
||||||
pub lists: ThirdLevelIndex,
|
pub lists: ThirdLevelIndex,
|
||||||
pub structures: IndexMap<(ClauseName, usize), ThirdLevelIndex>,
|
pub structures: IndexMap<(ClauseName, usize), ThirdLevelIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeOffsets {
|
impl CodeOffsets {
|
||||||
pub fn new(flags: MachineFlags) -> Self {
|
pub fn new() -> Self {
|
||||||
CodeOffsets {
|
CodeOffsets {
|
||||||
flags,
|
|
||||||
constants: IndexMap::new(),
|
constants: IndexMap::new(),
|
||||||
lists: Vec::new(),
|
lists: Vec::new(),
|
||||||
structures: IndexMap::new(),
|
structures: IndexMap::new(),
|
||||||
@@ -65,18 +63,15 @@ impl CodeOffsets {
|
|||||||
let is_initial_index = self.lists.is_empty();
|
let is_initial_index = self.lists.is_empty();
|
||||||
self.lists.push(Self::add_index(is_initial_index, index));
|
self.lists.push(Self::add_index(is_initial_index, index));
|
||||||
}
|
}
|
||||||
&Term::Constant(_, Constant::String(ref s))
|
&Term::Constant(_, Constant::String(n, ref s)) => {
|
||||||
if !self.flags.double_quotes.is_atom() && !s.is_empty() =>
|
|
||||||
{
|
|
||||||
// strings are lists in this case.
|
|
||||||
let is_initial_index = self.lists.is_empty();
|
|
||||||
self.lists.push(Self::add_index(is_initial_index, index));
|
|
||||||
}
|
|
||||||
&Term::Constant(_, Constant::String(ref s))
|
|
||||||
if !self.flags.double_quotes.is_atom() && s.is_expandable() =>
|
|
||||||
{
|
|
||||||
let is_initial_index = self.lists.is_empty();
|
let is_initial_index = self.lists.is_empty();
|
||||||
self.lists.push(Self::add_index(is_initial_index, index));
|
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) => {
|
&Term::Constant(_, ref constant) => {
|
||||||
let code = self.constants.entry(constant.clone()).or_insert(Vec::new());
|
let code = self.constants.entry(constant.clone()).or_insert(Vec::new());
|
||||||
@@ -260,8 +255,8 @@ impl CodeOffsets {
|
|||||||
for (index, line) in prelude.iter_mut().enumerate() {
|
for (index, line) in prelude.iter_mut().enumerate() {
|
||||||
match line {
|
match line {
|
||||||
&mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i))
|
&mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i))
|
||||||
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i))
|
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i))
|
||||||
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => {
|
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => {
|
||||||
*i += prelude_length - index
|
*i += prelude_length - index
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
@@ -364,6 +364,17 @@ pub enum ControlInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ControlInstruction {
|
impl ControlInstruction {
|
||||||
|
pub fn perm_vars(&self) -> Option<usize> {
|
||||||
|
match self {
|
||||||
|
ControlInstruction::CallClause(_, _, num_cells, ..) =>
|
||||||
|
Some(*num_cells),
|
||||||
|
ControlInstruction::JmpBy(_, _, num_cells, ..) =>
|
||||||
|
Some(*num_cells),
|
||||||
|
_ =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_functor(&self) -> MachineStub {
|
pub fn to_functor(&self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&ControlInstruction::Allocate(num_frames) => {
|
&ControlInstruction::Allocate(num_frames) => {
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ impl<'a> QueryIterator<'a> {
|
|||||||
QueryIterator {
|
QueryIterator {
|
||||||
state_stack: vec![state],
|
state_stack: vec![state],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
|
&QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
|
||||||
let state = TermIterState::Clause(Level::Root, 0, cell, ct.clone(), terms);
|
let state = TermIterState::Clause(Level::Root, 0, cell, ct.clone(), terms);
|
||||||
QueryIterator {
|
QueryIterator {
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
:- module(atts, [attribute/1, call_residue_vars/2, '$absent_attr'/2,
|
:- module(atts, [op(1199, fx, attribute), call_residue_vars/2,
|
||||||
'$copy_attr_list'/2, '$get_attr'/2, '$put_attr'/2,
|
'$absent_attr'/2, '$copy_attr_list'/2, '$get_attr'/2,
|
||||||
'$absent_from_list'/2, '$get_from_list'/3,
|
'$put_attr'/2, '$absent_from_list'/2,
|
||||||
'$add_to_list'/3, '$del_attr'/3, '$del_attr_step'/3,
|
'$get_from_list'/3, '$add_to_list'/3, '$del_attr'/3,
|
||||||
'$del_attr_buried'/4, '$default_attr_list'/4]).
|
'$del_attr_step'/3, '$del_attr_buried'/4,
|
||||||
|
'$default_attr_list'/4]).
|
||||||
|
|
||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
:- use_module(library(terms)).
|
:- use_module(library(terms)).
|
||||||
|
|
||||||
:- op(1199, fx, attribute).
|
|
||||||
|
|
||||||
/* represent the list of attributes belonging to a variable,
|
/* represent the list of attributes belonging to a variable,
|
||||||
of a particular module, as a list of terms of the form
|
of a particular module, as a list of terms of the form
|
||||||
Module:put_atts(V, ListOfAtts). */
|
Module:put_atts(V, ListOfAtts). */
|
||||||
@@ -29,26 +28,26 @@
|
|||||||
'$get_attr_list'(V, Ls),
|
'$get_attr_list'(V, Ls),
|
||||||
'$absent_from_list'(Ls, Attr).
|
'$absent_from_list'(Ls, Attr).
|
||||||
|
|
||||||
'$absent_from_list'(X, _) :-
|
'$absent_from_list'(X, Attr) :-
|
||||||
var(X), !.
|
( var(X) -> true
|
||||||
'$absent_from_list'([L|Ls], Attr) :-
|
; X = [L|Ls], L \= Attr -> '$absent_from_list'(Ls, Attr)
|
||||||
( L \= Attr -> '$absent_from_list'(Ls, Attr) ).
|
).
|
||||||
|
|
||||||
'$get_attr'(V, Attr) :-
|
'$get_attr'(V, Attr) :-
|
||||||
'$get_attr_list'(V, Ls), nonvar(Ls), '$get_from_list'(Ls, V, Attr).
|
'$get_attr_list'(V, Ls), nonvar(Ls), '$get_from_list'(Ls, V, Attr).
|
||||||
|
|
||||||
'$get_from_list'([L|Ls], V, Attr) :-
|
'$get_from_list'([L|Ls], V, Attr) :-
|
||||||
nonvar(L),
|
nonvar(L),
|
||||||
( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr)
|
( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr)
|
||||||
; L = Attr -> '$enqueue_attr_var'(V)
|
; L = Attr, '$enqueue_attr_var'(V)
|
||||||
; '$get_from_list'(Ls, V, Attr)
|
|
||||||
).
|
).
|
||||||
|
|
||||||
'$put_attr'(V, Attr) :-
|
'$put_attr'(V, Attr) :-
|
||||||
'$get_attr_list'(V, Ls), '$add_to_list'(Ls, V, Attr).
|
'$get_attr_list'(V, Ls), '$add_to_list'(Ls, V, Attr).
|
||||||
|
|
||||||
'$add_to_list'(Ls, V, Attr) :-
|
'$add_to_list'(Ls, V, Attr) :-
|
||||||
( var(Ls) -> Ls = [Attr | _], '$enqueue_attr_var'(V)
|
( var(Ls) ->
|
||||||
|
Ls = [Attr | _], '$enqueue_attr_var'(V)
|
||||||
; Ls = [_ | Ls0], '$add_to_list'(Ls0, V, Attr)
|
; Ls = [_ | Ls0], '$add_to_list'(Ls0, V, Attr)
|
||||||
).
|
).
|
||||||
|
|
||||||
@@ -57,26 +56,27 @@
|
|||||||
'$del_attr'(Ls0, V, Attr) :-
|
'$del_attr'(Ls0, V, Attr) :-
|
||||||
Ls0 = [Att | Ls1],
|
Ls0 = [Att | Ls1],
|
||||||
nonvar(Att),
|
nonvar(Att),
|
||||||
( Att \= Attr -> '$del_attr_buried'(Ls0, Ls1, V, Attr)
|
( Att \= Attr -> '$del_attr_buried'(Ls0, Ls1, V, Attr)
|
||||||
; '$enqueue_attr_var'(V), '$del_attr_head'(V), '$del_attr'(Ls1, V, Attr)
|
; '$enqueue_attr_var'(V),
|
||||||
|
'$del_attr_head'(V),
|
||||||
|
'$del_attr'(Ls1, V, Attr)
|
||||||
).
|
).
|
||||||
|
|
||||||
'$del_attr_step'(Ls1, V, Attr) :-
|
'$del_attr_step'(Ls1, V, Attr) :-
|
||||||
( nonvar(Ls1) -> Ls1 = [_ | Ls2], '$del_attr_buried'(Ls1, Ls2, V, Attr)
|
( nonvar(Ls1) -> Ls1 = [_ | Ls2], '$del_attr_buried'(Ls1, Ls2, V, Attr)
|
||||||
; true ).
|
; true ).
|
||||||
|
|
||||||
%% assumptions: Ls0 is a list, Ls1 is its tail;
|
%% assumptions: Ls0 is a list, Ls1 is its tail;
|
||||||
%% the head of Ls0 can be ignored.
|
%% the head of Ls0 can be ignored.
|
||||||
'$del_attr_buried'(Ls0, Ls1, V, Attr) :-
|
'$del_attr_buried'(Ls0, Ls1, V, Attr) :-
|
||||||
Ls0 = [_, Att | _],
|
( var(Ls1) -> true
|
||||||
nonvar(Att),
|
; Ls1 = [Att | Ls2] ->
|
||||||
!,
|
( Att \= Attr -> '$del_attr_buried'(Ls1, Ls2, V, Attr)
|
||||||
( Att \= Attr -> '$del_attr_step'(Ls1, V, Attr)
|
; '$enqueue_attr_var'(V),
|
||||||
; '$enqueue_attr_var'(V),
|
'$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
|
||||||
'$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
|
'$del_attr_step'(Ls1, V, Attr)
|
||||||
'$del_attr_step'(Ls1, V, Attr)
|
)
|
||||||
).
|
).
|
||||||
'$del_attr_buried'(_, _, _, _).
|
|
||||||
|
|
||||||
'$copy_attr_list'(L, []) :- var(L), !.
|
'$copy_attr_list'(L, []) :- var(L), !.
|
||||||
'$copy_attr_list'([Att|Atts], [Att|CopiedAtts]) :-
|
'$copy_attr_list'([Att|Atts], [Att|CopiedAtts]) :-
|
||||||
@@ -125,11 +125,19 @@ put_attr(Name, Arity) -->
|
|||||||
{ functor(Attr, Name, Arity),
|
{ functor(Attr, Name, Arity),
|
||||||
numbervars(Attr, 0, Arity),
|
numbervars(Attr, 0, Arity),
|
||||||
V = '$VAR'(Arity) },
|
V = '$VAR'(Arity) },
|
||||||
[(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity), functor(AttrForm, Head, Arity),
|
[(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity),
|
||||||
'$get_attr_list'(V, Ls), '$del_attr'(Ls, V, AttrForm), '$put_attr'(V, Attr)),
|
functor(AttrForm, Head, Arity),
|
||||||
(put_atts(V, Attr) :- !, functor(Attr, Head, Arity), functor(AttrForm, Head, Arity),
|
'$get_attr_list'(V, Ls),
|
||||||
'$get_attr_list'(V, Ls), '$del_attr'(Ls, V, AttrForm), '$put_attr'(V, Attr)),
|
'$del_attr'(Ls, V, AttrForm),
|
||||||
(put_atts(V, -Attr) :- !, functor(Attr, _, _), '$get_attr_list'(V, Ls), '$del_attr'(Ls, V, Attr))].
|
'$put_attr'(V, Attr)),
|
||||||
|
(put_atts(V, Attr) :- !, functor(Attr, Head, Arity),
|
||||||
|
functor(AttrForm, Head, Arity),
|
||||||
|
'$get_attr_list'(V, Ls),
|
||||||
|
'$del_attr'(Ls, V, AttrForm),
|
||||||
|
'$put_attr'(V, Attr)),
|
||||||
|
(put_atts(V, -Attr) :- !, functor(Attr, _, _),
|
||||||
|
'$get_attr_list'(V, Ls),
|
||||||
|
'$del_attr'(Ls, V, Attr))].
|
||||||
|
|
||||||
get_attr(Name, Arity) -->
|
get_attr(Name, Arity) -->
|
||||||
{ functor(Attr, Name, Arity),
|
{ functor(Attr, Name, Arity),
|
||||||
@@ -150,3 +158,4 @@ call_residue_vars(Goal, Vars) :-
|
|||||||
'$get_attr_var_queue_delim'(B),
|
'$get_attr_var_queue_delim'(B),
|
||||||
call(Goal),
|
call(Goal),
|
||||||
'$get_attr_var_queue_beyond'(B, Vars).
|
'$get_attr_var_queue_beyond'(B, Vars).
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,15 @@
|
|||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
|
|
||||||
between(Lower, Upper, X) :-
|
between(Lower, Upper, X) :-
|
||||||
must_be(integer, Lower),
|
( Upper == inf ->
|
||||||
must_be(integer, Upper),
|
must_be(integer, Lower),
|
||||||
can_be(integer, X),
|
can_be(integer, X),
|
||||||
between_(Lower, Upper, X).
|
enumerate_nats(Lower, X)
|
||||||
|
; must_be(integer, Lower),
|
||||||
|
must_be(integer, Upper),
|
||||||
|
can_be(integer, X),
|
||||||
|
between_(Lower, Upper, X)
|
||||||
|
).
|
||||||
|
|
||||||
between_(Lower, Upper, Lower) :-
|
between_(Lower, Upper, Lower) :-
|
||||||
Lower =< Upper.
|
Lower =< Upper.
|
||||||
|
|||||||
@@ -1,35 +1,19 @@
|
|||||||
:- op(400, yfx, /).
|
:- op(400, yfx, /).
|
||||||
|
|
||||||
/* this is an implementation specific declarative operator used to implement call_with_inference_limit/3
|
|
||||||
and setup_call_cleanup/3. switches to the default trust_me and retry_me_else. Indexing choice
|
|
||||||
instructions are unchanged. */
|
|
||||||
:- op(700, fx, non_counted_backtracking).
|
|
||||||
|
|
||||||
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, (^)/2, (\)/1, (+)/1,
|
|
||||||
(+)/2, (**)/2, (*)/2, (-)/1, (-)/2, (/)/2, (/\)/2, (\/)/2,
|
|
||||||
(is)/2, (xor)/2, (div)/2, (//)/2, (rdiv)/2, (<<)/2, (>>)/2,
|
|
||||||
(mod)/2, (rem)/2, (>)/2, (<)/2, (=\=)/2, (=:=)/2, (>=)/2,
|
|
||||||
(=<)/2, (',')/2, (->)/2, (;)/2, (=..)/2, (==)/2, (\==)/2,
|
|
||||||
(@=<)/2, (@>=)/2, (@<)/2, (@>)/2, (:)/2, 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, 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, write_canonical/1, write_term/2, writeq/1]).
|
|
||||||
|
|
||||||
% module resolution operator.
|
% module resolution operator.
|
||||||
:- op(600, xfy, :).
|
:- op(600, xfy, :).
|
||||||
|
|
||||||
user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
||||||
expand_op_list([Op | OtherOps], Pred, Spec, OpResults).
|
'$expand_op_list'([Op | OtherOps], Pred, Spec, OpResults).
|
||||||
|
|
||||||
expand_op_list([], _, _, []).
|
'$expand_op_list'([], _, _, []).
|
||||||
expand_op_list([Op | OtherOps], Pred, Spec, [(:- op(Pred, Spec, Op)) | OtherResults]) :-
|
'$expand_op_list'([Op | OtherOps], Pred, Spec, [(:- op(Pred, Spec, Op)) | OtherResults]) :-
|
||||||
expand_op_list(OtherOps, Pred, Spec, OtherResults).
|
'$expand_op_list'(OtherOps, Pred, Spec, OtherResults).
|
||||||
|
|
||||||
|
/* this is an implementation specific declarative operator used to implement call_with_inference_limit/3
|
||||||
|
and setup_call_cleanup/3. switches to the default trust_me and retry_me_else. Indexing choice
|
||||||
|
instructions are unchanged. */
|
||||||
|
:- op(700, fx, non_counted_backtracking).
|
||||||
|
|
||||||
% arithmetic operators.
|
% arithmetic operators.
|
||||||
:- op(700, xfx, is).
|
:- op(700, xfx, is).
|
||||||
@@ -37,8 +21,7 @@ expand_op_list([Op | OtherOps], Pred, Spec, [(:- op(Pred, Spec, Op)) | OtherResu
|
|||||||
:- op(400, yfx, *).
|
:- op(400, yfx, *).
|
||||||
:- op(200, xfy, [**, ^]).
|
:- op(200, xfy, [**, ^]).
|
||||||
:- op(500, yfx, [/\, \/, xor]).
|
:- op(500, yfx, [/\, \/, xor]).
|
||||||
:- op(400, yfx, [div, //, rdiv]).
|
:- op(400, yfx, [div, //, rdiv, <<, >>, mod, rem]).
|
||||||
:- op(400, yfx, [<<, >>, mod, rem]).
|
|
||||||
:- op(200, fy, [+, -, \]).
|
:- op(200, fy, [+, -, \]).
|
||||||
|
|
||||||
% arithmetic comparison operators.
|
% arithmetic comparison operators.
|
||||||
@@ -47,9 +30,6 @@ expand_op_list([Op | OtherOps], Pred, Spec, [(:- op(Pred, Spec, Op)) | OtherResu
|
|||||||
% term comparison.
|
% term comparison.
|
||||||
:- op(700, xfx, [==, \==, @=<, @>=, @<, @>]).
|
:- op(700, xfx, [==, \==, @=<, @>=, @<, @>]).
|
||||||
|
|
||||||
% the maximum arity flag. needs to be replaced with current_prolog_flag(max_arity, MAX_ARITY).
|
|
||||||
max_arity(255).
|
|
||||||
|
|
||||||
% conditional operators.
|
% conditional operators.
|
||||||
:- op(1050, xfy, ->).
|
:- op(1050, xfy, ->).
|
||||||
:- op(1100, xfy, ;).
|
:- op(1100, xfy, ;).
|
||||||
@@ -58,6 +38,28 @@ max_arity(255).
|
|||||||
:- op(700, xfx, [=, =.., \=]).
|
:- op(700, xfx, [=, =.., \=]).
|
||||||
:- op(900, fy, \+).
|
:- op(900, fy, \+).
|
||||||
|
|
||||||
|
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2,
|
||||||
|
(=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6,
|
||||||
|
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
|
||||||
|
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,
|
||||||
|
write_canonical/1, write_term/2, writeq/1]).
|
||||||
|
|
||||||
|
|
||||||
|
% the maximum arity flag. needs to be replaced with
|
||||||
|
% current_prolog_flag(max_arity, MAX_ARITY).
|
||||||
|
max_arity(255).
|
||||||
|
|
||||||
% unify.
|
% unify.
|
||||||
X = X.
|
X = X.
|
||||||
|
|
||||||
@@ -72,6 +74,57 @@ Module : Predicate :-
|
|||||||
; throw(error(type_error(atom, Module), (:)/2))
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
|
:(Module, Predicate, A1) :-
|
||||||
|
( atom(Module) -> '$module_call'(A1, Module, Predicate)
|
||||||
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
|
).
|
||||||
|
|
||||||
|
:(Module, Predicate, A1, A2) :-
|
||||||
|
( atom(Module) -> '$module_call'(A1, A2, Module, Predicate)
|
||||||
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
|
).
|
||||||
|
|
||||||
|
:(Module, Predicate, A1, A2, A3) :-
|
||||||
|
( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate)
|
||||||
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
|
).
|
||||||
|
|
||||||
|
:(Module, Predicate, A1, A2, A3, A4) :-
|
||||||
|
( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate)
|
||||||
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
|
).
|
||||||
|
|
||||||
|
:(Module, Predicate, A1, A2, A3, A4, A5) :-
|
||||||
|
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate)
|
||||||
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
|
).
|
||||||
|
|
||||||
|
:(Module, Predicate, A1, A2, A3, A4, A5, A6) :-
|
||||||
|
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate)
|
||||||
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
|
).
|
||||||
|
|
||||||
|
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7) :-
|
||||||
|
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate)
|
||||||
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
|
).
|
||||||
|
|
||||||
|
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8) :-
|
||||||
|
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate)
|
||||||
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
|
).
|
||||||
|
|
||||||
|
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9) :-
|
||||||
|
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate)
|
||||||
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
|
).
|
||||||
|
|
||||||
|
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) :-
|
||||||
|
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate)
|
||||||
|
; throw(error(type_error(atom, Module), (:)/2))
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
% flags.
|
% flags.
|
||||||
|
|
||||||
current_prolog_flag(Flag, false) :- Flag == bounded, !.
|
current_prolog_flag(Flag, false) :- Flag == bounded, !.
|
||||||
@@ -125,13 +178,13 @@ set_prolog_flag(Flag, _) :-
|
|||||||
|
|
||||||
fail :- '$fail'.
|
fail :- '$fail'.
|
||||||
|
|
||||||
\+ G :- G, !, false.
|
\+ G :- call(G), !, false.
|
||||||
\+ _.
|
\+ _.
|
||||||
|
|
||||||
X \= X :- !, false.
|
X \= X :- !, false.
|
||||||
_ \= _.
|
_ \= _.
|
||||||
|
|
||||||
once(G) :- G, !.
|
once(G) :- call(G), !.
|
||||||
|
|
||||||
repeat.
|
repeat.
|
||||||
repeat :- repeat.
|
repeat :- repeat.
|
||||||
@@ -148,13 +201,14 @@ comma_errors(G1, G2, B) :- '$call_with_default_policy'(','(G1, G2, B)).
|
|||||||
'$set_cp'(B),
|
'$set_cp'(B),
|
||||||
'$call_with_default_policy'(comma_errors(G1, G2, B)).
|
'$call_with_default_policy'(comma_errors(G1, G2, B)).
|
||||||
','(!, Atom, B) :- Atom == !, '$set_cp'(B).
|
','(!, Atom, B) :- Atom == !, '$set_cp'(B).
|
||||||
','(!, G, B) :- '$set_cp'(B), G.
|
','(!, G, B) :- '$set_cp'(B), call(G).
|
||||||
','(G, CF, B) :- compound(CF),
|
','(G, CF, B) :- compound(CF),
|
||||||
'$call_with_default_policy'(CF = ','(G1, G2)),
|
'$call_with_default_policy'(CF = ','(G1, G2)),
|
||||||
!, G,
|
!,
|
||||||
|
call(G),
|
||||||
'$call_with_default_policy'(comma_errors(G1, G2, B)).
|
'$call_with_default_policy'(comma_errors(G1, G2, B)).
|
||||||
','(G, Atom, B) :- Atom == !, !, G, '$set_cp'(B).
|
','(G, Atom, B) :- Atom == !, !, call(G), '$set_cp'(B).
|
||||||
','(G1, G2, _) :- G1, G2.
|
','(G1, G2, _) :- call(G1), call(G2).
|
||||||
|
|
||||||
;(G1, G2) :- '$get_b_value'(B), ;(G1, G2, B).
|
;(G1, G2) :- '$get_b_value'(B), ;(G1, G2, B).
|
||||||
|
|
||||||
@@ -162,37 +216,47 @@ comma_errors(G1, G2, B) :- '$call_with_default_policy'(','(G1, G2, B)).
|
|||||||
;(G1, G4, B) :- compound(G1),
|
;(G1, G4, B) :- compound(G1),
|
||||||
'$call_with_default_policy'(G1 = ->(G2, G3)),
|
'$call_with_default_policy'(G1 = ->(G2, G3)),
|
||||||
!,
|
!,
|
||||||
(G2 -> G3 ; '$set_cp'(B), G4).
|
( call(G2) -> call(G3)
|
||||||
;(G1, G2, B) :- G1 == !, '$set_cp'(B), G2.
|
; '$set_cp'(B),
|
||||||
;(G1, G2, B) :- G2 == !, G1, '$set_cp'(B).
|
call(G4)
|
||||||
;(G, _, _) :- G.
|
).
|
||||||
;(_, G, _) :- G.
|
;(G1, G2, B) :- G1 == !, '$set_cp'(B), call(G2).
|
||||||
|
;(G1, G2, B) :- G2 == !, call(G1), '$set_cp'(B).
|
||||||
|
;(G, _, _) :- call(G).
|
||||||
|
;(_, G, _) :- call(G).
|
||||||
|
|
||||||
G1 -> G2 :- '$get_b_value'(B), '$call_with_default_policy'(->(G1, G2, B)).
|
G1 -> G2 :- '$get_b_value'(B), '$call_with_default_policy'(->(G1, G2, B)).
|
||||||
|
|
||||||
:- non_counted_backtracking (->)/3.
|
:- non_counted_backtracking (->)/3.
|
||||||
->(G1, G2, B) :- G2 == !, G1, '$set_cp'(B).
|
->(G1, G2, B) :- G2 == !, call(G1), '$set_cp'(B).
|
||||||
->(G1, G2, B) :- G1, '$set_cp'(B), G2.
|
->(G1, G2, B) :- call(G1), '$set_cp'(B), call(G2).
|
||||||
|
|
||||||
% univ.
|
% univ.
|
||||||
|
|
||||||
:- non_counted_backtracking univ_errors/3.
|
:- non_counted_backtracking univ_errors/3.
|
||||||
univ_errors(Term, List, N) :-
|
univ_errors(Term, List, N) :-
|
||||||
'$skip_max_list'(N, -1, List, R),
|
'$skip_max_list'(N, -1, List, R),
|
||||||
( var(R) -> ( var(Term), throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
|
( var(R) ->
|
||||||
; true )
|
( var(Term), throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
|
||||||
; R \== [] -> throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b)
|
; true
|
||||||
; List = [H|T] -> ( var(H), var(Term), % R == [] => List is a proper list.
|
)
|
||||||
throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 c)
|
; R \== [] ->
|
||||||
; T \== [], nonvar(H), \+ atom(H),
|
throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b)
|
||||||
throw(error(type_error(atom, H), (=..)/2)) % 8.5.3.3 d)
|
; List = [H|T] ->
|
||||||
; compound(H), T == [],
|
( var(H), var(Term), % R == [] => List is a proper list.
|
||||||
throw(error(type_error(atomic, H), (=..)/2)) % 8.5.3.3 e)
|
throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 c)
|
||||||
; var(Term), max_arity(M), N - 1 > M,
|
; T \== [], nonvar(H), \+ atom(H),
|
||||||
throw(error(representation_error(max_arity), (=..)/2)) % 8.5.3.3 g)
|
throw(error(type_error(atom, H), (=..)/2)) % 8.5.3.3 d)
|
||||||
; true )
|
; compound(H), T == [],
|
||||||
; var(Term) -> throw(error(domain_error(non_empty_list, List), (=..)/2)) % 8.5.3.3 f)
|
throw(error(type_error(atomic, H), (=..)/2)) % 8.5.3.3 e)
|
||||||
; true ).
|
; var(Term), max_arity(M), N - 1 > M,
|
||||||
|
throw(error(representation_error(max_arity), (=..)/2)) % 8.5.3.3 g)
|
||||||
|
; true
|
||||||
|
)
|
||||||
|
; var(Term) ->
|
||||||
|
throw(error(domain_error(non_empty_list, List), (=..)/2)) % 8.5.3.3 f)
|
||||||
|
; true
|
||||||
|
).
|
||||||
|
|
||||||
Term =.. List :- '$call_with_default_policy'(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)).
|
'$call_with_default_policy'(univ_worker(Term, List, N)).
|
||||||
@@ -319,7 +383,8 @@ catch(G,C,R) :- '$get_current_block'(Bb), '$call_with_default_policy'(catch(G,C,
|
|||||||
|
|
||||||
:- non_counted_backtracking catch/4.
|
:- non_counted_backtracking catch/4.
|
||||||
catch(G,C,R,Bb) :-
|
catch(G,C,R,Bb) :-
|
||||||
'$install_new_block'(NBb), call(G),
|
'$install_new_block'(NBb),
|
||||||
|
call(G),
|
||||||
'$call_with_default_policy'(end_block(Bb, NBb)).
|
'$call_with_default_policy'(end_block(Bb, NBb)).
|
||||||
catch(G,C,R,Bb) :-
|
catch(G,C,R,Bb) :-
|
||||||
'$reset_block'(Bb),
|
'$reset_block'(Bb),
|
||||||
@@ -549,9 +614,11 @@ assertz_clause(Head, Body) :-
|
|||||||
arg(1, Head, Module),
|
arg(1, Head, Module),
|
||||||
arg(2, Head, F),
|
arg(2, Head, F),
|
||||||
module_assertz_clause(F, Body, Module)
|
module_assertz_clause(F, Body, Module)
|
||||||
; '$no_such_predicate'(Head) -> call_assertz(Head, Body, Name, Arity)
|
; '$no_such_predicate'(Head) ->
|
||||||
; '$head_is_dynamic'(Head) -> call_assertz(Head, Body, Name, Arity)
|
call_assertz(Head, Body, Name, Arity)
|
||||||
; throw(error(permission_error(modify, static_procedure, Name/Arity), assertz/1))
|
; '$head_is_dynamic'(Head) ->
|
||||||
|
call_assertz(Head, Body, Name, Arity)
|
||||||
|
; throw(error(permission_error(modify, static_procedure, Name/Arity), assertz/1))
|
||||||
)
|
)
|
||||||
; throw(error(type_error(callable, Head), assertz/1))
|
; throw(error(type_error(callable, Head), assertz/1))
|
||||||
).
|
).
|
||||||
@@ -861,8 +928,12 @@ must_be_number(N, PI) :-
|
|||||||
; throw(error(instantiation_error, PI))
|
; throw(error(instantiation_error, PI))
|
||||||
).
|
).
|
||||||
|
|
||||||
can_be_chars_or_vars(Cs, _) :- var(Cs), !.
|
can_be_chars_or_vars(Cs, _) :- var(Cs), !.
|
||||||
can_be_chars_or_vars(Cs, PI) :- chars_or_vars(Cs, PI).
|
can_be_chars_or_vars(Cs, PI) :-
|
||||||
|
( string(Cs) ->
|
||||||
|
current_prolog_flag(double_quotes, chars)
|
||||||
|
; chars_or_vars(Cs, PI)
|
||||||
|
).
|
||||||
|
|
||||||
chars_or_vars([], _).
|
chars_or_vars([], _).
|
||||||
chars_or_vars([C|Cs], PI) :-
|
chars_or_vars([C|Cs], PI) :-
|
||||||
@@ -876,8 +947,12 @@ chars_or_vars([C|Cs], PI) :-
|
|||||||
; chars_or_vars(Cs, PI)
|
; chars_or_vars(Cs, PI)
|
||||||
).
|
).
|
||||||
|
|
||||||
can_be_codes_or_vars(Cs, _) :- var(Cs), !.
|
can_be_codes_or_vars(Cs, _) :- var(Cs), !.
|
||||||
can_be_codes_or_vars(Cs, PI) :- codes_or_vars(Cs, PI).
|
can_be_codes_or_vars(Cs, PI) :-
|
||||||
|
( string(Cs) ->
|
||||||
|
current_prolog_flag(double_quotes, codes)
|
||||||
|
; codes_or_vars(Cs, PI)
|
||||||
|
).
|
||||||
|
|
||||||
codes_or_vars([], _).
|
codes_or_vars([], _).
|
||||||
codes_or_vars([C|Cs], PI) :-
|
codes_or_vars([C|Cs], PI) :-
|
||||||
|
|||||||
@@ -16,11 +16,9 @@
|
|||||||
Public operators.
|
Public operators.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
:- op(300, fy, ~).
|
:- module(clpb, [op(300, fy, ~),
|
||||||
:- op(500, yfx, #).
|
op(500, yfx, #),
|
||||||
|
sat/1,
|
||||||
:- module(clpb, [
|
|
||||||
sat/1,
|
|
||||||
taut/2,
|
taut/2,
|
||||||
labeling/1,
|
labeling/1,
|
||||||
sat_count/2,
|
sat_count/2,
|
||||||
@@ -1186,7 +1184,7 @@ indomain(1).
|
|||||||
% Examples:
|
% Examples:
|
||||||
%
|
%
|
||||||
% ==
|
% ==
|
||||||
% ?- sat(A =< B), Vs = [A,B], sat_count(+[1|Vs], Count).
|
% ?- sat(A =< B), Vs = [A,B], sat_count(+[1|Vs], Count).
|
||||||
% Vs = [A, B],
|
% Vs = [A, B],
|
||||||
% Count = 3,
|
% Count = 3,
|
||||||
% sat(A=:=A*B).
|
% sat(A=:=A*B).
|
||||||
|
|||||||
31
src/prolog/lib/cont.pl
Normal file
31
src/prolog/lib/cont.pl
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
:- module(cont, [reset/3, shift/1]).
|
||||||
|
|
||||||
|
reset(Goal, Ball, Cont) :-
|
||||||
|
call(Goal),
|
||||||
|
'$reset_cont_marker',
|
||||||
|
'$bind_from_register'(Cont, 3),
|
||||||
|
'$bind_from_register'(Ball, 4).
|
||||||
|
|
||||||
|
shift(Term) :-
|
||||||
|
'$nextEP'(first, E, P),
|
||||||
|
get_chunks(E, P, L),
|
||||||
|
( L == [] ->
|
||||||
|
Cont = none
|
||||||
|
; Cont = cont(call_continuation(L))
|
||||||
|
),
|
||||||
|
'$write_cont_and_term'(_, _, Cont, Term),
|
||||||
|
'$unwind_environments'.
|
||||||
|
|
||||||
|
get_chunks(E, P, L) :-
|
||||||
|
( '$points_to_cont_reset_marker'(P) ->
|
||||||
|
L = []
|
||||||
|
; '$get_cont_chunk'(E,P,TB),
|
||||||
|
L = [TB|Rest],
|
||||||
|
'$nextEP'(E, NextE, NextP),
|
||||||
|
get_chunks(NextE, NextP, Rest)
|
||||||
|
).
|
||||||
|
|
||||||
|
call_continuation(L) :- '$call_continuation'(L).
|
||||||
|
|
||||||
|
'$write_cont_and_term'(_, _, _, _).
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
:- op(1200, xfx, -->).
|
|
||||||
% :- op(1105, xfy, ('|')).
|
% :- op(1105, xfy, ('|')).
|
||||||
|
|
||||||
:- module(dcgs, [phrase/2, phrase/3]).
|
:- module(dcgs, [op(1200, xfx, -->), phrase/2, phrase/3]).
|
||||||
|
|
||||||
:- use_module(library(lists), [append/3]).
|
:- use_module(library(lists), [append/3]).
|
||||||
|
|
||||||
user:term_expansion(Term0, (Head :- Body)) :-
|
user:term_expansion(Term0, Term) :-
|
||||||
dcg_rule(Term0, Term),
|
nonvar(Term0),
|
||||||
|
dcg_rule(Term0, (Head :- Body)),
|
||||||
Term = (Head :- Body).
|
Term = (Head :- Body).
|
||||||
|
|
||||||
phrase(GRBody, S0) :-
|
phrase(GRBody, S0) :-
|
||||||
@@ -34,7 +34,7 @@ phrase_((A ; B), S0, S) :-
|
|||||||
%% phrase_((A | B), S0, S) :-
|
%% phrase_((A | B), S0, S) :-
|
||||||
%% ( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
%% ( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
||||||
phrase_({G}, S0, S) :-
|
phrase_({G}, S0, S) :-
|
||||||
( G, S0 = S ).
|
( call(G), S0 = S ).
|
||||||
phrase_(call(G), S0, S) :-
|
phrase_(call(G), S0, S) :-
|
||||||
call(G, S0, S).
|
call(G, S0, S).
|
||||||
phrase_((A -> B), S0, S) :-
|
phrase_((A -> B), S0, S) :-
|
||||||
@@ -44,6 +44,17 @@ phrase_(phrase(NonTerminal), S0, S) :-
|
|||||||
phrase_([T|Ts], S0, S) :-
|
phrase_([T|Ts], S0, S) :-
|
||||||
append([T|Ts], S, S0).
|
append([T|Ts], S, S0).
|
||||||
|
|
||||||
|
% The same version of the below two dcg_rule clauses, but with module scoping.
|
||||||
|
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
|
||||||
|
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||||
|
dcg_body(GRBody, S0, S1, Goal1),
|
||||||
|
dcg_terminals(Terminals, S, S1, Goal2),
|
||||||
|
Body = ( Goal1, Goal2 ).
|
||||||
|
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
|
||||||
|
NonTerminal \= ( _, _ ),
|
||||||
|
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||||
|
dcg_body(GRBody, S0, S, Body).
|
||||||
|
|
||||||
% This program uses append/3 as defined in the Prolog prologue.
|
% This program uses append/3 as defined in the Prolog prologue.
|
||||||
% Expands a DCG rule into a Prolog rule, when no error condition applies.
|
% Expands a DCG rule into a Prolog rule, when no error condition applies.
|
||||||
dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :-
|
dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :-
|
||||||
|
|||||||
@@ -21,16 +21,8 @@ freeze(X, Goal) :-
|
|||||||
put_atts(Fresh, frozen(Goal)),
|
put_atts(Fresh, frozen(Goal)),
|
||||||
Fresh = X.
|
Fresh = X.
|
||||||
|
|
||||||
gather_freeze_goals(Attrs, _) -->
|
attribute_goals(Var) -->
|
||||||
{ var(Attrs) },
|
{ get_atts(Var, frozen(Goals)),
|
||||||
!.
|
put_atts(Var, -frozen(_)) },
|
||||||
gather_freeze_goals([frozen(X) | _], Var) -->
|
[freeze(Var, Goals)].
|
||||||
[freeze(Var, X)],
|
|
||||||
{ put_atts(Var, -frozen(_)) },
|
|
||||||
!.
|
|
||||||
gather_freeze_goals([_ | Attrs], Var) -->
|
|
||||||
gather_freeze_goals(Attrs, Var).
|
|
||||||
|
|
||||||
attribute_goals(X) -->
|
|
||||||
{ '$get_attr_list'(X, Attrs) },
|
|
||||||
gather_freeze_goals(Attrs, X).
|
|
||||||
|
|||||||
32
src/prolog/lib/gensym.pl
Normal file
32
src/prolog/lib/gensym.pl
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
:- module(gensym, [gensym/2,
|
||||||
|
reset_gensym/1]).
|
||||||
|
|
||||||
|
:- use_module(library(error)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(non_iso)).
|
||||||
|
:- use_module(library(si)).
|
||||||
|
|
||||||
|
gensym_key(Base, BaseKey) :-
|
||||||
|
atom_concat('gensym_', Base, BaseKey).
|
||||||
|
|
||||||
|
append_id(Base, UniqueID, Unique) :-
|
||||||
|
atom_chars(Base, BaseChars),
|
||||||
|
number_chars(UniqueID, IDChars),
|
||||||
|
append(BaseChars, IDChars, AtomChars),
|
||||||
|
atom_chars(Unique, AtomChars).
|
||||||
|
|
||||||
|
gensym(Base, Unique) :-
|
||||||
|
must_be(var, Unique),
|
||||||
|
atom_si(Base),
|
||||||
|
gensym_key(Base, BaseKey),
|
||||||
|
( bb_get(BaseKey, UniqueID0) ->
|
||||||
|
UniqueID is UniqueID0 + 1,
|
||||||
|
bb_put(BaseKey, UniqueID),
|
||||||
|
append_id(Base, UniqueID, Unique)
|
||||||
|
; bb_put(BaseKey, 1),
|
||||||
|
append_id(Base, 1, Unique)
|
||||||
|
).
|
||||||
|
|
||||||
|
reset_gensym(Base) :-
|
||||||
|
atom_si(Base),
|
||||||
|
bb_put(Base, 0).
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
:- module(lists, [member/2, select/3, append/3, memberchk/2,
|
:- module(lists, [member/2, select/3, append/3, foldl/4, foldl/5,
|
||||||
reverse/2, length/2, maplist/2, maplist/3,
|
memberchk/2, reverse/2, length/2, maplist/2,
|
||||||
maplist/4, maplist/5, maplist/6, maplist/7,
|
maplist/3, maplist/4, maplist/5, maplist/6,
|
||||||
maplist/8, maplist/9]).
|
maplist/7, maplist/8, maplist/9, same_length/2,
|
||||||
|
sumlist/2]).
|
||||||
|
|
||||||
|
|
||||||
|
:- use_module(library(error)).
|
||||||
|
|
||||||
|
|
||||||
length(Xs, N) :-
|
length(Xs, N) :-
|
||||||
@@ -96,3 +100,37 @@ maplist(_, [], [], [], [], [], [], [], []).
|
|||||||
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s], [E8|E8s]) :-
|
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s], [E8|E8s]) :-
|
||||||
call(Cont, E1, E2, E3, E4, E5, E6, E7),
|
call(Cont, E1, E2, E3, E4, E5, E6, E7),
|
||||||
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s, E8s).
|
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).
|
||||||
|
|
||||||
|
sumlist(Ns, S) :-
|
||||||
|
must_be(list, Ns),
|
||||||
|
sumlist_(Ns, S, 0).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
same_length([], []).
|
||||||
|
same_length([_|As], [_|Bs]) :-
|
||||||
|
same_length(As, Bs).
|
||||||
|
|
||||||
|
|
||||||
|
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(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).
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
:- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
|
:- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
|
||||||
call_with_inference_limit/3, forall/2, maybe/0,
|
call_with_inference_limit/3, forall/2, maybe/0,
|
||||||
set_random/1, setup_call_cleanup/3, variant/2]).
|
partial_string/1, partial_string/3,
|
||||||
|
partial_string_tail/2, set_random/1,
|
||||||
|
setup_call_cleanup/3, variant/2]).
|
||||||
|
|
||||||
forall(Generate, Test) :-
|
forall(Generate, Test) :-
|
||||||
\+ (Generate, \+ Test).
|
\+ (Generate, \+ Test).
|
||||||
@@ -21,7 +23,7 @@ bb_b_put(Key, NewValue) :-
|
|||||||
( '$bb_get_with_offset'(Key, OldValue, OldOffset) ->
|
( '$bb_get_with_offset'(Key, OldValue, OldOffset) ->
|
||||||
call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
|
call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
|
||||||
reset_global_var_at_offset(Key, OldValue, OldOffset))
|
reset_global_var_at_offset(Key, OldValue, OldOffset))
|
||||||
; call_cleanup((store_global_var(Key, NewValue, _) ; false),
|
; call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
|
||||||
reset_global_var_at_key(Key))
|
reset_global_var_at_key(Key))
|
||||||
).
|
).
|
||||||
|
|
||||||
@@ -46,10 +48,34 @@ call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
|
|||||||
|
|
||||||
% setup_call_cleanup.
|
% setup_call_cleanup.
|
||||||
|
|
||||||
setup_call_cleanup(S, G, C) :- '$get_b_value'(B),
|
setup_call_cleanup(S, G, C) :-
|
||||||
S, '$set_cp_by_default'(B), '$get_current_block'(Bb),
|
'$get_b_value'(B),
|
||||||
( '$call_with_default_policy'(var(C)) -> throw(error(instantiation_error, setup_call_cleanup/3))
|
call(S),
|
||||||
; '$call_with_default_policy'(scc_helper(C, G, Bb)) ).
|
'$set_cp_by_default'(B),
|
||||||
|
'$get_current_block'(Bb),
|
||||||
|
( '$call_with_default_policy'(var(C)) ->
|
||||||
|
throw(error(instantiation_error, setup_call_cleanup/3))
|
||||||
|
; '$call_with_default_policy'(scc_helper(C, G, Bb))
|
||||||
|
).
|
||||||
|
|
||||||
|
:- non_counted_backtracking scc_helper/3.
|
||||||
|
scc_helper(C, G, Bb) :-
|
||||||
|
'$get_cp'(Cp), '$install_scc_cleaner'(C, NBb), call(G),
|
||||||
|
( '$check_cp'(Cp) ->
|
||||||
|
'$reset_block'(Bb),
|
||||||
|
'$call_with_default_policy'(run_cleaners_without_handling(Cp))
|
||||||
|
; '$call_with_default_policy'(true)
|
||||||
|
; '$reset_block'(NBb),
|
||||||
|
'$fail').
|
||||||
|
scc_helper(_, _, Bb) :-
|
||||||
|
'$reset_block'(Bb), '$get_ball'(Ball),
|
||||||
|
'$call_with_default_policy'(run_cleaners_with_handling),
|
||||||
|
'$erase_ball',
|
||||||
|
'$call_with_default_policy'(throw(Ball)).
|
||||||
|
scc_helper(_, _, _) :-
|
||||||
|
'$get_cp'(Cp),
|
||||||
|
'$call_with_default_policy'(run_cleaners_without_handling(Cp)),
|
||||||
|
'$fail'.
|
||||||
|
|
||||||
:- non_counted_backtracking run_cleaners_with_handling/0.
|
:- non_counted_backtracking run_cleaners_with_handling/0.
|
||||||
run_cleaners_with_handling :-
|
run_cleaners_with_handling :-
|
||||||
@@ -62,27 +88,14 @@ run_cleaners_with_handling :-
|
|||||||
|
|
||||||
:- non_counted_backtracking run_cleaners_without_handling/1.
|
:- non_counted_backtracking run_cleaners_without_handling/1.
|
||||||
run_cleaners_without_handling(Cp) :-
|
run_cleaners_without_handling(Cp) :-
|
||||||
'$get_scc_cleaner'(C), '$get_level'(B), C, '$set_cp_by_default'(B),
|
'$get_scc_cleaner'(C),
|
||||||
|
'$get_level'(B),
|
||||||
|
call(C),
|
||||||
|
'$set_cp_by_default'(B),
|
||||||
'$call_with_default_policy'(run_cleaners_without_handling(Cp)).
|
'$call_with_default_policy'(run_cleaners_without_handling(Cp)).
|
||||||
run_cleaners_without_handling(Cp) :-
|
run_cleaners_without_handling(Cp) :-
|
||||||
'$set_cp_by_default'(Cp), '$restore_cut_policy'.
|
'$set_cp_by_default'(Cp),
|
||||||
|
'$restore_cut_policy'.
|
||||||
:- non_counted_backtracking scc_helper/3.
|
|
||||||
scc_helper(C, G, Bb) :-
|
|
||||||
'$get_cp'(Cp), '$install_scc_cleaner'(C, NBb), call(G),
|
|
||||||
( '$check_cp'(Cp) -> '$reset_block'(Bb),
|
|
||||||
'$call_with_default_policy'(run_cleaners_without_handling(Cp))
|
|
||||||
; '$call_with_default_policy'(true)
|
|
||||||
; '$reset_block'(NBb), '$fail').
|
|
||||||
scc_helper(_, _, Bb) :-
|
|
||||||
'$reset_block'(Bb), '$get_ball'(Ball),
|
|
||||||
'$call_with_default_policy'(run_cleaners_with_handling),
|
|
||||||
'$erase_ball',
|
|
||||||
'$call_with_default_policy'(throw(Ball)).
|
|
||||||
scc_helper(_, _, _) :-
|
|
||||||
'$get_cp'(Cp),
|
|
||||||
'$call_with_default_policy'(run_cleaners_without_handling(Cp)),
|
|
||||||
'$fail'.
|
|
||||||
|
|
||||||
% call_with_inference_limit
|
% call_with_inference_limit
|
||||||
|
|
||||||
@@ -119,8 +132,12 @@ call_with_inference_limit(G, L, R, Bb, B) :-
|
|||||||
call_with_inference_limit(_, _, R, Bb, B) :-
|
call_with_inference_limit(_, _, R, Bb, B) :-
|
||||||
'$reset_block'(Bb),
|
'$reset_block'(Bb),
|
||||||
'$remove_inference_counter'(B, _),
|
'$remove_inference_counter'(B, _),
|
||||||
( '$get_ball'(Ball), '$get_level'(Cp), '$set_cp_by_default'(Cp)
|
( '$get_ball'(Ball),
|
||||||
; '$remove_call_policy_check'(B), '$fail' ),
|
'$get_level'(Cp),
|
||||||
|
'$set_cp_by_default'(Cp)
|
||||||
|
; '$remove_call_policy_check'(B),
|
||||||
|
'$fail'
|
||||||
|
),
|
||||||
'$erase_ball',
|
'$erase_ball',
|
||||||
'$call_with_default_policy'(handle_ile(B, Ball, R)).
|
'$call_with_default_policy'(handle_ile(B, Ball, R)).
|
||||||
|
|
||||||
@@ -139,3 +156,20 @@ set_random(Seed) :-
|
|||||||
)
|
)
|
||||||
; throw(error(instantiation_error, set_random/1))
|
; throw(error(instantiation_error, set_random/1))
|
||||||
).
|
).
|
||||||
|
|
||||||
|
partial_string(String, L, L0) :-
|
||||||
|
( String == [] -> throw(error(type_error(list, []), partial_string/3))
|
||||||
|
; catch(atom_chars(Atom, String),
|
||||||
|
error(E, _),
|
||||||
|
throw(error(E, partial_string/3)))
|
||||||
|
),
|
||||||
|
'$create_partial_string'(Atom, L, L0).
|
||||||
|
|
||||||
|
partial_string(String) :-
|
||||||
|
'$is_partial_string'(String).
|
||||||
|
|
||||||
|
partial_string_tail(String, Tail) :-
|
||||||
|
( partial_string(String) ->
|
||||||
|
'$partial_string_tail'(String, Tail)
|
||||||
|
; throw(error(type_error(partial_string, String), partial_string_tail/2))
|
||||||
|
).
|
||||||
|
|||||||
224
src/prolog/lib/tabling.pl
Normal file
224
src/prolog/lib/tabling.pl
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
|
||||||
|
:- module(tabling,
|
||||||
|
[ start_tabling/2, % +Wrapper, :Worker.
|
||||||
|
|
||||||
|
abolish_all_tables/0,
|
||||||
|
|
||||||
|
% (table)/1, % +PI ...
|
||||||
|
op(1150, fx, table)
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module('tabling/double_linked_list').
|
||||||
|
:- use_module('tabling/table_data_structure').
|
||||||
|
:- use_module('tabling/batched_worklist').
|
||||||
|
:- use_module('tabling/wrapper').
|
||||||
|
:- use_module('tabling/global_worklist').
|
||||||
|
:- use_module('tabling/table_link_manager').
|
||||||
|
|
||||||
|
:- use_module(library(cont)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
%:- use_module(library(debug)).
|
||||||
|
:- use_module(library(non_iso)).
|
||||||
|
|
||||||
|
%% :- meta_predicate
|
||||||
|
%% start_tabling(+, 0).
|
||||||
|
|
||||||
|
%% user:exception(+Exception, +Var, -Action)
|
||||||
|
%
|
||||||
|
% Realises lazy initialization of table variables.
|
||||||
|
|
||||||
|
%% user:exception(undefined_global_variable, Var, retry) :-
|
||||||
|
%% ( table_gvar(Var)
|
||||||
|
%% -> true
|
||||||
|
%% ; format('Creating global var ~q~n', [Var]),
|
||||||
|
%% nb_setval(Var, [])
|
||||||
|
%% ).
|
||||||
|
/*
|
||||||
|
table_gvar(trie_table_link) :-
|
||||||
|
table_datastructure_initialize.
|
||||||
|
table_gvar(newly_created_table_identifiers) :-
|
||||||
|
table_datastructure_initialize.
|
||||||
|
table_gvar(table_global_worklist) :-
|
||||||
|
bb_put(table_global_worklist, []).
|
||||||
|
table_gvar(table_leader) :-
|
||||||
|
bb_put(table_leader, []).
|
||||||
|
*/
|
||||||
|
|
||||||
|
%% abolish_all_tables
|
||||||
|
%
|
||||||
|
% Remove all tables. Should not be called when tabling is in
|
||||||
|
% progress.
|
||||||
|
%
|
||||||
|
% @bug Check whether tabling is in progress
|
||||||
|
|
||||||
|
|
||||||
|
abolish_all_tables :-
|
||||||
|
bb_put(trie_table_link, []),
|
||||||
|
bb_put(newly_created_table_identifiers, []),
|
||||||
|
bb_put(table_global_worklist,[]),
|
||||||
|
bb_put(table_leader, []).
|
||||||
|
|
||||||
|
|
||||||
|
% Find table and status for the given call variant.
|
||||||
|
%
|
||||||
|
table_and_status_for_variant(V,T,S) :-
|
||||||
|
% Order of the two calls really important: first create, then get status
|
||||||
|
table_for_variant(V,T),
|
||||||
|
tbd_table_status(T,S).
|
||||||
|
|
||||||
|
start_tabling(Wrapper,Worker) :-
|
||||||
|
put_new_trie_table_link,
|
||||||
|
put_new_global_worklist,
|
||||||
|
put_new_table_identifiers,
|
||||||
|
table_and_status_for_variant(Wrapper,T,S),
|
||||||
|
( S == complete ->
|
||||||
|
get_answer(T,Wrapper)
|
||||||
|
;
|
||||||
|
( exists_scheduling_component ->
|
||||||
|
run_leader(Wrapper,Worker,T),
|
||||||
|
% Now answer the original query!
|
||||||
|
get_answer(T,Wrapper)
|
||||||
|
;
|
||||||
|
run_follower(S,Wrapper,Worker,T)
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
|
run_follower(fresh,Wrapper,Worker,T) :-
|
||||||
|
activate(Wrapper,Worker,T),
|
||||||
|
shift(call_info(Wrapper,T)).
|
||||||
|
|
||||||
|
run_follower(active,Wrapper,_Worker,T) :-
|
||||||
|
shift(call_info(Wrapper,T)).
|
||||||
|
|
||||||
|
run_leader(Wrapper,Worker,T) :-
|
||||||
|
create_scheduling_component,
|
||||||
|
activate(Wrapper,Worker,T),
|
||||||
|
completion,
|
||||||
|
unset_scheduling_component.
|
||||||
|
|
||||||
|
exists_scheduling_component :-
|
||||||
|
bb_get(table_leader, Leader),
|
||||||
|
Leader == [].
|
||||||
|
|
||||||
|
create_scheduling_component :-
|
||||||
|
bb_b_put(table_leader, leaderCreated).
|
||||||
|
|
||||||
|
unset_scheduling_component :-
|
||||||
|
bb_put(table_leader, []).
|
||||||
|
|
||||||
|
set_all_complete :-
|
||||||
|
get_newly_created_table_identifiers(Ts, _),
|
||||||
|
set_all_complete_(Ts).
|
||||||
|
|
||||||
|
set_all_complete_([]).
|
||||||
|
set_all_complete_([T|Ts]) :-
|
||||||
|
set_complete_status(T),
|
||||||
|
set_all_complete_(Ts).
|
||||||
|
|
||||||
|
cleanup_all_complete :-
|
||||||
|
get_newly_created_table_identifiers(Ts,_),
|
||||||
|
cleanup_all_complete_(Ts).
|
||||||
|
|
||||||
|
cleanup_all_complete_([]).
|
||||||
|
cleanup_all_complete_([T|Ts]) :-
|
||||||
|
cleanup_after_complete(T),
|
||||||
|
cleanup_all_complete_(Ts).
|
||||||
|
|
||||||
|
activate(Wrapper,Worker,T) :-
|
||||||
|
set_active_status(T),
|
||||||
|
(
|
||||||
|
delim(Wrapper,Worker,T),
|
||||||
|
fail
|
||||||
|
;
|
||||||
|
true
|
||||||
|
).
|
||||||
|
|
||||||
|
delim(Wrapper,Worker,Table) :-
|
||||||
|
% debug(tabling, 'ACT: ~p on ~p', [Wrapper, Table]),
|
||||||
|
reset(Worker,SourceCall,Continuation),
|
||||||
|
( Continuation == none, var(SourceCall) ->
|
||||||
|
( add_answer(Table,Wrapper)
|
||||||
|
-> true %debug(tabling, 'ADD: ~p', [Wrapper])
|
||||||
|
; %debug(tabling, 'DUP: ~p', [Wrapper]),
|
||||||
|
fail
|
||||||
|
)
|
||||||
|
;
|
||||||
|
( Continuation = cont(Cont) ->
|
||||||
|
true
|
||||||
|
; Continuation = none ->
|
||||||
|
Cont = true
|
||||||
|
),
|
||||||
|
SourceCall = call_info(_,SourceTable),
|
||||||
|
TargetCall = call_info(Wrapper,Table),
|
||||||
|
Dependency = dependency(SourceCall,Cont,TargetCall),
|
||||||
|
%debug(tabling, 'DEP: ~p: ~p', [SourceTable,Dependency]),
|
||||||
|
store_dependency(SourceTable,Dependency)
|
||||||
|
).
|
||||||
|
|
||||||
|
completion :-
|
||||||
|
( worklist_empty ->
|
||||||
|
set_all_complete,
|
||||||
|
cleanup_all_complete,
|
||||||
|
% The place of the call to reset is really important: it must happen after the completion. If you do it before, you will wrongly remove yourself from the list of newly created table identifiers. On starting hProlog there are no newly created table identifiers, and nb_getval gives [] which is the perfect value.
|
||||||
|
reset_newly_created_table_identifiers
|
||||||
|
;
|
||||||
|
pop_worklist(Table),
|
||||||
|
completion_step(Table),
|
||||||
|
completion
|
||||||
|
).
|
||||||
|
|
||||||
|
completion_step(SourceTableID) :-
|
||||||
|
bb_get(SourceTableID, Table),
|
||||||
|
get_nb_identifiers(Table, NBWorklistID, _),
|
||||||
|
(
|
||||||
|
table_get_work(NBWorklistID,Answer,dependency(Source,Continuation,Target)),
|
||||||
|
Source = call_info(Answer,_),
|
||||||
|
Target = call_info(Wrapper,TargetTable),
|
||||||
|
delim(Wrapper,Continuation,TargetTable),
|
||||||
|
fail
|
||||||
|
;
|
||||||
|
true
|
||||||
|
).
|
||||||
|
|
||||||
|
table_get_work(NBWorklistID,Answer,Dependency) :-
|
||||||
|
% get_worklist(Table, Worklist),
|
||||||
|
% NOT IN PAPER (could be part of the definition of pop_worklist):
|
||||||
|
bb_get(NBWorklistID, table_nb_worklist(Worklist)),
|
||||||
|
unset_global_worklist_presence_flag(Worklist),
|
||||||
|
set_flag_executing_all_work(Worklist),
|
||||||
|
bb_put(NBWorklistID, table_nb_worklist(Worklist)),
|
||||||
|
table_get_work_(NBWorklistID,Answer,Dependency).
|
||||||
|
|
||||||
|
table_get_work_(NBWorklistID,Answer,Dependency) :-
|
||||||
|
worklist_do_all_work(NBWorklistID,Answer,Dependency0), % This will eventually fail
|
||||||
|
copy_term(Dependency0,Dependency).
|
||||||
|
|
||||||
|
table_get_work_(NBWorklistID,_Answer,_Dependency) :-
|
||||||
|
bb_get(NBWorklistID, table_nb_worklist(Worklist)),
|
||||||
|
unset_flag_executing_all_work(Worklist),
|
||||||
|
bb_put(NBWorklistID, table_nb_worklist(Worklist)),
|
||||||
|
fail.
|
||||||
|
|
||||||
|
worklist_do_all_work(NBWorklistID,Answer,Dependency) :-
|
||||||
|
( bb_get(NBWorklistID, table_nb_worklist(Worklist)),
|
||||||
|
wkl_worklist_work_done(Worklist) ->
|
||||||
|
fail
|
||||||
|
;
|
||||||
|
worklist_do_step(NBWorklistID,Answer,Dependency)
|
||||||
|
;
|
||||||
|
worklist_do_all_work(NBWorklistID,Answer,Dependency)
|
||||||
|
).
|
||||||
|
|
||||||
|
worklist_do_step(NBWorklistID,Answer,Dependency) :-
|
||||||
|
bb_get(NBWorklistID, table_nb_worklist(Worklist)),
|
||||||
|
wkl_p_get_rightmost_inner_answer_cluster_pointer(Worklist,ACP),
|
||||||
|
wkl_p_swap_answer_continuation(Worklist,ACP,SCP),
|
||||||
|
dll_get_data(ACP,wkl_answer_cluster(AListFlag)),
|
||||||
|
dll_get_data(SCP,wkl_suspension_cluster(SListFlag)),
|
||||||
|
get_atts(AListFlag, batched_worklist, wkl_answer_cluster(AList)),
|
||||||
|
get_atts(SListFlag, batched_worklist, wkl_suspension_cluster(SList)),
|
||||||
|
bb_put(NBWorklistID, table_nb_worklist(Worklist)),
|
||||||
|
member(Answer,AList),
|
||||||
|
member(Dependency,SList).
|
||||||
|
|
||||||
|
:- initialization(bb_put(table_leader, [])).
|
||||||
389
src/prolog/lib/tabling/batched_worklist.pl
Normal file
389
src/prolog/lib/tabling/batched_worklist.pl
Normal file
@@ -0,0 +1,389 @@
|
|||||||
|
/* Part of SWI-Prolog
|
||||||
|
|
||||||
|
Author: Benoit Desouter <Benoit.Desouter@UGent.be>
|
||||||
|
Jan Wielemaker (SWI-Prolog port)
|
||||||
|
Copyright (c) 2016, Benoit Desouter
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Ported to Scryer Prolog by Mark Thom (2019/2020).
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:- module(batched_worklist,
|
||||||
|
[ wkl_add_answer/2, % +WorkList, +Answer
|
||||||
|
wkl_add_suspension/2, % +Worklist, +Suspension
|
||||||
|
wkl_new_worklist/2, % +TableID, -WorkList
|
||||||
|
unset_flag_executing_all_work/1, % +WorkList
|
||||||
|
unset_global_worklist_presence_flag/1, % +WorkList
|
||||||
|
set_flag_executing_all_work/1, % +WorkList
|
||||||
|
wkl_p_get_rightmost_inner_answer_cluster_pointer/2, % +WorkList, -Cluster
|
||||||
|
wkl_p_swap_answer_continuation/3, % +WorkList, +Cluster1, +Cluster2
|
||||||
|
wkl_worklist_work_done/1 % +WorkList
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module(global_worklist).
|
||||||
|
:- use_module(double_linked_list).
|
||||||
|
|
||||||
|
:- use_module(library(atts)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
|
||||||
|
:- attribute executing_all_work/1, worklist_presence/1, wkl_answer_cluster/1, wkl_suspension_cluster/1, wkl_answer_cluster_pointer_flag/1.
|
||||||
|
|
||||||
|
/** <module> Tabling Worklist management
|
||||||
|
|
||||||
|
A batched worklist: a worklist that clusters suspensions and answers as
|
||||||
|
much as possible. The idea is to minimize the number of swaps. This
|
||||||
|
should be more efficient than the worklist implementation without
|
||||||
|
clustering.
|
||||||
|
|
||||||
|
Argument positions for nb_setarg:
|
||||||
|
|
||||||
|
1. double linked list
|
||||||
|
2. pointer to the list entry of the rightmost inner answer cluster
|
||||||
|
3. flag indicating the execution of wkl_unfolded_do_all_work
|
||||||
|
4. flag indicating whether the table identifier associated with this
|
||||||
|
worklist is already in the global worklist. This is because more
|
||||||
|
than one answer can be added due to the execution of other
|
||||||
|
worklists. 5: table identifier for the table this worklist belongs
|
||||||
|
to
|
||||||
|
|
||||||
|
Contents of a batched worklist:
|
||||||
|
|
||||||
|
- wkl_answer_cluster([Answer|RestAnswers]).
|
||||||
|
- wkl_suspension([Suspension|RestSuspension]).
|
||||||
|
|
||||||
|
The difficulty is that you should not add new entries to a cluster once
|
||||||
|
you started its execution. Probably the simplest way to do so is by
|
||||||
|
swapping the answer cluster AC and suspension cluster SC before you take
|
||||||
|
the cartesian product of all answers in AC with all suspensions in SC.
|
||||||
|
|
||||||
|
Illustration why you may need a complex procedure for finding the future
|
||||||
|
rightmost inner answer cluster.
|
||||||
|
|
||||||
|
Assume all clusters have 2 entries.
|
||||||
|
|
||||||
|
1. AA1 CC1
|
||||||
|
2. AA2 CC1 AA1 CC2 (swapped AA1 and CC1)
|
||||||
|
3. AA2 CC1 CC2 AA1 (swapped AA1 and CC2)
|
||||||
|
4. AA3 CC1 AA2 CC2 AA1 CC3 (swapped AA2 and CC1)
|
||||||
|
|
||||||
|
Now AA1 is the RIAC, but AA2 is the future RIAC.
|
||||||
|
|
||||||
|
Can you find the future RIAC smarter than by walking back? If you don't,
|
||||||
|
then it doesn't make sense to use a future RIAC at all. You could use a
|
||||||
|
stack, which should not grow too large because you use batches. But
|
||||||
|
walking back also should not take too long, since you use batches.
|
||||||
|
|
||||||
|
So let's not use a future RIAC in the first place, and just walk back
|
||||||
|
when we need a new RIAC. This is easy to implement, hence we can test
|
||||||
|
more quickly.
|
||||||
|
|
||||||
|
Abbreviations:
|
||||||
|
|
||||||
|
- RIAC = rightmost inner answer cluster
|
||||||
|
- FUTRIAC = future rightmost inner answer cluster
|
||||||
|
*/
|
||||||
|
|
||||||
|
%% wkl_new_worklist(+TableID, -WorkList) is det.
|
||||||
|
%
|
||||||
|
% Create a new worklist for TableID and add it to the global
|
||||||
|
% worklist list (global variable `table_global_worklist`.
|
||||||
|
|
||||||
|
wkl_new_worklist(TableIdentifier, wkl_worklist(List,AnswerClusterPointerFlag,ExecutingAllWork,WorklistPresence,TableIdentifier)) :-
|
||||||
|
dll_new_double_linked_list(List),
|
||||||
|
put_atts(AnswerClusterPointerFlag, wkl_answer_cluster_pointer_flag(List)),
|
||||||
|
% We set the RIAC to the dummy element at the start of the double linked list, which is List.
|
||||||
|
% Don't set all the rest for now.
|
||||||
|
put_atts(ExecutingAllWork, executing_all_work(false)),
|
||||||
|
put_atts(WorklistPresence, worklist_presence(true)),
|
||||||
|
add_to_global_worklist(TableIdentifier).
|
||||||
|
|
||||||
|
%% wkl_worklist_work_done(+WorkList) is semidet.
|
||||||
|
%
|
||||||
|
% The work is done if the RIAC pointer points to the unused cell
|
||||||
|
% at the beginning. The work is also done if the RIAC pointer
|
||||||
|
% points to the sole answer cluster in a list dll_start -
|
||||||
|
% wkl_answer_cluster, because in that case there are no
|
||||||
|
% suspensions to swap with. This is a special case, which we only
|
||||||
|
% discovered by testing. You can detect it by checking whether the
|
||||||
|
% NEXT-pointer of the RIAC is the dummy pointer.
|
||||||
|
|
||||||
|
wkl_worklist_work_done(Worklist) :-
|
||||||
|
wkl_p_get_rightmost_inner_answer_cluster_pointer(Worklist,RiacPointer),
|
||||||
|
( wkl_is_dummy_pointer(Worklist,RiacPointer) ->
|
||||||
|
true
|
||||||
|
;
|
||||||
|
dll_get_pointer_to_next(RiacPointer,NextPointer),
|
||||||
|
wkl_is_dummy_pointer(Worklist,NextPointer)
|
||||||
|
).
|
||||||
|
|
||||||
|
set_flag_executing_all_work(wkl_worklist(_,_,ExecutingAllWork,_,_)) :-
|
||||||
|
put_atts(ExecutingAllWork, executing_all_work(true)).
|
||||||
|
|
||||||
|
unset_flag_executing_all_work(wkl_worklist(_,_,ExecutingAllWork,_,_)) :-
|
||||||
|
put_atts(ExecutingAllWork, executing_all_work(false)).
|
||||||
|
|
||||||
|
% Swap answer cluster and the adjacent continuation cluster.
|
||||||
|
% Mode: + + -
|
||||||
|
wkl_p_swap_answer_continuation(Worklist,InnerAnswerClusterPointer,SuspensionClusterPointer) :-
|
||||||
|
% You can have a worklist containing only an answer cluster, but no continuations.
|
||||||
|
% In that case SuspensionClusterPointer will be dll_start. We must take our precautions elsewhere.
|
||||||
|
% Do not forget that the list of answers and the list of suspensions is wrapped in a predicate!
|
||||||
|
dll_get_pointer_to_next(InnerAnswerClusterPointer,SuspensionClusterPointer),
|
||||||
|
% For reasons of speed we don't use dll_swap: we only swap adjacent elements and we can be sure that they are in the order A,B.
|
||||||
|
% Therefore we can use dll_p_swap_adjacent_elements_
|
||||||
|
dll_p_swap_adjacent_elements_(InnerAnswerClusterPointer,SuspensionClusterPointer),
|
||||||
|
% Update the necessary pointers
|
||||||
|
wkl_p_update_righmost_inner_answer_cluster_pointer(Worklist,InnerAnswerClusterPointer).
|
||||||
|
|
||||||
|
% Update the pointer if the answer cluster it points to is no longer the rightmost inner answer cluster.
|
||||||
|
wkl_p_update_righmost_inner_answer_cluster_pointer(Worklist,InnerAnswerClusterPointer) :-
|
||||||
|
( wkl_p_answer_cluster_currently_moved_completely(Worklist,InnerAnswerClusterPointer) ->
|
||||||
|
wkl_p_find_new_rightmost_inner_answer_cluster_pointer(Worklist,InnerAnswerClusterPointer,NewRiacPointer),
|
||||||
|
wkl_p_set_rightmost_inner_answer_cluster_pointer(Worklist,NewRiacPointer)
|
||||||
|
;
|
||||||
|
true
|
||||||
|
).
|
||||||
|
|
||||||
|
% Rationale for this implementation: see the top of the file.
|
||||||
|
% Unify NewRiacPointer to the first pointer satisfying the following conditions:
|
||||||
|
% - left of StartPointer (when viewing the list as DUMMY-ELEM POINTER POINTER POINTER START-POINTER)
|
||||||
|
% - either an anwer pointer or the dummy element
|
||||||
|
% When StartPointer is the dummy element, NewRiacPointer is also the dummy element. We never look "in front of" the dummy element.
|
||||||
|
wkl_p_find_new_rightmost_inner_answer_cluster_pointer(Worklist,StartPointer,NewRiacPointer) :-
|
||||||
|
( wkl_is_dummy_pointer(Worklist,StartPointer) ->
|
||||||
|
NewRiacPointer = StartPointer
|
||||||
|
;
|
||||||
|
dll_get_pointer_to_previous(StartPointer,FirstCandidatePointer),
|
||||||
|
wkl_p_find_new_riac_helper(Worklist,FirstCandidatePointer,NewRiacPointer)
|
||||||
|
).
|
||||||
|
|
||||||
|
wkl_p_find_new_riac_helper(Worklist,CandidatePointer,NewRiacPointer) :-
|
||||||
|
( is_answer_cluster_or_dummy_pointer(Worklist,CandidatePointer) ->
|
||||||
|
NewRiacPointer = CandidatePointer
|
||||||
|
;
|
||||||
|
dll_get_pointer_to_previous(CandidatePointer,NewCandidate),
|
||||||
|
wkl_p_find_new_riac_helper(Worklist,NewCandidate,NewRiacPointer)
|
||||||
|
).
|
||||||
|
|
||||||
|
is_answer_cluster_or_dummy_pointer(Worklist,Pointer) :-
|
||||||
|
( wkl_is_dummy_pointer(Worklist,Pointer) ->
|
||||||
|
true
|
||||||
|
;
|
||||||
|
wkl_p_dereference_pointer(Worklist,Pointer,A),
|
||||||
|
wkl_p_is_answer_cluster(A)
|
||||||
|
).
|
||||||
|
|
||||||
|
% Failure-driven loop
|
||||||
|
wkl_clusters_cartesian_product(AnswerCluster,SuspensionCluster) :-
|
||||||
|
( member(Answer,AnswerCluster),
|
||||||
|
member(Suspension,SuspensionCluster),
|
||||||
|
% The meat
|
||||||
|
run_worklist_helper(Suspension,Answer),
|
||||||
|
% Trigger loop
|
||||||
|
fail
|
||||||
|
;
|
||||||
|
% Loop base case
|
||||||
|
true
|
||||||
|
).
|
||||||
|
|
||||||
|
run_worklist_helper(_Suspension, _Answer) :- % FIXME: just silense
|
||||||
|
throw('not implemented').
|
||||||
|
|
||||||
|
wkl_both_flags_unset(wkl_worklist(_Dll,_Riac,ExecutingAllWork,WorklistPresence,_TableIdentifier)) :-
|
||||||
|
put_atts(ExecutingAllWork, executing_all_work(false)),
|
||||||
|
put_atts(WorklistPresence, worklist_presence(false)).
|
||||||
|
|
||||||
|
set_global_worklist_presence_flag(wkl_worklist(_,_,_,WorklistPresence,_)) :-
|
||||||
|
put_atts(WorklistPresence, worklist_presence(true)).
|
||||||
|
|
||||||
|
unset_global_worklist_presence_flag(wkl_worklist(_,_,_,WorklistPresence,_)) :-
|
||||||
|
put_atts(WorklistPresence, worklist_presence(false)).
|
||||||
|
|
||||||
|
potentially_add_to_global_worklist(Worklist) :-
|
||||||
|
( wkl_both_flags_unset(Worklist) ->
|
||||||
|
% Set the flag for presence in the metaworklist
|
||||||
|
set_global_worklist_presence_flag(Worklist),
|
||||||
|
% Should add to the metaworklist
|
||||||
|
arg(5,Worklist,TableIdentifier),
|
||||||
|
add_to_global_worklist(TableIdentifier)
|
||||||
|
;
|
||||||
|
% Nothing to do.
|
||||||
|
true
|
||||||
|
).
|
||||||
|
|
||||||
|
wkl_add_answer(Worklist,Answer) :-
|
||||||
|
% Add to global worklist if not executing during wkl_unfolded_do_all_work and not there yet as well.
|
||||||
|
potentially_add_to_global_worklist(Worklist),
|
||||||
|
( wkl_p_leftmost_cluster_is_answer_cluster(Worklist) ->
|
||||||
|
wkl_add_to_existing_answer_cluster(Worklist,Answer)
|
||||||
|
% If you add to an existing cluster, then obviously you should not change the RIAC.
|
||||||
|
;
|
||||||
|
wkl_add_to_new_answer_cluster(Worklist,Answer,AnswerClusterPointer),
|
||||||
|
% If the RIAC is the dummy pointer, we need to change that.
|
||||||
|
wkl_p_update_rightmost_inner_answer_cluster_pointer(Worklist,AnswerClusterPointer)
|
||||||
|
).
|
||||||
|
|
||||||
|
wkl_p_update_rightmost_inner_answer_cluster_pointer(Worklist,NewAnswerClusterPointer) :-
|
||||||
|
wkl_p_get_rightmost_inner_answer_cluster_pointer(Worklist,CurrentRiac),
|
||||||
|
( wkl_is_dummy_pointer(Worklist,CurrentRiac) -> %% <- debugging this.
|
||||||
|
wkl_p_set_rightmost_inner_answer_cluster_pointer(Worklist,NewAnswerClusterPointer)
|
||||||
|
;
|
||||||
|
% Nothing to do.
|
||||||
|
true
|
||||||
|
).
|
||||||
|
|
||||||
|
wkl_add_suspension(Worklist,Suspension) :-
|
||||||
|
% Add to global worklist if not executing during wkl_unfolded_do_all_work and not there yet as well.
|
||||||
|
potentially_add_to_global_worklist(Worklist),
|
||||||
|
( wkl_p_rightmost_cluster_is_suspension_cluster(Worklist) ->
|
||||||
|
wkl_add_to_existing_suspension_cluster(Worklist,Suspension)
|
||||||
|
;
|
||||||
|
wkl_add_to_new_suspension_cluster(Worklist,Suspension,SuspensionClusterPointer),
|
||||||
|
% If added to a new suspension cluster, we may need to change the righmost inner answer pointer
|
||||||
|
wkl_p_potential_rias_update_add_contin(Worklist,SuspensionClusterPointer)
|
||||||
|
).
|
||||||
|
|
||||||
|
% This predicate should not fail.
|
||||||
|
wkl_p_potential_rias_update_add_contin(Worklist,SuspensionClusterPointer) :-
|
||||||
|
% Look back one entry of the freshly inserted SuspensionClusterPointer
|
||||||
|
dll_get_pointer_to_previous(SuspensionClusterPointer,PotentialNewRiacPointer),
|
||||||
|
( wkl_p_is_answer_cluster_pointer(Worklist,PotentialNewRiacPointer) ->
|
||||||
|
% We must indeed update the rightmost inner answer cluster pointer.
|
||||||
|
wkl_p_set_rightmost_inner_answer_cluster_pointer(Worklist,PotentialNewRiacPointer)
|
||||||
|
;
|
||||||
|
% Nothing to do, but we should not fail.
|
||||||
|
true
|
||||||
|
).
|
||||||
|
|
||||||
|
wkl_add_to_existing_answer_cluster(Worklist, Answer) :-
|
||||||
|
arg(1,Worklist,Dll),
|
||||||
|
dll_get_pointer_to_next(Dll,AnswerClusterPointer),
|
||||||
|
wkl_p_dereference_pointer(Worklist,AnswerClusterPointer,AnswerCluster),
|
||||||
|
AnswerCluster = wkl_answer_cluster(AnswersFlag),
|
||||||
|
get_atts(AnswersFlag, wkl_answer_cluster(AnswersAlreadyInCluster)),
|
||||||
|
put_atts(AnswersFlag, wkl_answer_cluster([Answer|AnswersAlreadyInCluster])).
|
||||||
|
|
||||||
|
wkl_add_to_new_answer_cluster(
|
||||||
|
wkl_worklist(Dll,_Ria,_FlagExecutingWork,_AlreadyInMetaworklist,_TableIdentifier),
|
||||||
|
Answer,AnswerClusterPointer
|
||||||
|
) :-
|
||||||
|
dll_append_left(Dll,wkl_answer_cluster(AnswerFlag),AnswerClusterPointer),
|
||||||
|
put_atts(AnswerFlag, wkl_answer_cluster([Answer])).
|
||||||
|
|
||||||
|
wkl_add_to_existing_suspension_cluster(Worklist, Suspension) :-
|
||||||
|
arg(1,Worklist,Dll),
|
||||||
|
dll_get_pointer_to_previous(Dll,SuspensionClusterPointer),
|
||||||
|
wkl_p_dereference_pointer(Worklist,SuspensionClusterPointer,SuspensionCluster),
|
||||||
|
SuspensionCluster = wkl_suspension_cluster(SuspensionsFlag),
|
||||||
|
get_atts(SuspensionsFlag, wkl_suspension_cluster(SuspensionsAlreadyInCluster)),
|
||||||
|
put_atts(SuspensionsFlag, wkl_suspension_cluster([Suspension|SuspensionsAlreadyInCluster])).
|
||||||
|
%% nb_linkarg(1,SuspensionCluster,[Suspension|SuspensionsAlreadyInCluster]).
|
||||||
|
|
||||||
|
wkl_add_to_new_suspension_cluster(
|
||||||
|
wkl_worklist(Dll,_Ria,_FlagExecutingWork,_AlreadyInMetaworklist,_TableIdentifier),
|
||||||
|
Suspension,
|
||||||
|
SuspensionClusterPointer
|
||||||
|
) :-
|
||||||
|
put_atts(SuspensionFlag, wkl_suspension_cluster([Suspension])),
|
||||||
|
dll_append_right(Dll,wkl_suspension_cluster(SuspensionFlag),SuspensionClusterPointer).
|
||||||
|
|
||||||
|
wkl_p_is_answer_cluster(CandidateAnswerCluster) :-
|
||||||
|
nonvar(CandidateAnswerCluster),
|
||||||
|
CandidateAnswerCluster = wkl_answer_cluster(_).
|
||||||
|
|
||||||
|
wkl_p_is_suspension_cluster(CandidateSuspensionCluster) :-
|
||||||
|
nonvar(CandidateSuspensionCluster),
|
||||||
|
CandidateSuspensionCluster = wkl_suspension_cluster(_).
|
||||||
|
|
||||||
|
wkl_p_leftmost_cluster_is_answer_cluster(Worklist) :-
|
||||||
|
arg(1,Worklist,Dll),
|
||||||
|
dll_get_pointer_to_next(Dll,CandidateAnswerClusterPointer),
|
||||||
|
wkl_p_is_answer_cluster_pointer(Worklist,CandidateAnswerClusterPointer).
|
||||||
|
|
||||||
|
wkl_p_rightmost_cluster_is_suspension_cluster(Worklist) :-
|
||||||
|
arg(1,Worklist,Dll),
|
||||||
|
dll_get_pointer_to_previous(Dll,CandidateSuspensionClusterPointer),
|
||||||
|
wkl_p_is_suspension_cluster_pointer(Worklist,CandidateSuspensionClusterPointer).
|
||||||
|
|
||||||
|
|
||||||
|
wkl_p_get_rightmost_inner_answer_cluster_pointer(wkl_worklist(_Dll,InnerAnswerClusterPointerFlag,_FlagExecutingWork,_AlreadyInMetaworklist,_TableIdentifier), InnerAnswerClusterPointer) :-
|
||||||
|
get_atts(InnerAnswerClusterPointerFlag, wkl_answer_cluster_pointer_flag(InnerAnswerClusterPointer)).
|
||||||
|
|
||||||
|
% Succeed if there are currently no more continuation clusters on the right of the given position:
|
||||||
|
% Why 'currently' in the name? Another continuation can be added.
|
||||||
|
wkl_p_answer_cluster_currently_moved_completely(Worklist,AnswerClusterPointer) :-
|
||||||
|
( wkl_p_at_right(Worklist,AnswerClusterPointer) ->
|
||||||
|
true
|
||||||
|
;
|
||||||
|
wkl_p_answer_cluster_on_right(Worklist,AnswerClusterPointer)
|
||||||
|
).
|
||||||
|
|
||||||
|
% Succeeds if the given pointer points to the last element in the list. That is, if its next pointer is the dummy element in the double linked list.
|
||||||
|
wkl_p_at_right(Worklist,Pointer) :-
|
||||||
|
dll_get_pointer_to_next(Pointer,NextPointer),
|
||||||
|
wkl_is_dummy_pointer(Worklist,NextPointer).
|
||||||
|
|
||||||
|
wkl_p_answer_cluster_on_right(Worklist,Pointer) :-
|
||||||
|
dll_get_pointer_to_next(Pointer,NextPointer),
|
||||||
|
wkl_p_is_answer_cluster_pointer(Worklist,NextPointer).
|
||||||
|
|
||||||
|
wkl_is_dummy_pointer(Worklist,Pointer) :-
|
||||||
|
wkl_p_get_double_linked_list(Worklist,Dll),
|
||||||
|
dll_is_dummy_pointer(Dll,Pointer).
|
||||||
|
|
||||||
|
wkl_p_is_answer_cluster_pointer(Worklist,PointerCandidateAnswerCluster) :-
|
||||||
|
( wkl_is_dummy_pointer(Worklist,PointerCandidateAnswerCluster) ->
|
||||||
|
% Certainly not an answer cluster, should not dereference this
|
||||||
|
fail
|
||||||
|
;
|
||||||
|
wkl_p_dereference_pointer(Worklist,PointerCandidateAnswerCluster,CandidateAnswerCluster),
|
||||||
|
wkl_p_is_answer_cluster(CandidateAnswerCluster)
|
||||||
|
).
|
||||||
|
|
||||||
|
wkl_p_is_suspension_cluster_pointer(Worklist,PointerCandidateSuspensionCluster) :-
|
||||||
|
( wkl_is_dummy_pointer(Worklist,PointerCandidateSuspensionCluster) ->
|
||||||
|
% Certainly not an answer cluster, should not dereference this
|
||||||
|
fail
|
||||||
|
;
|
||||||
|
wkl_p_dereference_pointer(Worklist,PointerCandidateSuspensionCluster,CandidateSuspensionCluster),
|
||||||
|
wkl_p_is_suspension_cluster(CandidateSuspensionCluster)
|
||||||
|
).
|
||||||
|
|
||||||
|
wkl_p_get_double_linked_list(Worklist,Dll) :-
|
||||||
|
arg(1,Worklist,Dll).
|
||||||
|
|
||||||
|
% One should not attempt to dereference the dummy pointer in the double linked list.
|
||||||
|
wkl_p_dereference_pointer(_Worklist,Pointer,Data) :-
|
||||||
|
dll_get_data(Pointer,Data).
|
||||||
|
|
||||||
|
% SETTING POINTERS
|
||||||
|
%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
wkl_p_set_rightmost_inner_answer_cluster_pointer(Worklist,AnswerClusterPointer) :-
|
||||||
|
arg(2, Worklist, AnswerClusterPointerFlag),
|
||||||
|
put_atts(AnswerClusterPointerFlag, wkl_answer_cluster_pointer_flag(AnswerClusterPointer)).
|
||||||
211
src/prolog/lib/tabling/double_linked_list.pl
Normal file
211
src/prolog/lib/tabling/double_linked_list.pl
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/* Part of SWI-Prolog
|
||||||
|
|
||||||
|
Author: Benoit Desouter <Benoit.Desouter@UGent.be>
|
||||||
|
Jan Wielemaker (SWI-Prolog port)
|
||||||
|
Copyright (c) 2016, Benoit Desouter
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Ported to Scryer Prolog by Mark Thom (2019/2020).
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:- module(double_linked_list,
|
||||||
|
[ dll_new_double_linked_list/1, % -List
|
||||||
|
dll_append_right/2, % !List, +Element
|
||||||
|
dll_append_left/2, % !List, +Element
|
||||||
|
dll_append_right/3, % !List, +Element, -Pointer
|
||||||
|
dll_append_left/3, % !List, +Element, -Pointer
|
||||||
|
dll_get_data/2, % +List, -Head
|
||||||
|
dll_get_pointer_to_next/2, % +List, -Pointer
|
||||||
|
dll_get_pointer_to_previous/2, % +List, -Pointer
|
||||||
|
dll_is_dummy_pointer/2, % +List, +Pointer
|
||||||
|
dll_p_swap_adjacent_elements_/2, % +Pointer1, +Pointer2
|
||||||
|
dll_get_contents/2,
|
||||||
|
dll_get_reverse_contents/2
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module(library(atts)).
|
||||||
|
|
||||||
|
:- attribute dll_element/1, dll_next/1, dll_prev/1.
|
||||||
|
|
||||||
|
% A circular double linked list
|
||||||
|
% =============================
|
||||||
|
|
||||||
|
% Always have a unused-cell at the beginning.
|
||||||
|
|
||||||
|
% I do not always inline unifications because the head is then more readable for users who don't need to know the details.
|
||||||
|
|
||||||
|
% Due to lack of modules in hProlog, the following predicate names should not be used elsewhere:
|
||||||
|
% - the heads of all following rules (starting with dll_, I reserve "the namespace"!)
|
||||||
|
|
||||||
|
% dll_cell(Element,Next,Previous)
|
||||||
|
|
||||||
|
% The following is perhaps odd:
|
||||||
|
%
|
||||||
|
% Next link = more to the front (the left)
|
||||||
|
% Previous link = more to the back (the right)
|
||||||
|
%
|
||||||
|
% List structure
|
||||||
|
% --------------
|
||||||
|
% front-of-the-list | ... | back-of-the-list
|
||||||
|
|
||||||
|
dll_new_double_linked_list(List) :-
|
||||||
|
% Nonused cell dll_start at the beginning, points to itself (this is easy when adding elements).
|
||||||
|
List = dll_cell(Start),
|
||||||
|
put_atts(Start, [dll_next(List), dll_prev(List), dll_element(dll_start)]).
|
||||||
|
|
||||||
|
dll_append_right(List, Element) :-
|
||||||
|
dll_append_right(List, Element, _).
|
||||||
|
|
||||||
|
dll_append_left(List, Element) :-
|
||||||
|
dll_append_left(List, Element, _).
|
||||||
|
|
||||||
|
% Append at the back of the list
|
||||||
|
% Mode: + + -
|
||||||
|
dll_append_right(List, Element, Pointer) :-
|
||||||
|
% Get pointer to cell currently at the back. Done by taking the previous element from the unused element representing the list.
|
||||||
|
dll_get_pointer_to_previous(List, OldBack),
|
||||||
|
% Make the new cell point to OldBack as predecessor
|
||||||
|
% Make the new cell point to the unused cell as successor.
|
||||||
|
Pointer = dll_cell(NewCell),
|
||||||
|
put_atts(NewCell, [dll_element(Element), dll_next(List), dll_prev(OldBack)]),
|
||||||
|
% Make OldBack point to the new cell as successor
|
||||||
|
dll_p_set_next_pointer(OldBack, Pointer),
|
||||||
|
% Make the unused cell point to the new cell as predecessor
|
||||||
|
dll_p_set_previous_pointer(List, Pointer).
|
||||||
|
|
||||||
|
% Add to the front of the list
|
||||||
|
% Mode: + + -
|
||||||
|
dll_append_left(List, Element, Pointer) :-
|
||||||
|
% Get pointer to cell currently at the front. Done by taking the next element from the unused element representing the list.
|
||||||
|
dll_get_pointer_to_next(List, OldFront),
|
||||||
|
% Make the new cell point to OldFront as successor
|
||||||
|
% Make the new cell point to the unused cell as predecessor
|
||||||
|
Pointer = dll_cell(NewCell),
|
||||||
|
put_atts(NewCell, [dll_element(Element), dll_prev(List), dll_next(OldFront)]),
|
||||||
|
% Make OldFront point to the new cell as predecessor
|
||||||
|
dll_p_set_previous_pointer(OldFront, Pointer),
|
||||||
|
% Make the unused cell point to the new cell as successor
|
||||||
|
dll_p_set_next_pointer(List, Pointer).
|
||||||
|
|
||||||
|
% get_next_cell?
|
||||||
|
dll_get_pointer_to_next(dll_cell(Cell), PointerNext) :-
|
||||||
|
get_atts(Cell, dll_next(PointerNext)).
|
||||||
|
|
||||||
|
% get_previous_cell?
|
||||||
|
dll_get_pointer_to_previous(dll_cell(Cell), PointerPrevious) :-
|
||||||
|
get_atts(Cell, dll_prev(PointerPrevious)).
|
||||||
|
|
||||||
|
% Will happily give you the "data" from the unused cell at the beginning. (We use this odd behaviour below, f.e. in dll_p_foreach_element_/2.)
|
||||||
|
dll_get_data(dll_cell(Cell), Element) :-
|
||||||
|
get_atts(Cell, dll_element(Element)).
|
||||||
|
|
||||||
|
dll_is_dummy_pointer(List, Pointer) :-
|
||||||
|
dll_get_contents(List, ListContents),
|
||||||
|
dll_get_contents(Pointer, PointerContents),
|
||||||
|
\+ PointerContents \= ListContents.
|
||||||
|
|
||||||
|
% Special case of swapping - used in dll_swap/2.
|
||||||
|
% This is also the case used for swapping a freshly created list with itself.
|
||||||
|
%
|
||||||
|
% Sketch: APrevious <-> PointerA <-> PointerB <-> BNext etc.
|
||||||
|
dll_p_swap_adjacent_elements(PointerA, PointerB) :-
|
||||||
|
% Order B A?
|
||||||
|
( dll_get_pointer_to_next(PointerB, PointerA) ->
|
||||||
|
dll_p_swap_adjacent_elements_(PointerB, PointerA)
|
||||||
|
;
|
||||||
|
% Order A B!
|
||||||
|
dll_p_swap_adjacent_elements_(PointerA, PointerB)
|
||||||
|
).
|
||||||
|
|
||||||
|
% Assumes the order A B.
|
||||||
|
dll_p_swap_adjacent_elements_(PointerA, PointerB) :-
|
||||||
|
% Get A's previous and B's next
|
||||||
|
dll_get_pointer_to_previous(PointerA, PointerAPrevious),
|
||||||
|
dll_get_pointer_to_next(PointerB, PointerBNext),
|
||||||
|
% Set A's previous to B
|
||||||
|
dll_p_set_previous_pointer(PointerA, PointerB),
|
||||||
|
% Set B's next to A
|
||||||
|
dll_p_set_next_pointer(PointerB, PointerA),
|
||||||
|
% Set A's next to BNext
|
||||||
|
dll_p_set_next_pointer(PointerA, PointerBNext),
|
||||||
|
% Set B's previous to APrevious
|
||||||
|
dll_p_set_previous_pointer(PointerB, PointerAPrevious),
|
||||||
|
% Set APrevious' next to B !!
|
||||||
|
dll_p_set_next_pointer(PointerAPrevious, PointerB),
|
||||||
|
% Set BNext's previous to A !!
|
||||||
|
dll_p_set_previous_pointer(PointerBNext, PointerA).
|
||||||
|
|
||||||
|
% Private
|
||||||
|
% Careful: make sure this is called on the actual cell, and not some copy.
|
||||||
|
% Mode: + +
|
||||||
|
dll_p_set_previous_pointer(dll_cell(Cell), PointerToNewPrevious) :-
|
||||||
|
put_atts(Cell, dll_prev(PointerToNewPrevious)).
|
||||||
|
|
||||||
|
% Private
|
||||||
|
% Careful: make sure this is called on the actual cell, and not some copy.
|
||||||
|
% Mode: + +
|
||||||
|
dll_p_set_next_pointer(dll_cell(Cell), PointerToNewNext) :-
|
||||||
|
put_atts(Cell, dll_next(PointerToNewNext)).
|
||||||
|
|
||||||
|
dll_extract_element(ElementFlag, Element) :-
|
||||||
|
( ElementFlag = wkl_suspension_cluster(SuspensionClusterFlag) ->
|
||||||
|
get_atts(SuspensionClusterFlag, batched_worklist, wkl_suspension_cluster(SuspensionCluster)),
|
||||||
|
Element = wkl_suspension_cluster(SuspensionCluster)
|
||||||
|
; ElementFlag = wkl_answer_cluster(AnswerClusterFlag) ->
|
||||||
|
get_atts(AnswerClusterFlag, batched_worklist, wkl_answer_cluster(AnswerCluster)),
|
||||||
|
Element = wkl_answer_cluster(AnswerCluster)
|
||||||
|
).
|
||||||
|
|
||||||
|
dll_get_contents(List, Contents) :-
|
||||||
|
dll_get_pointer_to_next(List, Next),
|
||||||
|
dll_get_contents_(Next, Contents).
|
||||||
|
|
||||||
|
dll_get_contents_(List, Contents) :-
|
||||||
|
dll_get_data(List, ElementFlag),
|
||||||
|
( ElementFlag == dll_start ->
|
||||||
|
Contents = []
|
||||||
|
; dll_extract_element(ElementFlag, Element),
|
||||||
|
Contents = [Element | Rest],
|
||||||
|
dll_get_pointer_to_next(List, Next),
|
||||||
|
dll_get_contents_(Next, Rest)
|
||||||
|
).
|
||||||
|
|
||||||
|
dll_get_reverse_contents(List, Contents) :-
|
||||||
|
dll_get_pointer_to_previous(List, Prev),
|
||||||
|
dll_get_reverse_contents_(Prev, Contents).
|
||||||
|
|
||||||
|
dll_get_reverse_contents_(List, Contents) :-
|
||||||
|
dll_get_data(List, ElementFlag),
|
||||||
|
( ElementFlag == dll_start ->
|
||||||
|
Contents = []
|
||||||
|
; dll_extract_element(ElementFlag, Element),
|
||||||
|
Contents = [Element | Rest],
|
||||||
|
dll_get_pointer_to_previous(List, Prev),
|
||||||
|
dll_get_reverse_contents_(Prev, Rest)
|
||||||
|
).
|
||||||
|
|
||||||
40
src/prolog/lib/tabling/global_worklist.pl
Normal file
40
src/prolog/lib/tabling/global_worklist.pl
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/* Ported to Scryer Prolog by Mark Thom (2019/2020).
|
||||||
|
*/
|
||||||
|
|
||||||
|
:- module(global_worklist,
|
||||||
|
[ put_new_global_worklist/0,
|
||||||
|
add_to_global_worklist/1,
|
||||||
|
worklist_empty/0,
|
||||||
|
pop_worklist/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module(library(atts)).
|
||||||
|
:- use_module(library(non_iso)).
|
||||||
|
|
||||||
|
:- attribute table_global_worklist/1.
|
||||||
|
|
||||||
|
put_new_global_worklist :-
|
||||||
|
( bb_get(table_global_worklist_initialized, _) ->
|
||||||
|
true
|
||||||
|
; put_atts(Worklist, table_global_worklist([])),
|
||||||
|
bb_put(table_global_worklist, Worklist),
|
||||||
|
bb_b_put(table_global_worklist_initialized, [])
|
||||||
|
).
|
||||||
|
|
||||||
|
add_to_global_worklist(TableIdentifier) :-
|
||||||
|
bb_get(table_global_worklist, TableGlobalWorklistFlag),
|
||||||
|
get_atts(TableGlobalWorklistFlag, table_global_worklist(L1)),
|
||||||
|
put_atts(TableGlobalWorklistFlag, table_global_worklist([TableIdentifier|L1])),
|
||||||
|
bb_put(table_global_worklist, TableGlobalWorklistFlag).
|
||||||
|
|
||||||
|
worklist_empty :-
|
||||||
|
bb_get(table_global_worklist,TableGlobalWorklistFlag),
|
||||||
|
get_atts(TableGlobalWorklistFlag, table_global_worklist(L)),
|
||||||
|
L == [].
|
||||||
|
|
||||||
|
pop_worklist(TableIdentifier) :-
|
||||||
|
bb_get(table_global_worklist,TableGlobalWorklistFlag),
|
||||||
|
get_atts(TableGlobalWorklistFlag, table_global_worklist(L1)),
|
||||||
|
L1 = [TableIdentifier|L2],
|
||||||
|
put_atts(TableGlobalWorklistFlag, table_global_worklist(L2)),
|
||||||
|
bb_put(table_global_worklist, TableGlobalWorklistFlag).
|
||||||
253
src/prolog/lib/tabling/table_data_structure.pl
Normal file
253
src/prolog/lib/tabling/table_data_structure.pl
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
:- module(table_datastructure,
|
||||||
|
[ get_answer/2, % +TableID, -Answer
|
||||||
|
add_answer/2, % +TableID, +Answer
|
||||||
|
get_call_variant/2, % +TableID, -CallVariant
|
||||||
|
set_complete_status/1, % +TableID
|
||||||
|
set_active_status/1, % +TableID
|
||||||
|
tbd_table_status/2, % +TableID, -Status
|
||||||
|
table_for_variant/2, % +Variant, -TableID
|
||||||
|
store_dependency/2, % +TableID, +Suspension
|
||||||
|
cleanup_after_complete/1, % +TableID
|
||||||
|
get_newly_created_table_identifiers/2, % NewlyCreatedTableIDs, NumIDs
|
||||||
|
reset_newly_created_table_identifiers/0,
|
||||||
|
answers_for_variant/2, % +Variant, -Answers
|
||||||
|
put_new_table_identifiers/0,
|
||||||
|
get_nb_identifiers/3 % +Table, -NbWorklistID, -NbAnswerTreeID
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module(table_link_manager).
|
||||||
|
:- use_module(trie).
|
||||||
|
|
||||||
|
/* Part of SWI-Prolog
|
||||||
|
|
||||||
|
Author: Benoit Desouter <Benoit.Desouter@UGent.be>
|
||||||
|
Jan Wielemaker (SWI-Prolog port)
|
||||||
|
Copyright (c) 2016, Benoit Desouter
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Ported to Scryer Prolog by Mark Thom (2019/2020).
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:- use_module(batched_worklist).
|
||||||
|
|
||||||
|
:- use_module(library(atts)).
|
||||||
|
:- use_module(library(gensym)).
|
||||||
|
:- use_module(library(non_iso)).
|
||||||
|
|
||||||
|
:- attribute table_status/1, newly_created_table_identifiers/1.
|
||||||
|
|
||||||
|
% This file defines the table datastructure.
|
||||||
|
%
|
||||||
|
% The table datastructure contains the following sub-structures:
|
||||||
|
% - the answer trie
|
||||||
|
% - the worklist
|
||||||
|
%
|
||||||
|
% Structure for tables:
|
||||||
|
% table(CallVariant,Status,AnswerTrie,Worklist) or complete_table(CallVariant,AnswerTrie).
|
||||||
|
% where AnswerTrie contains a trie of unique answers
|
||||||
|
%
|
||||||
|
% Remember that a table may also be nonexistent!
|
||||||
|
% nb_getval(nonexistent,X) then gives [].
|
||||||
|
|
||||||
|
put_new_table_identifiers :-
|
||||||
|
( bb_get(newly_created_table_identifiers_initialized, _) ->
|
||||||
|
true
|
||||||
|
; put_atts(NewlyCreatedFlag, newly_created_table_identifiers([]-0)),
|
||||||
|
bb_b_put(newly_created_table_identifiers, NewlyCreatedFlag),
|
||||||
|
bb_b_put(newly_created_table_identifiers_initialized, [])
|
||||||
|
).
|
||||||
|
|
||||||
|
% Returns a list of newly created table identifiers since the last call to reset_newly_created_table_identifiers/0, as well as the length of the list.
|
||||||
|
get_newly_created_table_identifiers(NewlyCreatedTableIdentifiers,NumIdentifiers) :-
|
||||||
|
bb_get(newly_created_table_identifiers, NewlyCreatedFlag),
|
||||||
|
get_atts(NewlyCreatedFlag, newly_created_table_identifiers(NewlyCreatedTableIdentifiers-NumIdentifiers)).
|
||||||
|
|
||||||
|
reset_newly_created_table_identifiers :-
|
||||||
|
bb_get(newly_created_table_identifiers, NewlyCreatedFlag),
|
||||||
|
put_atts(NewlyCreatedFlag, newly_created_table_identifiers([]-0)).
|
||||||
|
|
||||||
|
add_to_newly_created_table_identifiers(TableIdentifier) :-
|
||||||
|
bb_get(newly_created_table_identifiers, NewlyCreatedFlag),
|
||||||
|
get_atts(NewlyCreatedFlag, newly_created_table_identifiers(L1-Num1)),
|
||||||
|
Num2 is Num1 + 1,
|
||||||
|
put_atts(NewlyCreatedFlag, newly_created_table_identifiers([TableIdentifier|L1]-Num2)).
|
||||||
|
|
||||||
|
% PRIVATE
|
||||||
|
% Mode: + -
|
||||||
|
%
|
||||||
|
% Created in the fresh status.
|
||||||
|
p_create_table(CallVariant,TableIdentifier) :-
|
||||||
|
% We use a copy_term here so that we can be sure not to corrupt our table if CallVariant is "changed" afterwards.
|
||||||
|
copy_term(CallVariant,CallVariant2),
|
||||||
|
% Generate a table identifier, create the table and do bookkeeping.
|
||||||
|
gensym(table,TableIdentifier),
|
||||||
|
% Create a trie and a worklist.
|
||||||
|
trie_new(EmptyTrie),
|
||||||
|
wkl_new_worklist(TableIdentifier,NewWorklist),
|
||||||
|
put_atts(StatusFlag, table_status(fresh)),
|
||||||
|
%% this is important! we don't want to copy the incomplete table every time we refer to it,
|
||||||
|
%% which would occur if we used bb_put here.
|
||||||
|
%% note that the complete_table variant is written to the blackboard using bb_get.
|
||||||
|
atom_concat(TableIdentifier, nb_worklist, NbWorklistID),
|
||||||
|
atom_concat(TableIdentifier, nb_answer_trie, NbAnswerTrieID),
|
||||||
|
bb_put(TableIdentifier, table(CallVariant2,StatusFlag,NbWorklistID,NbAnswerTrieID)),
|
||||||
|
bb_put(NbWorklistID, table_nb_worklist(NewWorklist)),
|
||||||
|
bb_put(NbAnswerTrieID, table_nb_answer_trie(EmptyTrie)),
|
||||||
|
p_link_variant_identifier(CallVariant2,TableIdentifier),
|
||||||
|
add_to_newly_created_table_identifiers(TableIdentifier).
|
||||||
|
|
||||||
|
% Get the Status for table TableIdentifier
|
||||||
|
% Throws exception if this table does not exist.
|
||||||
|
tbd_table_status(TableIdentifier,Status) :-
|
||||||
|
p_get_table_for_identifier(TableIdentifier,Table),
|
||||||
|
tbd_table_status_(Table,Status).
|
||||||
|
|
||||||
|
% Is also used in other predicates than tbd_table_status.
|
||||||
|
tbd_table_status_(table(_CallVariant,StatusFlag,_NbWorklistID, _NbAnswerTrieID),Status) :-
|
||||||
|
get_atts(StatusFlag, table_status(Status)).
|
||||||
|
tbd_table_status_(complete_table(_,_,_),complete).
|
||||||
|
|
||||||
|
% PRIVATE
|
||||||
|
% Table must already exist.
|
||||||
|
p_get_table_for_identifier(TableIdentifier,Table) :-
|
||||||
|
bb_get(TableIdentifier,Table).
|
||||||
|
|
||||||
|
% Get the table identifier (!!) for call variant V, creating a new one if necessary.
|
||||||
|
%
|
||||||
|
% More costly than directly passing the table identifier for already existing tables.
|
||||||
|
%
|
||||||
|
% Since this creates a new table, this predicate is NOT meant for users who should get access to existing tables - f.e. benchmark shortest_path.P
|
||||||
|
%
|
||||||
|
table_for_variant(V,TableIdentifier) :-
|
||||||
|
( p_existing_table(V,TableIdentifier) ->
|
||||||
|
true
|
||||||
|
;
|
||||||
|
p_create_table(V,TableIdentifier)
|
||||||
|
).
|
||||||
|
|
||||||
|
% Get call variant for this table
|
||||||
|
get_call_variant(TableIdentifier,CallVariant) :-
|
||||||
|
p_get_table_for_identifier(TableIdentifier,Table),
|
||||||
|
get_call_variant_(Table,CallVariant).
|
||||||
|
|
||||||
|
get_call_variant_(table(CallVariant,_Status,_NbWorklistID,_NbAnswerTrieID),CallVariant).
|
||||||
|
get_call_variant_(complete_table(CallVariant,_NbWorklistID,_NbAnswerTrieID),CallVariant).
|
||||||
|
|
||||||
|
add_answer(TableIdentifier,A) :-
|
||||||
|
p_get_table_for_identifier(TableIdentifier,Table),
|
||||||
|
% arg(1,Table,CallVariant),
|
||||||
|
arg(3,Table,NbWorklistID),
|
||||||
|
arg(4,Table,NbAnswerTrieID),
|
||||||
|
bb_get(NbWorklistID,table_nb_worklist(Worklist)),
|
||||||
|
bb_get(NbAnswerTrieID,table_nb_answer_trie(AnswerTrie)),
|
||||||
|
copy_term(A,A2),
|
||||||
|
% This predicate succeeds if the answer was new, otherwise it fails.
|
||||||
|
trie_insert(AnswerTrie,A2,A2), % Use answer both as key and as value. Having it as value uses memory, but greatly simplifies getting all the answers.
|
||||||
|
% We got here, so trie_insert added a new answer.
|
||||||
|
% We must also insert this answer in the worklist
|
||||||
|
wkl_add_answer(Worklist,A2),
|
||||||
|
bb_put(NbWorklistID, table_nb_worklist(Worklist)),
|
||||||
|
bb_put(NbAnswerTrieID, table_nb_answer_trie(AnswerTrie)).
|
||||||
|
|
||||||
|
get_answer(TableIdentifier,A) :-
|
||||||
|
p_get_table_for_identifier(TableIdentifier,Table),
|
||||||
|
get_answer_trie_(Table,AnswerTrie),
|
||||||
|
% The trick is that we have stored the answers as values of the trie and that there is a method to get all the values.
|
||||||
|
trie_get_all_values(AnswerTrie,A).
|
||||||
|
|
||||||
|
% get_answer_trie_(TableOrCompleteTable,AnswerTrie).
|
||||||
|
% First argument is not a TableIdentifier.
|
||||||
|
get_answer_trie_(table(_CallVariant,_Status,_NbWorklistID, NbAnswerTrieID),AnswerTrie) :-
|
||||||
|
bb_get(NbAnswerTrieID, table_nb_answer_trie(AnswerTrie)).
|
||||||
|
get_answer_trie_(complete_table(_CallVariant,_NbWorklistID, NbAnswerTrieID),AnswerTrie) :-
|
||||||
|
bb_get(NbAnswerTrieID, table_nb_answer_trie(AnswerTrie)).
|
||||||
|
|
||||||
|
get_nb_identifiers(table(_CallVariant, _Status, NbWorklistID, NbAnswerTrieID), NbWorklistID, NbAnswerTrieID).
|
||||||
|
get_nb_identifiers(complete_table(_CallVariant, NbWorklistID, NbAnswerTrieID), NbWorklistID, NbAnswerTrieID).
|
||||||
|
|
||||||
|
% Get a list of answers for the given call variant.
|
||||||
|
% Used in compare_expected_for_variant/3 in testlib.pl
|
||||||
|
% IMPORTANT: table must be filled already, this is not done in this predicate! Therefore can be called during execution.
|
||||||
|
% V = variant
|
||||||
|
% LA = list of answers.
|
||||||
|
%
|
||||||
|
% More costly operation than directly giving the table identifier.
|
||||||
|
answers_for_variant(V,LA) :-
|
||||||
|
table_for_variant(V,TableIdentifier),
|
||||||
|
p_get_table_for_identifier(TableIdentifier,Table),
|
||||||
|
get_answer_trie_(Table,AnswerTrie),
|
||||||
|
findall(Value,trie_get_all_values(AnswerTrie,Value),LA).
|
||||||
|
|
||||||
|
% Set status of table TableIdentifier to active
|
||||||
|
set_active_status(TableIdentifier) :-
|
||||||
|
tbd_status_transition(TableIdentifier,active,fresh,'set_active_status').
|
||||||
|
|
||||||
|
cleanup_after_complete(TableIdentifier) :-
|
||||||
|
p_get_table_for_identifier(TableIdentifier,Table),
|
||||||
|
cleanup_after_complete_(Table,TableIdentifier).
|
||||||
|
|
||||||
|
% Clause for a (noncomplete) table.
|
||||||
|
cleanup_after_complete_(
|
||||||
|
table(CallVariant,_ActualOldStatus, NbWorklistID, NbAnswerTrieID),
|
||||||
|
TableIdentifier
|
||||||
|
) :-
|
||||||
|
bb_put(TableIdentifier,complete_table(CallVariant, NbWorklistID, NbAnswerTrieID)).
|
||||||
|
% If necessary for debugging add second clause for complete_table.
|
||||||
|
|
||||||
|
% Set status of table TableIdentifier to complete.
|
||||||
|
set_complete_status(TableIdentifier) :-
|
||||||
|
% The transition must be active to complete, otherwise we have an invalid status transition.
|
||||||
|
% Preexisting tables should have been cleaned-up, thus not have the form table/5 anymore, thus complete -> complete is not possible there.
|
||||||
|
p_get_table_for_identifier(TableIdentifier,Table),
|
||||||
|
set_complete_status_(Table,TableIdentifier).
|
||||||
|
|
||||||
|
% set_complete_status_(Table,TableIdentifier).
|
||||||
|
set_complete_status_(table(_CallVariant,_OldStatus,_NbWorklistID, _NbAnswerTrieID),TableIdentifier) :-
|
||||||
|
tbd_status_transition(TableIdentifier,complete,active,'set_complete_status').
|
||||||
|
|
||||||
|
tbd_status_transition_no_check(TableIdentifier,NewStatus) :-
|
||||||
|
p_get_table_for_identifier(TableIdentifier,Table),
|
||||||
|
tbd_status_transition_no_check_(TableIdentifier,Table,NewStatus).
|
||||||
|
|
||||||
|
tbd_status_transition_no_check_(TableIdentifier,Table,NewStatus) :-
|
||||||
|
Table = table(_,StatusFlag,_,_),
|
||||||
|
put_atts(StatusFlag, table_status(NewStatus)),
|
||||||
|
bb_put(TableIdentifier, Table).
|
||||||
|
|
||||||
|
% Set Table's status to NewStatus if current status is RequiredOldStatus, otherwise throw an exception mentioning CallerAsString: attempt to set NewStatus for table TableIdentifier, but current status was ActualOldStatus instead of RequiredOldStatus
|
||||||
|
tbd_status_transition(TableIdentifier,NewStatus,_RequiredOldStatus,_CallerAsString) :-
|
||||||
|
p_get_table_for_identifier(TableIdentifier,Table),
|
||||||
|
tbd_status_transition_no_check_(TableIdentifier,Table,NewStatus).
|
||||||
|
|
||||||
|
store_dependency(TableIdentifier,Suspension) :-
|
||||||
|
p_get_table_for_identifier(TableIdentifier, Table),
|
||||||
|
get_nb_identifiers(Table, NbWorklistID, _NbAnswerTrieID),
|
||||||
|
copy_term(Suspension, SuspensionCopy),
|
||||||
|
bb_get(NbWorklistID, table_nb_worklist(Worklist)),
|
||||||
|
wkl_add_suspension(Worklist, SuspensionCopy),
|
||||||
|
bb_put(NbWorklistID, table_nb_worklist(Worklist)).
|
||||||
123
src/prolog/lib/tabling/table_link_manager.pl
Normal file
123
src/prolog/lib/tabling/table_link_manager.pl
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/* Part of SWI-Prolog
|
||||||
|
|
||||||
|
Author: Benoit Desouter <Benoit.Desouter@UGent.be>
|
||||||
|
Jan Wielemaker (SWI-Prolog port)
|
||||||
|
Copyright (c) 2016, Benoit Desouter
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Ported to Scryer Prolog by Mark Thom (2019/2020).
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:- module(table_link_manager,
|
||||||
|
[ get_existing_tables/1, % -Tables
|
||||||
|
p_existing_table/2, % +Variant, -TableID
|
||||||
|
p_link_variant_identifier/2, % +Variant, -TableID
|
||||||
|
num_tables/1, % -Count
|
||||||
|
get_trie_table_link/1, % -Trie
|
||||||
|
put_new_trie_table_link/0
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module(library(atts)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(non_iso)).
|
||||||
|
:- use_module(library(terms)).
|
||||||
|
|
||||||
|
:- use_module(trie).
|
||||||
|
|
||||||
|
:- attribute trie_table_link/1.
|
||||||
|
|
||||||
|
% This file defines a call pattern trie.
|
||||||
|
%
|
||||||
|
% This data structure keeps the relation between a variant and the
|
||||||
|
% corresponding table identifier using a trie. The trick is to make a
|
||||||
|
% canonical representation of a given variant using the numbervars/3
|
||||||
|
% predicate. The trie uses this canonical representation as key, and
|
||||||
|
% the table identifier as value.
|
||||||
|
|
||||||
|
% Uses the (private) global variable trie_table_link
|
||||||
|
|
||||||
|
% This predicate should be called exactly once.
|
||||||
|
% It throws an exception if it is called more than once.
|
||||||
|
|
||||||
|
%% table_link_manager_initialize
|
||||||
|
%
|
||||||
|
% Initializes the global variables `trie_table_link`. Normally
|
||||||
|
% called from table_datastructure_initialize/0.
|
||||||
|
|
||||||
|
put_new_trie_table_link :-
|
||||||
|
( bb_get(trie_table_link_initialized, _) ->
|
||||||
|
true
|
||||||
|
; trie_new(Trie),
|
||||||
|
put_atts(TrieFlag, trie_table_link(Trie)),
|
||||||
|
bb_put(trie_table_link, TrieFlag),
|
||||||
|
bb_put(trie_table_link_initialized, [])
|
||||||
|
).
|
||||||
|
|
||||||
|
get_trie_table_link(Trie) :-
|
||||||
|
bb_get(trie_table_link, TrieFlag),
|
||||||
|
get_atts(TrieFlag, trie_table_link(Trie)).
|
||||||
|
|
||||||
|
% PRIVATE
|
||||||
|
% mode: + -
|
||||||
|
% Variant is not modified
|
||||||
|
variant_canonical_representation(Variant, CanonicalRepresentation) :-
|
||||||
|
copy_term(Variant, CanonicalRepresentation),
|
||||||
|
numbervars(CanonicalRepresentation, 0 ,_).
|
||||||
|
|
||||||
|
% Succeeds if there is a table TableIdentifier in existance for the
|
||||||
|
% given call variant Variant.
|
||||||
|
p_existing_table(Variant, TableIdentifier) :-
|
||||||
|
get_trie_table_link(Trie),
|
||||||
|
variant_canonical_representation(Variant, CanonicalRepresentation),
|
||||||
|
trie_lookup(Trie, CanonicalRepresentation, TableIdentifier).
|
||||||
|
|
||||||
|
% Important remark: we cannot use an out-of-the-box association list,
|
||||||
|
% because we need a lookup based on variant checking, which is not
|
||||||
|
% available for such lists. Converting the association list to a
|
||||||
|
% regular list => why would you use an association list in the first
|
||||||
|
% place...
|
||||||
|
p_link_variant_identifier(Variant, TableIdentifier) :-
|
||||||
|
get_trie_table_link(Trie),
|
||||||
|
variant_canonical_representation(Variant, CanonicalRepresentation),
|
||||||
|
trie_insert_succeed(Trie, CanonicalRepresentation, TableIdentifier),
|
||||||
|
put_atts(TrieFlag, trie_table_link(Trie)),
|
||||||
|
bb_put(trie_table_link, TrieFlag).
|
||||||
|
|
||||||
|
% Returns a list of existing table identifiers.
|
||||||
|
% Rather costly.
|
||||||
|
get_existing_tables(Ts) :-
|
||||||
|
get_trie_table_link(Trie),
|
||||||
|
findall(T, trie_get_all_values(Trie, T), Ts).
|
||||||
|
|
||||||
|
% A very unefficient way of implementing this predicate. But it is
|
||||||
|
% only used for unit testing, so it doesn't really matter. Also, it
|
||||||
|
% doesn't require any additional bookkeeping during the actual
|
||||||
|
% execution.
|
||||||
|
num_tables(N) :-
|
||||||
|
get_existing_tables(Ts),
|
||||||
|
length(Ts, N).
|
||||||
225
src/prolog/lib/tabling/trie.pl
Normal file
225
src/prolog/lib/tabling/trie.pl
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/* Part of SWI-Prolog
|
||||||
|
|
||||||
|
Author: Benoit Desouter <Benoit.Desouter@UGent.be>
|
||||||
|
Jan Wielemaker (SWI-Prolog port)
|
||||||
|
Copyright (c) 2016, Benoit Desouter
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Ported to Scryer Prolog by Mark Thom (2019/2020).
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:- module(trie,
|
||||||
|
[ trie_new/1, % -Trie
|
||||||
|
trie_insert/3, % !Trie, +Key, +Value
|
||||||
|
trie_insert_succeed/3,
|
||||||
|
trie_lookup/3, % +Trie, +Key, -Value
|
||||||
|
trie_get_all_values/2 % +Trie, -Value
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module(library(assoc)).
|
||||||
|
:- use_module(library(atts)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
|
||||||
|
:- attribute maybe_just/1, children/1.
|
||||||
|
|
||||||
|
% Implementation of a prefix tree, a.k.a. trie %
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
% Desired complexity for lookup and insert: linear in the length of the key.
|
||||||
|
|
||||||
|
% ATTENTION: do not use the term functor_data/2; this is used internally here.
|
||||||
|
|
||||||
|
% Inspiration from http://en.wikipedia.org/wiki/Trie
|
||||||
|
|
||||||
|
% Structure of tries:
|
||||||
|
% trie_inner_node(MaybeValue,Children).
|
||||||
|
% where Children is an association list of nonvars to tries.
|
||||||
|
% and where MaybeValue is maybe_none/0 or maybe_just(Value).
|
||||||
|
|
||||||
|
% PRIVATE
|
||||||
|
% For a term of the form p(a,q(b)), "returns" functor_data(p,2) and [a,q(b)].
|
||||||
|
% p_trie_arity_univ(+Term,-FunctorData,-ArgumentsList).
|
||||||
|
p_trie_arity_univ(Term,functor_data(Name,Arity),Arguments) :-
|
||||||
|
( var(Term) ->
|
||||||
|
Name = var,
|
||||||
|
Arity = 0,
|
||||||
|
Arguments = []
|
||||||
|
; Term =.. [Name|Arguments],
|
||||||
|
functor(Term,_,Arity)
|
||||||
|
).
|
||||||
|
|
||||||
|
% Returns a new empty trie.
|
||||||
|
trie_new(Trie) :-
|
||||||
|
empty_assoc(Assoc),
|
||||||
|
put_atts(A, children(Assoc)),
|
||||||
|
Trie = trie_inner_node(_,A).
|
||||||
|
|
||||||
|
% Succeeds if given trie does not contain any key-value pair.
|
||||||
|
% trie_is_empty(+Trie)
|
||||||
|
trie_is_empty(trie_inner_node(X,A)) :-
|
||||||
|
get_atts(X, -maybe_just(_)),
|
||||||
|
get_atts(A, children(Assoc)),
|
||||||
|
empty_assoc(Assoc).
|
||||||
|
|
||||||
|
% For internal use.
|
||||||
|
% For now, Children is an association list that can be manipulated using the assoc_ predicates.
|
||||||
|
trie_get_children(trie_inner_node(_,ChildNode),Children) :-
|
||||||
|
get_atts(ChildNode, children(Children)).
|
||||||
|
|
||||||
|
% For internal use.
|
||||||
|
trie_get_maybe_value(trie_inner_node(MaybeNode,_),MaybeValue) :-
|
||||||
|
get_atts(MaybeNode, maybe_just(MaybeValue)).
|
||||||
|
|
||||||
|
% Destructive update of the association list Children.
|
||||||
|
% For internal use.
|
||||||
|
trie_set_children(trie_inner_node(_,ChildNode),Children) :-
|
||||||
|
put_atts(ChildNode, children(Children)).
|
||||||
|
|
||||||
|
trie_set_maybe_value(trie_inner_node(MaybeNode, _),MaybeValue) :-
|
||||||
|
put_atts(MaybeNode, MaybeValue).
|
||||||
|
|
||||||
|
trie_insert_succeed(Trie,Key,Value) :-
|
||||||
|
( trie_insert(Trie,Key,Value) ->
|
||||||
|
true
|
||||||
|
;
|
||||||
|
true
|
||||||
|
).
|
||||||
|
|
||||||
|
% Succeeds if the term was not present, fails if the term was present.
|
||||||
|
% The term will be present now, whatever the outcome.
|
||||||
|
% We don't use an extra argument to indicate earlier presence, as this increases the trail size.
|
||||||
|
trie_insert(Trie,Key,Value) :-
|
||||||
|
p_trie_arity_univ(Key,FunctorData,KeyList),
|
||||||
|
trie_insert_1(KeyList,FunctorData,Trie,Value).
|
||||||
|
|
||||||
|
trie_insert_1([],FunctorData,Trie,Value) :-
|
||||||
|
trie_get_children(Trie,Assoc),
|
||||||
|
% You need Assoc twice: once to traverse through it, once keeping it as a whole for insertion using put_assoc/4.
|
||||||
|
trie_insert_a(Assoc,Assoc,FunctorData,Trie,Value).
|
||||||
|
|
||||||
|
% Inline the failure and success continuation to avoid a growing trail stack.
|
||||||
|
trie_insert_1([First|Rest],FunctorData,Trie,Value) :-
|
||||||
|
trie_get_children(Trie,Assoc),
|
||||||
|
% You need Assoc twice: once to traverse through it, once keeping it as a whole for insertion using put_assoc/4.
|
||||||
|
trie_insert_1_1(Assoc,Assoc,FunctorData,Trie,First,Rest,Value).
|
||||||
|
|
||||||
|
% Else part, base case: empty assoc list.
|
||||||
|
trie_insert_a(t,Assoc,FunctorData,Trie,Value) :-
|
||||||
|
trie_new(Subtrie),
|
||||||
|
trie_set_maybe_value(Subtrie,maybe_just(Value)),
|
||||||
|
put_assoc(FunctorData,Assoc,Subtrie,NewAssoc),
|
||||||
|
trie_set_children(Trie,NewAssoc).
|
||||||
|
|
||||||
|
% Then part, nonempty assoc tree.
|
||||||
|
trie_insert_a(t(K,V,_,L,R),Assoc,FunctorData,Trie,Value) :-
|
||||||
|
compare(Rel,FunctorData,K),
|
||||||
|
trie_insert_b(Rel,V,L,R,Assoc,FunctorData,Trie,Value).
|
||||||
|
|
||||||
|
% Recursively look in the left part of the assoc tree.
|
||||||
|
trie_insert_b(<,_V,L,_R,Assoc,FunctorData,Trie,Value) :-
|
||||||
|
trie_insert_a(L,Assoc,FunctorData,Trie,Value).
|
||||||
|
|
||||||
|
% Recursively look in the right part of the assoc tree.
|
||||||
|
trie_insert_b(>,_V,_L,R,Assoc,FunctorData,Trie,Value) :-
|
||||||
|
trie_insert_a(R,Assoc,FunctorData,Trie,Value).
|
||||||
|
|
||||||
|
trie_insert_b(=,V,_L,_R,_Assoc,_FunctorData,_Trie,Value) :-
|
||||||
|
trie_get_maybe_value(V,MaybeValue), % V is the Subtrie
|
||||||
|
( MaybeValue == maybe_none ->
|
||||||
|
trie_set_maybe_value(V,maybe_just(Value))
|
||||||
|
% Use true to indicate that the answer was new.
|
||||||
|
;
|
||||||
|
MaybeValue = maybe_just(JustValue),
|
||||||
|
( JustValue == Value ->
|
||||||
|
% Fail to indicate earlier presence
|
||||||
|
fail
|
||||||
|
;
|
||||||
|
throw('trie: attempt to update the value for a key')
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
|
% Else part, base case: empty assoc list
|
||||||
|
trie_insert_1_1(t,Assoc,FunctorData,Trie,First,Rest,Value) :-
|
||||||
|
% Assoc = t, % t is the empty assoc tree
|
||||||
|
trie_new(Subtrie),
|
||||||
|
put_assoc(FunctorData,Assoc,Subtrie,NewAssoc),
|
||||||
|
trie_set_children(Trie,NewAssoc),
|
||||||
|
trie_insert_2(First,Rest,Subtrie,Value).
|
||||||
|
|
||||||
|
% Then part, lookup in assoc list.
|
||||||
|
trie_insert_1_1(t(K,V,_,L,R),Assoc,FunctorData,Trie,First,Rest,Value) :-
|
||||||
|
compare(Rel,FunctorData,K),
|
||||||
|
trie_insert_1_1_1(Rel,V,L,R,Assoc,FunctorData,Trie,First,Rest,Value).
|
||||||
|
|
||||||
|
trie_insert_1_1_1(=,V,_L,_R,_Assoc,_FunctorData,_Trie,First,Rest,Value) :-
|
||||||
|
trie_insert_2(First,Rest,V,Value). % V is the Subtrie
|
||||||
|
|
||||||
|
trie_insert_1_1_1(<,_V,L,_R,Assoc,FunctorData,Trie,First,Rest,Value) :-
|
||||||
|
% Look in the left part of the assoc tree.
|
||||||
|
trie_insert_1_1(L,Assoc,FunctorData,Trie,First,Rest,Value).
|
||||||
|
|
||||||
|
trie_insert_1_1_1(>,_V,_L,R,Assoc,FunctorData,Trie,First,Rest,Value) :-
|
||||||
|
% Look in the right part of the assoc tree.
|
||||||
|
trie_insert_1_1(R,Assoc,FunctorData,Trie,First,Rest,Value).
|
||||||
|
|
||||||
|
trie_insert_2(RegularTerm,Rest,Trie,Value) :-
|
||||||
|
p_trie_arity_univ(RegularTerm,FunctorData,KList),
|
||||||
|
append(KList,Rest,KList2),
|
||||||
|
trie_insert_1(KList2,FunctorData,Trie,Value).
|
||||||
|
|
||||||
|
trie_lookup(Trie,Key,Value) :-
|
||||||
|
p_trie_arity_univ(Key,FunctorData,KeyList),
|
||||||
|
trie_lookup_1(FunctorData,KeyList,Trie,Value).
|
||||||
|
|
||||||
|
trie_lookup_1(FunctorData,Rest,Trie,Value) :-
|
||||||
|
% Select right subtree, fail if it isn't there, and do recursive call.
|
||||||
|
trie_get_children(Trie,Assoc),
|
||||||
|
get_assoc(FunctorData,Assoc,Subtrie), % Fails if not present
|
||||||
|
trie_lookup_2(Rest,Subtrie,Value).
|
||||||
|
|
||||||
|
trie_lookup_2([],Trie,Value) :-
|
||||||
|
% If the value at this trie is maybe_just(X), then X is our Value.
|
||||||
|
% Otherwise, there is no value for this key, so we fail...
|
||||||
|
trie_get_maybe_value(Trie,Value).
|
||||||
|
% Regular term at the head, like p or p(a). Not functor_data/2.
|
||||||
|
trie_lookup_2([RegularTerm|Rest],Trie,Value) :-
|
||||||
|
% split RegularTerm
|
||||||
|
p_trie_arity_univ(RegularTerm,FunctorData,KList),
|
||||||
|
% Make a recursive call on KList ++ Rest.
|
||||||
|
% Since we cannot implement p_trie_arity_univ so that "its result", KList, has a free variable at the end, without resorting to techniques that require linear time, we need a call to append/3. However, since KList will in general be rather short, I don't expect this to be a large problem in practice.
|
||||||
|
append(KList,Rest,KList2),
|
||||||
|
trie_lookup_1(FunctorData,KList2,Trie,Value).
|
||||||
|
|
||||||
|
|
||||||
|
% Returns all values in the trie by backtracking - we don't provide any information about the associated key.
|
||||||
|
trie_get_all_values(Trie,Value) :-
|
||||||
|
trie_get_maybe_value(Trie,Value).
|
||||||
|
trie_get_all_values(Trie,Value) :-
|
||||||
|
trie_get_children(Trie,Children),
|
||||||
|
gen_assoc(_Key, Children, ChildTrie),
|
||||||
|
trie_get_all_values(ChildTrie,Value).
|
||||||
118
src/prolog/lib/tabling/wrapper.pl
Normal file
118
src/prolog/lib/tabling/wrapper.pl
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/* Part of SWI-Prolog
|
||||||
|
|
||||||
|
Author: Jan Wielemaker
|
||||||
|
Copyright (c) 2016, VU University Amsterdam
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Ported to Scryer Prolog by Mark Thom (2019/2020).
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:- module(table_wrapper,
|
||||||
|
[ %(table)/1, % +Predicates
|
||||||
|
op(1150, fx, table)
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(error)).
|
||||||
|
|
||||||
|
%%:- multifile
|
||||||
|
%% system:term_expansion/2,
|
||||||
|
%% tabled/2.
|
||||||
|
%%:- dynamic
|
||||||
|
%% system:term_expansion/2.
|
||||||
|
|
||||||
|
%% table(+PredicateIndicators)
|
||||||
|
%
|
||||||
|
% Prepare the given PredicateIndicators for tabling. Can only
|
||||||
|
% be used as a directive.
|
||||||
|
|
||||||
|
%% table(PIList) :-
|
||||||
|
%% throw(error(context_error(nodirective, table(PIList)), _)).
|
||||||
|
|
||||||
|
instantiation_error(Var) :-
|
||||||
|
throw(error(instantiation_error(Var), _)).
|
||||||
|
|
||||||
|
wrappers(Var) -->
|
||||||
|
{ var(Var), !,
|
||||||
|
instantiation_error(Var)
|
||||||
|
}.
|
||||||
|
wrappers((A,B)) --> !,
|
||||||
|
wrappers(A),
|
||||||
|
wrappers(B).
|
||||||
|
wrappers(Name//Arity) -->
|
||||||
|
{ atom(Name), integer(Arity), Arity >= 0, !,
|
||||||
|
Arity1 is Arity+2
|
||||||
|
},
|
||||||
|
wrappers(Name/Arity1).
|
||||||
|
wrappers(Name/Arity) -->
|
||||||
|
{ atom(Name), integer(Arity), Arity >= 0, !,
|
||||||
|
functor(Head, Name, Arity),
|
||||||
|
atom_concat(Name, ' tabled', WrapName),
|
||||||
|
Head =.. [Name|Args],
|
||||||
|
WrappedHead =.. [WrapName|Args],
|
||||||
|
'$module_of'(Module, Name) %prolog_load_context(module, Module)
|
||||||
|
},
|
||||||
|
[ ( Head :-
|
||||||
|
start_tabling(Module:Head, WrappedHead)
|
||||||
|
),
|
||||||
|
(:- multifile(table_wrapper:tabled/2)),
|
||||||
|
table_wrapper:tabled(Head, Module)
|
||||||
|
].
|
||||||
|
|
||||||
|
rename(M:Term0, M:Term, _) :-
|
||||||
|
atom(M), !,
|
||||||
|
rename(Term0, Term, M).
|
||||||
|
rename((Head :- Body), (NewHead :- Body), Module) :- !,
|
||||||
|
rename(Head, NewHead, Module).
|
||||||
|
rename((Head --> Body), (NewHead --> Body), Module) :- !,
|
||||||
|
functor(Head, Name, Arity),
|
||||||
|
PlainArity is Arity+1,
|
||||||
|
functor(PlainHead, Name, PlainArity),
|
||||||
|
table_wrapper:tabled(PlainHead, Module),
|
||||||
|
rename_term(Head, NewHead).
|
||||||
|
rename(Head, NewHead, Module) :-
|
||||||
|
table_wrapper:tabled(Head, Module), !,
|
||||||
|
rename_term(Head, NewHead).
|
||||||
|
|
||||||
|
rename_term(Compound0, Compound) :-
|
||||||
|
compound(Compound0), !,
|
||||||
|
Compound0 =.. [Name|Args],
|
||||||
|
atom_concat(Name, ' tabled', WrapName),
|
||||||
|
Compound =.. [WrapName|Args].
|
||||||
|
rename_term(Name, WrapName) :-
|
||||||
|
atom_concat(Name, ' tabled', WrapName).
|
||||||
|
|
||||||
|
|
||||||
|
user:term_expansion(Term0, Clauses) :-
|
||||||
|
nonvar(Term0),
|
||||||
|
Term0 = (:- table Preds),
|
||||||
|
phrase(wrappers(Preds), Clauses).
|
||||||
|
user:term_expansion(Clause, NewClause) :-
|
||||||
|
nonvar(Clause),
|
||||||
|
'$module_of'(Module, Clause),
|
||||||
|
rename(Clause, NewClause, Module).
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
use crate::prolog::machine::machine_indices::*;
|
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Frame {
|
|
||||||
pub global_index: usize,
|
|
||||||
pub e: usize,
|
|
||||||
pub cp: LocalCodePtr,
|
|
||||||
pub interrupt_cp: LocalCodePtr,
|
|
||||||
perms: Vec<Addr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(global_index: usize, fr: usize, e: usize, cp: LocalCodePtr, n: usize) -> Self {
|
|
||||||
Frame {
|
|
||||||
global_index,
|
|
||||||
e: e,
|
|
||||||
cp: cp,
|
|
||||||
interrupt_cp: LocalCodePtr::default(),
|
|
||||||
perms: (1..n + 1).map(|i| Addr::StackCell(fr, i)).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.perms.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AndStack(Vec<Frame>);
|
|
||||||
|
|
||||||
impl AndStack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
AndStack(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn take(&mut self) -> Self {
|
|
||||||
AndStack(mem::replace(&mut self.0, vec![]))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, global_index: usize, e: usize, cp: LocalCodePtr, n: usize) {
|
|
||||||
let len = self.0.len();
|
|
||||||
self.0.push(Frame::new(global_index, len, e, cp, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.0.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resize(&mut self, fr: usize, n: usize) {
|
|
||||||
let len = self[fr].perms.len();
|
|
||||||
|
|
||||||
if len < n {
|
|
||||||
self[fr].perms.reserve(n - len);
|
|
||||||
|
|
||||||
for i in len..n {
|
|
||||||
self[fr].perms.push(Addr::StackCell(fr, i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn truncate(&mut self, len: usize) {
|
|
||||||
self.0.truncate(len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for AndStack {
|
|
||||||
type Output = Frame;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.0.index(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for AndStack {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.0.index_mut(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Frame {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.perms.index(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Frame {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.perms.index_mut(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
driver(Vars, Values) :-
|
driver(Vars, Values) :-
|
||||||
iterate(Vars, Values, ListOfListsOfGoalLists),
|
iterate(Vars, Values, ListOfListsOfGoalLists),
|
||||||
'$redo_attr_var_bindings', % the bindings list is emptied here.
|
'$clear_attr_var_bindings',
|
||||||
!,
|
!,
|
||||||
call_goals(ListOfListsOfGoalLists),
|
call_goals(ListOfListsOfGoalLists),
|
||||||
'$return_from_verify_attr'.
|
'$return_from_verify_attr'.
|
||||||
@@ -8,6 +8,7 @@ driver(Vars, Values) :-
|
|||||||
iterate([Var|VarBindings], [Value|ValueBindings], [ListOfGoalLists | ListsCubed]) :-
|
iterate([Var|VarBindings], [Value|ValueBindings], [ListOfGoalLists | ListsCubed]) :-
|
||||||
'$get_attr_list'(Var, Ls),
|
'$get_attr_list'(Var, Ls),
|
||||||
call_verify_attributes(Ls, Var, Value, ListOfGoalLists),
|
call_verify_attributes(Ls, Var, Value, ListOfGoalLists),
|
||||||
|
'$redo_attr_var_binding'(Var, Value),
|
||||||
iterate(VarBindings, ValueBindings, ListsCubed).
|
iterate(VarBindings, ValueBindings, ListsCubed).
|
||||||
iterate([], [], []).
|
iterate([], [], []).
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ call_verify_attributes(Attrs, _, _, []) :-
|
|||||||
call_verify_attributes([], _, _, []).
|
call_verify_attributes([], _, _, []).
|
||||||
call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
|
call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
|
||||||
gather_modules([Attr|Attrs], Modules0),
|
gather_modules([Attr|Attrs], Modules0),
|
||||||
sort(Modules0, Modules),
|
sort(Modules0, Modules),
|
||||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||||
|
|
||||||
call_goals([ListOfGoalLists | ListsCubed]) :-
|
call_goals([ListOfGoalLists | ListsCubed]) :-
|
||||||
|
|||||||
@@ -32,9 +32,15 @@ impl AttrVarInitializer {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn reset(&mut self) {
|
pub(super) fn reset(&mut self) {
|
||||||
|
self.attribute_goals.clear();
|
||||||
self.attr_var_queue.clear();
|
self.attr_var_queue.clear();
|
||||||
self.bindings.clear();
|
self.bindings.clear();
|
||||||
self.attribute_goals.clear();
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn backtrack(&mut self, queue_b: usize, bindings_b: usize) {
|
||||||
|
self.attr_var_queue.truncate(queue_b);
|
||||||
|
self.bindings.truncate(bindings_b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,13 +48,13 @@ 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() {
|
if self.attr_var_init.bindings.is_empty() {
|
||||||
self.attr_var_init.instigating_p = self.p.local();
|
self.attr_var_init.instigating_p = self.p.local();
|
||||||
|
|
||||||
if self.last_call {
|
if self.last_call {
|
||||||
self.attr_var_init.cp = self.cp;
|
self.attr_var_init.cp = self.cp;
|
||||||
} else {
|
} else {
|
||||||
self.attr_var_init.cp = self.p.local() + 1;
|
self.attr_var_init.cp = self.p.local() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc);
|
self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +67,7 @@ impl MachineState {
|
|||||||
.bindings
|
.bindings
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(ref h, _)| Addr::AttrVar(*h));
|
.map(|(ref h, _)| Addr::AttrVar(*h));
|
||||||
|
|
||||||
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||||
|
|
||||||
let iter = self
|
let iter = self
|
||||||
@@ -68,6 +75,7 @@ impl MachineState {
|
|||||||
.bindings
|
.bindings
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, ref addr)| addr.clone());
|
.map(|(_, ref addr)| addr.clone());
|
||||||
|
|
||||||
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||||
|
|
||||||
(var_list_addr, value_list_addr)
|
(var_list_addr, value_list_addr)
|
||||||
@@ -103,14 +111,16 @@ impl MachineState {
|
|||||||
self.allocate(self.num_of_args + 2);
|
self.allocate(self.num_of_args + 2);
|
||||||
|
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
self.and_stack[e].interrupt_cp = self.attr_var_init.cp;
|
self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp;
|
||||||
|
|
||||||
for i in 1 .. self.num_of_args + 1 {
|
for i in 1 .. self.num_of_args + 1 {
|
||||||
self.and_stack[e][i] = self[RegType::Temp(i)].clone();
|
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.and_stack[e][self.num_of_args + 1] = Addr::Con(Constant::Usize(self.b0));
|
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
|
||||||
self.and_stack[e][self.num_of_args + 2] = Addr::Con(Constant::Usize(self.num_of_args));
|
Addr::Con(Constant::CutPoint(self.b0));
|
||||||
|
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
|
||||||
|
Addr::Con(Constant::Usize(self.num_of_args));
|
||||||
|
|
||||||
self.verify_attributes();
|
self.verify_attributes();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
use prolog_parser::ast::MachineFlags;
|
|
||||||
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::prolog::clause_types::*;
|
||||||
use crate::prolog::codegen::*;
|
use crate::prolog::codegen::*;
|
||||||
use crate::prolog::debray_allocator::*;
|
use crate::prolog::debray_allocator::*;
|
||||||
@@ -9,7 +7,10 @@ use crate::prolog::machine::compile::*;
|
|||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::prolog::machine::machine_errors::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::prolog::machine::machine_indices::*;
|
||||||
|
|
||||||
|
use indexmap::IndexSet;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
pub struct CodeRepo {
|
pub struct CodeRepo {
|
||||||
pub(super) cached_query: Code,
|
pub(super) cached_query: Code,
|
||||||
@@ -59,11 +60,12 @@ impl CodeRepo {
|
|||||||
.unwrap_or((Predicate::new(), VecDeque::from(vec![])))
|
.unwrap_or((Predicate::new(), VecDeque::from(vec![])))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_in_situ_result(
|
pub(crate) fn add_in_situ_result(
|
||||||
&mut self,
|
&mut self,
|
||||||
result: &CompiledResult,
|
result: &CompiledResult,
|
||||||
in_situ_code_dir: &mut InSituCodeDir,
|
in_situ_code_dir: &mut InSituCodeDir,
|
||||||
flags: MachineFlags,
|
in_situ_module_dir: &mut ModuleStubDir,
|
||||||
|
non_counted_bt_preds: &IndexSet<PredicateKey>,
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
let (ref decl, ref queue) = result;
|
let (ref decl, ref queue) = result;
|
||||||
let (name, arity) = decl
|
let (name, arity) = decl
|
||||||
@@ -75,17 +77,26 @@ impl CodeRepo {
|
|||||||
})
|
})
|
||||||
.ok_or(SessionError::NamelessEntry)?;
|
.ok_or(SessionError::NamelessEntry)?;
|
||||||
|
|
||||||
|
let non_counted_bt = non_counted_bt_preds.contains(&(name.clone(), arity));
|
||||||
|
let module_name = name.owning_module();
|
||||||
|
|
||||||
let p = self.in_situ_code.len();
|
let p = self.in_situ_code.len();
|
||||||
in_situ_code_dir.insert((name, arity), p);
|
|
||||||
|
|
||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new(true, flags);
|
match in_situ_module_dir.get_mut(&module_name) {
|
||||||
// clone the decl to avoid the need to wipe its register cells later.
|
Some(ref mut module_stub) if name.has_table(&module_stub.atom_tbl) => {
|
||||||
let mut decl_code = cg.compile_predicate(&decl.0.clone())?;
|
module_stub.in_situ_code_dir.insert((name, arity), p);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
in_situ_code_dir.insert((name, arity), p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
compile_appendix(&mut decl_code, queue, true, flags)?;
|
let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt);
|
||||||
|
let mut decl_code = cg.compile_predicate(&decl.0)?;
|
||||||
|
|
||||||
self.in_situ_code.extend(decl_code.into_iter());
|
compile_appendix(&mut decl_code, queue, non_counted_bt)?;
|
||||||
Ok(())
|
|
||||||
|
Ok(self.in_situ_code.extend(decl_code.into_iter()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -93,6 +104,11 @@ impl CodeRepo {
|
|||||||
self.cached_query.len()
|
self.cached_query.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn take_in_situ_code(&mut self) -> Code {
|
||||||
|
mem::replace(&mut self.in_situ_code, Code::new())
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn lookup_instr<'a>(
|
pub(super) fn lookup_instr<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
last_call: bool,
|
last_call: bool,
|
||||||
@@ -134,7 +150,7 @@ impl CodeRepo {
|
|||||||
);
|
);
|
||||||
Some(RefOrOwned::Owned(call_clause))
|
Some(RefOrOwned::Owned(call_clause))
|
||||||
}
|
}
|
||||||
&CodePtr::CallN(arity, _) => {
|
&CodePtr::CallN(arity, _, last_call) => {
|
||||||
let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call);
|
let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call);
|
||||||
Some(RefOrOwned::Owned(call_clause))
|
Some(RefOrOwned::Owned(call_clause))
|
||||||
}
|
}
|
||||||
|
|||||||
81
src/prolog/machine/code_walker.rs
Normal file
81
src/prolog/machine/code_walker.rs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
use crate::prolog::instructions::*;
|
||||||
|
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
fn scan_for_trust_me(code: &Code, jmp_offsets: &mut VecDeque<usize>, after_idx: &mut usize) {
|
||||||
|
for (idx, instr) in code[*after_idx..].iter().enumerate() {
|
||||||
|
match instr {
|
||||||
|
&Line::Choice(ChoiceInstruction::TrustMe)
|
||||||
|
| &Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => {
|
||||||
|
*after_idx += idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
&Line::Control(ControlInstruction::JmpBy(_, offset, ..)) => {
|
||||||
|
jmp_offsets.push_back(*after_idx + idx + offset)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut usize) {
|
||||||
|
loop {
|
||||||
|
match &code[*last_idx] {
|
||||||
|
&Line::Choice(ChoiceInstruction::TryMeElse(..))
|
||||||
|
| &Line::IndexedChoice(IndexedChoiceInstruction::Try(..)) => {
|
||||||
|
*last_idx += 1;
|
||||||
|
scan_for_trust_me(code, queue, last_idx);
|
||||||
|
}
|
||||||
|
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
|
||||||
|
queue.push_back(*last_idx + offset);
|
||||||
|
*last_idx += 1;
|
||||||
|
}
|
||||||
|
&Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
|
||||||
|
queue.push_back(*last_idx + offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
&Line::Control(ControlInstruction::Proceed)
|
||||||
|
| &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) =>
|
||||||
|
break,
|
||||||
|
_ =>
|
||||||
|
*last_idx += 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function walks the code of a single predicate, supposed to
|
||||||
|
* begin in code at the offset p. Each instruction is passed to the
|
||||||
|
* walker function.
|
||||||
|
*/
|
||||||
|
pub fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line))
|
||||||
|
{
|
||||||
|
let mut queue = VecDeque::from(vec![p]);
|
||||||
|
|
||||||
|
while let Some(first_idx) = queue.pop_front() {
|
||||||
|
let mut last_idx = first_idx;
|
||||||
|
|
||||||
|
capture_next_range(code, &mut queue, &mut last_idx);
|
||||||
|
|
||||||
|
for instr in &code[first_idx .. last_idx + 1] {
|
||||||
|
walker(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A function for code walking that might result in modification to
|
||||||
|
* the code. Otherwise identical to walk_code.
|
||||||
|
*/
|
||||||
|
pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line))
|
||||||
|
{
|
||||||
|
let mut queue = VecDeque::from(vec![p]);
|
||||||
|
|
||||||
|
while let Some(first_idx) = queue.pop_front() {
|
||||||
|
let mut last_idx = first_idx;
|
||||||
|
|
||||||
|
capture_next_range(code, &mut queue, &mut last_idx);
|
||||||
|
|
||||||
|
for instr in &mut code[first_idx .. last_idx + 1] {
|
||||||
|
walker(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,28 @@
|
|||||||
use crate::prolog::machine::and_stack::*;
|
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::prolog::machine::machine_indices::*;
|
||||||
|
use crate::prolog::machine::stack::*;
|
||||||
|
|
||||||
use std::ops::IndexMut;
|
use std::ops::IndexMut;
|
||||||
|
|
||||||
type Trail = Vec<(Ref, HeapCellValue)>;
|
type Trail = Vec<(Ref, HeapCellValue)>;
|
||||||
|
|
||||||
pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
#[derive(Clone, Copy)]
|
||||||
fn threshold(&self) -> usize;
|
pub enum AttrVarPolicy {
|
||||||
fn push(&mut self, _: HeapCellValue);
|
DeepCopy,
|
||||||
fn store(&self, _: Addr) -> Addr;
|
StripAttributes
|
||||||
fn deref(&self, _: Addr) -> Addr;
|
|
||||||
fn stack(&mut self) -> &mut AndStack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn copy_term<T: CopierTarget>(target: T, addr: Addr) {
|
pub(crate) trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
||||||
let mut copy_term_state = CopyTermState::new(target);
|
fn threshold(&self) -> usize;
|
||||||
copy_term_state.copy_term_impl(addr);
|
fn push(&mut self, val: HeapCellValue);
|
||||||
|
fn store(&self, val: Addr) -> Addr;
|
||||||
|
fn deref(&self, val: Addr) -> Addr;
|
||||||
|
fn stack(&mut self) -> &mut Stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) {
|
||||||
|
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
|
||||||
|
copy_term_state.copy_term_impl(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CopyTermState<T: CopierTarget> {
|
struct CopyTermState<T: CopierTarget> {
|
||||||
@@ -23,15 +30,17 @@ struct CopyTermState<T: CopierTarget> {
|
|||||||
scan: usize,
|
scan: usize,
|
||||||
old_h: usize,
|
old_h: usize,
|
||||||
target: T,
|
target: T,
|
||||||
|
attr_var_policy: AttrVarPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: CopierTarget> CopyTermState<T> {
|
impl<T: CopierTarget> CopyTermState<T> {
|
||||||
fn new(target: T) -> Self {
|
fn new(target: T, attr_var_policy: AttrVarPolicy) -> Self {
|
||||||
CopyTermState {
|
CopyTermState {
|
||||||
trail: vec![],
|
trail: vec![],
|
||||||
scan: 0,
|
scan: 0,
|
||||||
old_h: target.threshold(),
|
old_h: target.threshold(),
|
||||||
target,
|
target,
|
||||||
|
attr_var_policy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,38 +50,29 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
&mut self.target[scan]
|
&mut self.target[scan]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reinstantiate_var(&mut self, addr: Addr, threshold: usize) {
|
fn copied_list(&mut self, addr: usize) -> bool {
|
||||||
match addr {
|
match &self.target[addr] {
|
||||||
Addr::HeapCell(h) => {
|
HeapCellValue::Addr(Addr::Lis(addr)) | HeapCellValue::Addr(Addr::HeapCell(addr)) => {
|
||||||
self.target[threshold] = HeapCellValue::Addr(Addr::HeapCell(threshold));
|
if *addr >= self.old_h {
|
||||||
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
|
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(*addr));
|
||||||
self.trail
|
self.scan += 1;
|
||||||
.push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h))));
|
return true;
|
||||||
}
|
}
|
||||||
Addr::StackCell(fr, sc) => {
|
|
||||||
self.target[threshold] = HeapCellValue::Addr(Addr::HeapCell(threshold));
|
|
||||||
self.target.stack()[fr][sc] = Addr::HeapCell(threshold);
|
|
||||||
self.trail.push((
|
|
||||||
Ref::StackCell(fr, sc),
|
|
||||||
HeapCellValue::Addr(Addr::StackCell(fr, sc)),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Addr::AttrVar(h) => {
|
|
||||||
self.target[threshold] = HeapCellValue::Addr(Addr::AttrVar(threshold));
|
|
||||||
self.target[h] = HeapCellValue::Addr(Addr::AttrVar(threshold));
|
|
||||||
self.trail
|
|
||||||
.push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h))));
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copied_list(&mut self, addr: usize) -> bool {
|
fn copied_partial_string(&mut self, addr: usize) -> bool {
|
||||||
if let HeapCellValue::Addr(Addr::Lis(addr)) = self.target[addr].clone() {
|
if let HeapCellValue::PartialString(ref pstr) = &self.target[addr] {
|
||||||
if addr >= self.old_h {
|
if let Addr::PStrLocation(h, n) = pstr.tail_addr() {
|
||||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(addr));
|
if *h >= self.old_h {
|
||||||
self.scan += 1;
|
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(*h, *n));
|
||||||
return true;
|
self.scan += 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,36 +85,176 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let threshold = self.target.threshold();
|
let threshold = self.target.threshold();
|
||||||
|
|
||||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
|
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
|
||||||
|
|
||||||
let hcv = self.target[addr].clone();
|
let ra = self.target[addr].as_addr(threshold);
|
||||||
self.target.push(hcv.clone());
|
let rd = self.target.store(self.target.deref(ra.clone()));
|
||||||
|
|
||||||
let ra = hcv.as_addr(threshold);
|
self.target.push(HeapCellValue::Addr(ra.clone()));
|
||||||
let rd = self.target.store(self.target.deref(ra));
|
|
||||||
|
let hcv = HeapCellValue::Addr(self.target[addr + 1].as_addr(addr + 1));
|
||||||
|
|
||||||
|
self.target.push(hcv);
|
||||||
|
|
||||||
match rd.clone() {
|
match rd.clone() {
|
||||||
Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
|
Addr::AttrVar(h) | Addr::HeapCell(h) | Addr::PStrTail(h, _)
|
||||||
self.target[threshold] = HeapCellValue::Addr(rd)
|
if h >= self.old_h => {
|
||||||
}
|
self.target[threshold] = HeapCellValue::Addr(rd)
|
||||||
ra @ Addr::AttrVar(_) | ra @ Addr::HeapCell(..) | ra @ Addr::StackCell(..) => {
|
}
|
||||||
|
var @ Addr::AttrVar(_)
|
||||||
|
| var @ Addr::HeapCell(..)
|
||||||
|
| var @ Addr::StackCell(..)
|
||||||
|
| var @ Addr::PStrTail(..) => {
|
||||||
if ra == rd {
|
if ra == rd {
|
||||||
self.reinstantiate_var(ra, threshold);
|
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));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.target[threshold] = HeapCellValue::Addr(ra);
|
self.target[threshold] = HeapCellValue::Addr(ra);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.trail
|
self.trail.push((
|
||||||
.push((Ref::HeapCell(addr), self.target[addr].clone()));
|
Ref::HeapCell(addr),
|
||||||
|
HeapCellValue::Addr(self.target[addr].as_addr(addr)),
|
||||||
|
));
|
||||||
|
|
||||||
self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold))
|
self.target[addr] = HeapCellValue::Addr(Addr::Lis(threshold))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let hcv = self.target[addr + 1].clone();
|
self.scan += 1;
|
||||||
self.target.push(hcv);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn copy_partial_string(&mut self, addr: usize, n: usize) {
|
||||||
|
let threshold = self.target.threshold();
|
||||||
|
|
||||||
|
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.scan += 1;
|
self.scan += 1;
|
||||||
|
|
||||||
|
self.copy_partial_string(addr, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
|
||||||
|
match addr {
|
||||||
|
Addr::HeapCell(h) => {
|
||||||
|
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||||
|
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||||
|
self.trail.push((
|
||||||
|
Ref::HeapCell(h),
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(h)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Addr::StackCell(fr, sc) => {
|
||||||
|
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||||
|
self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier);
|
||||||
|
self.trail.push((
|
||||||
|
Ref::StackCell(fr, sc),
|
||||||
|
HeapCellValue::Addr(Addr::StackCell(fr, sc)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
} else {
|
||||||
|
frontier
|
||||||
|
};
|
||||||
|
|
||||||
|
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)),
|
||||||
|
));
|
||||||
|
|
||||||
|
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||||
|
self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
|
||||||
|
|
||||||
|
let list_val = self.target[h + 1].clone();
|
||||||
|
self.target.push(list_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_var(&mut self, addr: Addr) {
|
fn copy_var(&mut self, addr: Addr) {
|
||||||
@@ -125,23 +265,13 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
*self.value_at_scan() = HeapCellValue::Addr(rd);
|
*self.value_at_scan() = HeapCellValue::Addr(rd);
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
}
|
}
|
||||||
Addr::AttrVar(h) if addr == rd => {
|
|
||||||
let threshold = self.target.threshold();
|
|
||||||
self.target
|
|
||||||
.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
|
|
||||||
|
|
||||||
let list_val = self.target[h + 1].clone();
|
|
||||||
self.target.push(list_val);
|
|
||||||
|
|
||||||
self.reinstantiate_var(addr, threshold);
|
|
||||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::AttrVar(threshold));
|
|
||||||
}
|
|
||||||
_ if addr == rd => {
|
_ if addr == rd => {
|
||||||
let scan = self.scan;
|
self.reinstantiate_var(addr, self.scan);
|
||||||
self.reinstantiate_var(addr, scan);
|
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
}
|
}
|
||||||
_ => *self.value_at_scan() = HeapCellValue::Addr(rd),
|
_ => {
|
||||||
|
*self.value_at_scan() = HeapCellValue::Addr(rd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,8 +288,7 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
HeapCellValue::NamedStr(arity, name.clone(), fixity.clone()),
|
HeapCellValue::NamedStr(arity, name.clone(), fixity.clone()),
|
||||||
));
|
));
|
||||||
|
|
||||||
self.target
|
self.target.push(HeapCellValue::NamedStr(arity, name, fixity));
|
||||||
.push(HeapCellValue::NamedStr(arity, name, fixity));
|
|
||||||
|
|
||||||
for i in 0..arity {
|
for i in 0..arity {
|
||||||
let hcv = self.target[addr + 1 + i].clone();
|
let hcv = self.target[addr + 1 + i].clone();
|
||||||
@@ -180,16 +309,35 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
self.target.push(HeapCellValue::Addr(addr));
|
self.target.push(HeapCellValue::Addr(addr));
|
||||||
|
|
||||||
while self.scan < self.target.threshold() {
|
while self.scan < self.target.threshold() {
|
||||||
match self.value_at_scan().clone() {
|
match self.value_at_scan() {
|
||||||
HeapCellValue::NamedStr(..) => self.scan += 1,
|
HeapCellValue::NamedStr(..) => {
|
||||||
HeapCellValue::Addr(addr) => match addr {
|
self.scan += 1;
|
||||||
Addr::Lis(addr) => self.copy_list(addr),
|
}
|
||||||
addr @ Addr::AttrVar(_)
|
HeapCellValue::Addr(ref addr) => {
|
||||||
| addr @ Addr::HeapCell(_)
|
match addr.clone() {
|
||||||
| addr @ Addr::StackCell(..) => self.copy_var(addr),
|
Addr::Lis(addr) => {
|
||||||
Addr::Str(addr) => self.copy_structure(addr),
|
self.copy_list(addr);
|
||||||
Addr::Con(_) | Addr::DBRef(_) => self.scan += 1,
|
}
|
||||||
},
|
addr @ Addr::AttrVar(_)
|
||||||
|
| addr @ Addr::HeapCell(_)
|
||||||
|
| addr @ Addr::StackCell(..)
|
||||||
|
| addr @ Addr::PStrTail(..) => {
|
||||||
|
self.copy_var(addr);
|
||||||
|
}
|
||||||
|
Addr::Str(addr) => {
|
||||||
|
self.copy_structure(addr);
|
||||||
|
}
|
||||||
|
Addr::PStrLocation(addr, n) => {
|
||||||
|
self.copy_partial_string_from(addr, n);
|
||||||
|
}
|
||||||
|
Addr::Con(_) | Addr::DBRef(_) => {
|
||||||
|
self.scan += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HeapCellValue::PartialString(_) => {
|
||||||
|
self.scan += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,8 +347,14 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
fn unwind_trail(&mut self) {
|
fn unwind_trail(&mut self) {
|
||||||
for (r, value) in self.trail.drain(0..) {
|
for (r, value) in self.trail.drain(0..) {
|
||||||
match r {
|
match r {
|
||||||
Ref::AttrVar(h) | Ref::HeapCell(h) => self.target[h] = value,
|
Ref::AttrVar(h) | Ref::HeapCell(h) =>
|
||||||
Ref::StackCell(fr, sc) => self.target.stack()[fr][sc] = value.as_addr(0),
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,19 +21,17 @@ impl Machine {
|
|||||||
name: ClauseName,
|
name: ClauseName,
|
||||||
arity: usize,
|
arity: usize,
|
||||||
) -> EvalSession {
|
) -> EvalSession {
|
||||||
let user_src = clause_name!("user");
|
|
||||||
|
|
||||||
match name.owning_module().as_str() {
|
match name.owning_module().as_str() {
|
||||||
"user" => match self.indices.code_dir.get(&(name.clone(), arity)).cloned() {
|
"user" => match self.indices.code_dir.get(&(name.clone(), arity)).cloned() {
|
||||||
Some(idx) => {
|
Some(idx) => {
|
||||||
let module = idx.0.borrow().1.clone();
|
let module = idx.0.borrow().1.clone();
|
||||||
|
|
||||||
match module.as_str() {
|
match module.as_str() {
|
||||||
"user" => compile_user_module(self, src, true, user_src),
|
"user" => compile_user_module(self, src, true, ListingSource::User),
|
||||||
_ => compile_into_module(self, module, src, name)
|
_ => compile_into_module(self, module, src, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => compile_user_module(self, src, true, user_src),
|
None => compile_user_module(self, src, true, ListingSource::User),
|
||||||
},
|
},
|
||||||
_ => compile_into_module(self, name.owning_module(), src, name),
|
_ => compile_into_module(self, name.owning_module(), src, name),
|
||||||
}
|
}
|
||||||
@@ -136,7 +134,7 @@ impl Machine {
|
|||||||
self.machine_st = machine_st;
|
self.machine_st = machine_st;
|
||||||
|
|
||||||
if let EvalSession::Error(err) = result {
|
if let EvalSession::Error(err) = result {
|
||||||
let h = self.machine_st.heap.h;
|
let h = self.machine_st.heap.h();
|
||||||
let stub = MachineError::functor_stub(src, 1);
|
let stub = MachineError::functor_stub(src, 1);
|
||||||
let err = MachineError::session_error(h, err);
|
let err = MachineError::session_error(h, err);
|
||||||
let err = self.machine_st.error_form(err, stub);
|
let err = self.machine_st.error_form(err, stub);
|
||||||
@@ -272,8 +270,12 @@ impl Machine {
|
|||||||
p: LocalCodePtr,
|
p: LocalCodePtr,
|
||||||
) {
|
) {
|
||||||
match trans_type {
|
match trans_type {
|
||||||
DynamicTransactionType::Abolish => self.abolish_dynamic_clause(temp_v!(1), temp_v!(2)),
|
DynamicTransactionType::Abolish => {
|
||||||
DynamicTransactionType::Assert(place) => self.recompile_dynamic_predicate(place),
|
self.abolish_dynamic_clause(temp_v!(1), temp_v!(2))
|
||||||
|
}
|
||||||
|
DynamicTransactionType::Assert(place) => {
|
||||||
|
self.recompile_dynamic_predicate(place)
|
||||||
|
}
|
||||||
DynamicTransactionType::ModuleAbolish => {
|
DynamicTransactionType::ModuleAbolish => {
|
||||||
self.abolish_dynamic_clause_in_module(temp_v!(1), temp_v!(2), temp_v!(3))
|
self.abolish_dynamic_clause_in_module(temp_v!(1), temp_v!(2), temp_v!(3))
|
||||||
}
|
}
|
||||||
@@ -283,7 +285,9 @@ impl Machine {
|
|||||||
DynamicTransactionType::ModuleRetract => {
|
DynamicTransactionType::ModuleRetract => {
|
||||||
self.retract_from_dynamic_predicate_in_module()
|
self.retract_from_dynamic_predicate_in_module()
|
||||||
}
|
}
|
||||||
DynamicTransactionType::Retract => self.retract_from_dynamic_predicate(),
|
DynamicTransactionType::Retract => {
|
||||||
|
self.retract_from_dynamic_predicate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.machine_st.p = CodePtr::Local(p);
|
self.machine_st.p = CodePtr::Local(p);
|
||||||
|
|||||||
@@ -1,99 +1,386 @@
|
|||||||
use prolog_parser::ast::*;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::prolog::machine::machine_indices::*;
|
||||||
|
use crate::prolog::machine::partial_string::*;
|
||||||
|
use crate::prolog::machine::raw_block::*;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
pub struct Heap {
|
pub(crate) struct StandardHeapTraits {}
|
||||||
heap: Vec<HeapCellValue>,
|
|
||||||
pub h: usize,
|
impl RawBlockTraits for StandardHeapTraits {
|
||||||
|
#[inline]
|
||||||
|
fn init_size() -> usize {
|
||||||
|
256 * mem::size_of::<HeapCellValue>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn align() -> usize {
|
||||||
|
mem::align_of::<HeapCellValue>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Heap {
|
pub(crate) struct HeapTemplate<T: RawBlockTraits> {
|
||||||
pub fn with_capacity(cap: usize) -> Self {
|
buf: RawBlock<T>,
|
||||||
Heap {
|
_marker: PhantomData<HeapCellValue>,
|
||||||
heap: Vec::with_capacity(cap),
|
}
|
||||||
h: 0,
|
|
||||||
|
pub(crate) type Heap = HeapTemplate<StandardHeapTraits>;
|
||||||
|
|
||||||
|
impl<T: RawBlockTraits> Drop for HeapTemplate<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.clear();
|
||||||
|
self.buf.deallocate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
struct HeapIntoIterator<T: RawBlockTraits> {
|
||||||
|
offset: usize,
|
||||||
|
buf: RawBlock<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RawBlockTraits> Drop for HeapIntoIterator<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let mut heap =
|
||||||
|
HeapTemplate { buf: self.buf.take(), _marker: PhantomData };
|
||||||
|
|
||||||
|
heap.truncate(self.offset / mem::size_of::<HeapCellValue>());
|
||||||
|
heap.buf.deallocate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RawBlockTraits> Iterator for HeapIntoIterator<T> {
|
||||||
|
type Item = HeapCellValue;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let ptr = self.buf.base as usize + self.offset;
|
||||||
|
self.offset += mem::size_of::<HeapCellValue>();
|
||||||
|
|
||||||
|
if ptr < self.buf.top as usize {
|
||||||
|
unsafe {
|
||||||
|
Some(ptr::read(ptr as *const HeapCellValue))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
struct HeapIterator<'a, T: RawBlockTraits> {
|
||||||
|
offset: usize,
|
||||||
|
buf: &'a RawBlock<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: RawBlockTraits> HeapIterator<'a, T> {
|
||||||
|
pub(crate)
|
||||||
|
fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
|
||||||
|
HeapIterator { buf, offset }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: RawBlockTraits> Iterator for HeapIterator<'a, T> {
|
||||||
|
type Item = &'a HeapCellValue;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let ptr = self.buf.base as usize + self.offset;
|
||||||
|
self.offset += mem::size_of::<HeapCellValue>();
|
||||||
|
|
||||||
|
if ptr < self.buf.top as usize {
|
||||||
|
unsafe {
|
||||||
|
Some(&*(ptr as *const _))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
struct HeapIteratorMut<'a, T: RawBlockTraits> {
|
||||||
|
offset: usize,
|
||||||
|
buf: &'a mut RawBlock<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: RawBlockTraits> HeapIteratorMut<'a, T> {
|
||||||
|
pub(crate)
|
||||||
|
fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
|
||||||
|
HeapIteratorMut { buf, offset }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: RawBlockTraits> Iterator for HeapIteratorMut<'a, T> {
|
||||||
|
type Item = &'a mut HeapCellValue;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let ptr = self.buf.base as usize + self.offset;
|
||||||
|
self.offset += mem::size_of::<HeapCellValue>();
|
||||||
|
|
||||||
|
if ptr < self.buf.top as usize {
|
||||||
|
unsafe {
|
||||||
|
Some(&mut *(ptr as *mut _))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn new() -> Self {
|
||||||
|
HeapTemplate { buf: RawBlock::new(), _marker: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn push(&mut self, val: HeapCellValue) {
|
pub(crate)
|
||||||
self.heap.push(val);
|
fn allocate_pstr(&mut self, mut src: &str) -> Option<Addr> {
|
||||||
self.h += 1;
|
let orig_h = self.h();
|
||||||
}
|
|
||||||
|
loop {
|
||||||
|
if src == "" {
|
||||||
|
return if orig_h == self.h() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let prev_h = self.h() - 1;
|
||||||
|
|
||||||
#[inline]
|
match &mut self[prev_h] {
|
||||||
pub(crate) fn take(&mut self) -> Self {
|
HeapCellValue::PartialString(ref mut pstr) => {
|
||||||
let h = self.h;
|
let s = pstr.block_as_str();
|
||||||
self.h = 0;
|
pstr.tail = Addr::PStrTail(prev_h, s.len());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Heap {
|
Some(Addr::PStrLocation(orig_h, 0))
|
||||||
heap: mem::replace(&mut self.heap, vec![]),
|
};
|
||||||
h,
|
}
|
||||||
|
|
||||||
|
let h = self.h();
|
||||||
|
|
||||||
|
let (mut pstr, rest_src) =
|
||||||
|
match PartialString::new(src, h) {
|
||||||
|
Some(tuple) => {
|
||||||
|
tuple
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if src.len() > '\u{0}'.len_utf8() {
|
||||||
|
src = &src['\u{0}'.len_utf8() ..];
|
||||||
|
continue;
|
||||||
|
} else if orig_h == h {
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(Addr::PStrLocation(orig_h, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_top = unsafe {
|
||||||
|
self.buf.new_block(mem::size_of::<HeapCellValue>())
|
||||||
|
};
|
||||||
|
|
||||||
|
if rest_src != "" {
|
||||||
|
pstr.tail = Addr::PStrLocation(h+1, 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 == "" {
|
||||||
|
return Some(Addr::PStrLocation(orig_h, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn truncate(&mut self, h: usize) {
|
pub(crate)
|
||||||
self.h = h;
|
fn take(&mut self) -> Self {
|
||||||
self.heap.truncate(h);
|
HeapTemplate {
|
||||||
|
buf: self.buf.take(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn last(&self) -> Option<&HeapCellValue> {
|
pub(crate)
|
||||||
self.heap.last()
|
fn truncate(&mut self, h: usize) {
|
||||||
|
let new_top = h * mem::size_of::<HeapCellValue>() + self.buf.base as usize;
|
||||||
|
let mut h = new_top;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
while h as *const _ < self.buf.top {
|
||||||
|
let val = h as *mut HeapCellValue;
|
||||||
|
ptr::drop_in_place(val);
|
||||||
|
h += mem::size_of::<HeapCellValue>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.buf.top = new_top as *const _;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn len(&self) -> usize {
|
pub(crate)
|
||||||
self.heap.len()
|
fn h(&self) -> usize {
|
||||||
|
(self.buf.top as usize - self.buf.base as usize) / mem::size_of::<HeapCellValue>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append(&mut self, vals: Vec<HeapCellValue>) {
|
pub(crate)
|
||||||
let n = vals.len();
|
fn append(&mut self, vals: Vec<HeapCellValue>) {
|
||||||
|
for val in vals {
|
||||||
self.heap.extend(vals.into_iter());
|
self.push(val);
|
||||||
self.h += n;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub(crate)
|
||||||
self.heap.clear();
|
fn clear(&mut self) {
|
||||||
self.h = 0;
|
if !self.buf.base.is_null() {
|
||||||
|
self.truncate(0);
|
||||||
|
self.buf.top = self.buf.base;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_list<Iter: Iterator<Item = Addr>>(&mut self, values: Iter) -> usize {
|
pub(crate)
|
||||||
let head_addr = self.h;
|
fn to_list<Iter: Iterator<Item = Addr>>(&mut self, values: Iter) -> usize {
|
||||||
|
let head_addr = self.h();
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let h = self.h;
|
let h = self.h();
|
||||||
|
|
||||||
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||||
self.push(HeapCellValue::Addr(value));
|
self.push(HeapCellValue::Addr(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push(HeapCellValue::Addr(Addr::Con(Constant::EmptyList)));
|
self.push(HeapCellValue::Addr(Addr::Con(Constant::EmptyList)));
|
||||||
|
|
||||||
head_addr
|
head_addr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend<Iter: Iterator<Item = HeapCellValue>>(&mut self, iter: Iter) {
|
/* 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>())
|
||||||
|
}
|
||||||
|
|
||||||
|
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>())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
fn into_iter(mut self) -> HeapIntoIterator<T> {
|
||||||
|
HeapIntoIterator { buf: self.buf.take(), offset: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
fn extend<Iter: Iterator<Item = HeapCellValue>>(&mut self, iter: Iter) {
|
||||||
for hcv in iter {
|
for hcv in iter {
|
||||||
self.push(hcv);
|
self.push(hcv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match addr {
|
||||||
|
Addr::Str(s) => {
|
||||||
|
match &self[*s] {
|
||||||
|
HeapCellValue::NamedStr(arity, ref name, _) => {
|
||||||
|
match (name.as_str(), *arity) {
|
||||||
|
("dir_entry", 1) => {
|
||||||
|
extract_integer(s+1).map(LocalCodePtr::DirEntry)
|
||||||
|
}
|
||||||
|
("in_situ_dir_entry", 1) => {
|
||||||
|
extract_integer(s+1).map(LocalCodePtr::InSituDirEntry)
|
||||||
|
}
|
||||||
|
("top_level", 2) => {
|
||||||
|
if let Some(chunk_num) = extract_integer(s+1) {
|
||||||
|
if let Some(p) = extract_integer(s+2) {
|
||||||
|
return Some(LocalCodePtr::TopLevel(chunk_num, p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
("user_goal_expansion", 1) => {
|
||||||
|
extract_integer(s+1).map(LocalCodePtr::UserGoalExpansion)
|
||||||
|
}
|
||||||
|
("user_term_expansion", 1) => {
|
||||||
|
extract_integer(s+1).map(LocalCodePtr::UserTermExpansion)
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<usize> for Heap {
|
impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
|
||||||
type Output = HeapCellValue;
|
type Output = HeapCellValue;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
&self.heap[index]
|
unsafe {
|
||||||
|
let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
|
||||||
|
&*(ptr as *const HeapCellValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexMut<usize> for Heap {
|
impl<T: RawBlockTraits> IndexMut<usize> for HeapTemplate<T> {
|
||||||
|
#[inline]
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
&mut self.heap[index]
|
unsafe {
|
||||||
|
let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
|
||||||
|
&mut *(ptr as *mut HeapCellValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
use prolog_parser::ast::*;
|
use prolog_parser::ast::*;
|
||||||
use prolog_parser::string_list::*;
|
|
||||||
|
|
||||||
|
use crate::prolog::forms::PredicateKey;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::prolog::machine::machine_indices::*;
|
||||||
use crate::prolog::machine::machine_state::*;
|
use crate::prolog::machine::machine_state::*;
|
||||||
use crate::prolog::rug::Integer;
|
use crate::prolog::rug::Integer;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub(crate) type MachineStub = Vec<HeapCellValue>;
|
pub(crate) type MachineStub = Vec<HeapCellValue>;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@@ -80,6 +82,7 @@ impl MachineError {
|
|||||||
],
|
],
|
||||||
SharedOpDesc::new(400, YFX)
|
SharedOpDesc::new(400, YFX)
|
||||||
));
|
));
|
||||||
|
|
||||||
stub.append(&mut functor!(
|
stub.append(&mut functor!(
|
||||||
":",
|
":",
|
||||||
2,
|
2,
|
||||||
@@ -133,7 +136,7 @@ impl MachineError {
|
|||||||
SessionError::InvalidFileName(filename) => {
|
SessionError::InvalidFileName(filename) => {
|
||||||
Self::existence_error(h, ExistenceError::Module(filename))
|
Self::existence_error(h, ExistenceError::Module(filename))
|
||||||
}
|
}
|
||||||
SessionError::ModuleDoesNotContainExport => Self::permission_error(
|
SessionError::ModuleDoesNotContainExport(..) => Self::permission_error(
|
||||||
PermissionError::Access,
|
PermissionError::Access,
|
||||||
"private_procedure",
|
"private_procedure",
|
||||||
clause_name!("module_does_not_contain_claimed_export"),
|
clause_name!("module_does_not_contain_claimed_export"),
|
||||||
@@ -388,10 +391,13 @@ impl EvalError {
|
|||||||
pub(super) enum CycleSearchResult {
|
pub(super) enum CycleSearchResult {
|
||||||
EmptyList,
|
EmptyList,
|
||||||
NotList,
|
NotList,
|
||||||
PartialList(usize, usize), // the list length (up to max), and an offset into the heap.
|
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
|
||||||
ProperList(usize), // the list length.
|
ProperList(usize), // the list length.
|
||||||
String(usize, StringList), // the number of elements iterated, the string tail.
|
CompleteString(usize, Rc<String>), // the string length (in bytes), the string.
|
||||||
UntouchedList(usize), // the address of an uniterated Addr::Lis(address).
|
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 {
|
impl MachineState {
|
||||||
@@ -482,7 +488,7 @@ impl MachineState {
|
|||||||
let location = err.location;
|
let location = err.location;
|
||||||
let err_len = err.len();
|
let err_len = err.len();
|
||||||
|
|
||||||
let h = self.heap.h;
|
let h = self.heap.h();
|
||||||
let mut stub = vec![
|
let mut stub = vec![
|
||||||
HeapCellValue::NamedStr(2, clause_name!("error"), None),
|
HeapCellValue::NamedStr(2, clause_name!("error"), None),
|
||||||
HeapCellValue::Addr(Addr::HeapCell(h + 3)),
|
HeapCellValue::Addr(Addr::HeapCell(h + 3)),
|
||||||
@@ -509,7 +515,7 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn throw_exception(&mut self, err: MachineStub) {
|
pub(super) fn throw_exception(&mut self, err: MachineStub) {
|
||||||
let h = self.heap.h;
|
let h = self.heap.h();
|
||||||
|
|
||||||
self.ball.boundary = 0;
|
self.ball.boundary = 0;
|
||||||
self.ball.stub.truncate(0);
|
self.ball.stub.truncate(0);
|
||||||
@@ -532,7 +538,7 @@ pub enum SessionError {
|
|||||||
CannotOverwriteBuiltIn(ClauseName),
|
CannotOverwriteBuiltIn(ClauseName),
|
||||||
CannotOverwriteImport(ClauseName),
|
CannotOverwriteImport(ClauseName),
|
||||||
InvalidFileName(ClauseName),
|
InvalidFileName(ClauseName),
|
||||||
ModuleDoesNotContainExport,
|
ModuleDoesNotContainExport(ClauseName, PredicateKey),
|
||||||
ModuleNotFound,
|
ModuleNotFound,
|
||||||
NamelessEntry,
|
NamelessEntry,
|
||||||
OpIsInfixAndPostFix(ClauseName),
|
OpIsInfixAndPostFix(ClauseName),
|
||||||
|
|||||||
@@ -4,7 +4,13 @@ use prolog_parser::tabled_rc::*;
|
|||||||
use crate::prolog::clause_types::*;
|
use crate::prolog::clause_types::*;
|
||||||
use crate::prolog::fixtures::*;
|
use crate::prolog::fixtures::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::prolog::forms::*;
|
||||||
|
use crate::prolog::machine::code_repo::CodeRepo;
|
||||||
use crate::prolog::machine::Ball;
|
use crate::prolog::machine::Ball;
|
||||||
|
use crate::prolog::machine::heap::*;
|
||||||
|
use crate::prolog::machine::partial_string::*;
|
||||||
|
use crate::prolog::machine::raw_block::RawBlockTraits;
|
||||||
|
use crate::prolog::instructions::*;
|
||||||
|
use crate::prolog::rug::Integer;
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
@@ -41,6 +47,8 @@ pub enum Addr {
|
|||||||
HeapCell(usize),
|
HeapCell(usize),
|
||||||
StackCell(usize, usize),
|
StackCell(usize, usize),
|
||||||
Str(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.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
|
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
@@ -48,6 +56,7 @@ pub enum Ref {
|
|||||||
AttrVar(usize),
|
AttrVar(usize),
|
||||||
HeapCell(usize),
|
HeapCell(usize),
|
||||||
StackCell(usize, usize),
|
StackCell(usize, usize),
|
||||||
|
PStrTail(usize, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ref {
|
impl Ref {
|
||||||
@@ -56,6 +65,7 @@ impl Ref {
|
|||||||
Ref::AttrVar(h) => Addr::AttrVar(h),
|
Ref::AttrVar(h) => Addr::AttrVar(h),
|
||||||
Ref::HeapCell(h) => Addr::HeapCell(h),
|
Ref::HeapCell(h) => Addr::HeapCell(h),
|
||||||
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
|
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
|
||||||
|
Ref::PStrTail(h, n) => Addr::PStrTail(h, n),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,23 +80,51 @@ impl PartialEq<Ref> for Addr {
|
|||||||
impl PartialOrd<Ref> for Addr {
|
impl PartialOrd<Ref> for Addr {
|
||||||
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
|
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
|
||||||
match self {
|
match self {
|
||||||
&Addr::StackCell(fr, sc) => match *r {
|
&Addr::StackCell(fr, sc) => {
|
||||||
Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater),
|
match *r {
|
||||||
Ref::StackCell(fr1, sc1) => {
|
Ref::AttrVar(_) | Ref::HeapCell(_) | Ref::PStrTail(..) => {
|
||||||
if fr1 < fr || (fr1 == fr && sc1 < sc) {
|
|
||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
} else if fr1 == fr && sc1 == sc {
|
}
|
||||||
Some(Ordering::Equal)
|
Ref::StackCell(fr1, sc1) => {
|
||||||
} else {
|
if fr1 < fr || (fr1 == fr && sc1 < sc) {
|
||||||
Some(Ordering::Less)
|
Some(Ordering::Greater)
|
||||||
|
} else if fr1 == fr && sc1 == sc {
|
||||||
|
Some(Ordering::Equal)
|
||||||
|
} else {
|
||||||
|
Some(Ordering::Less)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
&Addr::HeapCell(h) | &Addr::AttrVar(h) => match r {
|
&Addr::HeapCell(h) | &Addr::AttrVar(h) => {
|
||||||
&Ref::StackCell(..) => Some(Ordering::Less),
|
match r {
|
||||||
&Ref::AttrVar(h1) | &Ref::HeapCell(h1) => h.partial_cmp(&h1),
|
Ref::StackCell(..) => {
|
||||||
},
|
Some(Ordering::Less)
|
||||||
_ => None,
|
}
|
||||||
|
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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,8 +132,12 @@ impl PartialOrd<Ref> for Addr {
|
|||||||
impl Addr {
|
impl Addr {
|
||||||
pub fn is_ref(&self) -> bool {
|
pub fn is_ref(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&Addr::AttrVar(_) | &Addr::HeapCell(_) | &Addr::StackCell(_, _) => true,
|
Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) | Addr::PStrTail(..) => {
|
||||||
_ => false,
|
true
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +146,7 @@ impl Addr {
|
|||||||
&Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
|
&Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
|
||||||
&Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
|
&Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
|
||||||
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
|
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
|
||||||
|
&Addr::PStrTail(h, n) => Some(Ref::PStrTail(h, n)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,6 +168,8 @@ impl Add<usize> for Addr {
|
|||||||
Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
|
Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
|
||||||
Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
|
Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
|
||||||
Addr::Str(s) => Addr::Str(s + 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,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,6 +185,8 @@ impl Sub<i64> for Addr {
|
|||||||
Addr::AttrVar(h) => Addr::AttrVar(h + 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::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize),
|
||||||
Addr::Str(s) => Addr::Str(s + 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,
|
_ => self,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -157,6 +204,8 @@ impl Sub<usize> for Addr {
|
|||||||
Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
|
Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
|
||||||
Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
|
Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
|
||||||
Addr::Str(s) => Addr::Str(s - 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,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,16 +217,6 @@ impl SubAssign<usize> for Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Ref> for Addr {
|
|
||||||
fn from(r: Ref) -> Self {
|
|
||||||
match r {
|
|
||||||
Ref::AttrVar(h) => Addr::AttrVar(h),
|
|
||||||
Ref::HeapCell(h) => Addr::HeapCell(h),
|
|
||||||
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum TrailRef {
|
pub enum TrailRef {
|
||||||
Ref(Ref),
|
Ref(Ref),
|
||||||
@@ -195,13 +234,21 @@ impl From<Ref> for TrailRef {
|
|||||||
pub enum HeapCellValue {
|
pub enum HeapCellValue {
|
||||||
Addr(Addr),
|
Addr(Addr),
|
||||||
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
|
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
|
||||||
|
PartialString(PartialString),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeapCellValue {
|
impl HeapCellValue {
|
||||||
pub fn as_addr(&self, focus: usize) -> Addr {
|
pub fn as_addr(&self, focus: usize) -> Addr {
|
||||||
match self {
|
match self {
|
||||||
&HeapCellValue::Addr(ref a) => a.clone(),
|
HeapCellValue::Addr(ref a) => {
|
||||||
&HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus),
|
a.clone()
|
||||||
|
}
|
||||||
|
HeapCellValue::NamedStr(_, _, _) => {
|
||||||
|
Addr::Str(focus)
|
||||||
|
}
|
||||||
|
HeapCellValue::PartialString(_) => {
|
||||||
|
Addr::PStrLocation(focus, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,13 +257,21 @@ impl HeapCellValue {
|
|||||||
pub enum IndexPtr {
|
pub enum IndexPtr {
|
||||||
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
||||||
Undefined,
|
Undefined,
|
||||||
|
InSituDirEntry(usize),
|
||||||
Index(usize),
|
Index(usize),
|
||||||
|
UserGoalExpansion,
|
||||||
|
UserTermExpansion
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
pub struct CodeIndex(pub Rc<RefCell<(IndexPtr, ClauseName)>>);
|
pub struct CodeIndex(pub Rc<RefCell<(IndexPtr, ClauseName)>>);
|
||||||
|
|
||||||
impl CodeIndex {
|
impl CodeIndex {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(ptr: IndexPtr, module_name: ClauseName) -> Self {
|
||||||
|
CodeIndex(Rc::new(RefCell::new(( ptr, module_name ))))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_undefined(&self) -> bool {
|
pub fn is_undefined(&self) -> bool {
|
||||||
let index_ptr = &self.0.borrow().0;
|
let index_ptr = &self.0.borrow().0;
|
||||||
@@ -234,7 +289,7 @@ impl CodeIndex {
|
|||||||
module_name
|
module_name
|
||||||
))))
|
))))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn module_name(&self) -> ClauseName {
|
pub fn module_name(&self) -> ClauseName {
|
||||||
self.0.borrow().1.clone()
|
self.0.borrow().1.clone()
|
||||||
@@ -309,7 +364,7 @@ pub enum REPLCodePtr {
|
|||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum CodePtr {
|
pub enum CodePtr {
|
||||||
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
|
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
|
||||||
CallN(usize, LocalCodePtr), // arity, local.
|
CallN(usize, LocalCodePtr, bool), // arity, local, last call.
|
||||||
Local(LocalCodePtr),
|
Local(LocalCodePtr),
|
||||||
DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
|
DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
|
||||||
REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
|
REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
|
||||||
@@ -320,7 +375,7 @@ impl CodePtr {
|
|||||||
pub fn local(&self) -> LocalCodePtr {
|
pub fn local(&self) -> LocalCodePtr {
|
||||||
match self {
|
match self {
|
||||||
&CodePtr::BuiltInClause(_, ref local)
|
&CodePtr::BuiltInClause(_, ref local)
|
||||||
| &CodePtr::CallN(_, ref local)
|
| &CodePtr::CallN(_, ref local, _)
|
||||||
| &CodePtr::Local(ref local) => local.clone(),
|
| &CodePtr::Local(ref local) => local.clone(),
|
||||||
&CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
|
&CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
|
||||||
&CodePtr::REPL(_, p) | &CodePtr::DynamicTransaction(_, p) => p,
|
&CodePtr::REPL(_, p) | &CodePtr::DynamicTransaction(_, p) => p,
|
||||||
@@ -328,7 +383,7 @@ impl CodePtr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum LocalCodePtr {
|
pub enum LocalCodePtr {
|
||||||
DirEntry(usize), // offset.
|
DirEntry(usize), // offset.
|
||||||
InSituDirEntry(usize),
|
InSituDirEntry(usize),
|
||||||
@@ -338,12 +393,78 @@ pub enum LocalCodePtr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LocalCodePtr {
|
impl LocalCodePtr {
|
||||||
pub fn assign_if_local(&mut self, cp: CodePtr) {
|
pub(crate)
|
||||||
|
fn assign_if_local(&mut self, cp: CodePtr) {
|
||||||
match cp {
|
match cp {
|
||||||
CodePtr::Local(local) => *self = local,
|
CodePtr::Local(local) => *self = local,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool {
|
||||||
|
match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) {
|
||||||
|
Some(line) => {
|
||||||
|
match line.as_ref() {
|
||||||
|
Line::Control(ControlInstruction::CallClause(ref ct, ..)) => {
|
||||||
|
if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
fn as_functor<T: RawBlockTraits>(&self, heap: &mut HeapTemplate<T>) -> Addr {
|
||||||
|
let addr = Addr::HeapCell(heap.h());
|
||||||
|
|
||||||
|
match self {
|
||||||
|
LocalCodePtr::DirEntry(p) => {
|
||||||
|
heap.append(functor!(
|
||||||
|
"dir_entry",
|
||||||
|
1,
|
||||||
|
[heap_integer!(Integer::from(*p))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
LocalCodePtr::InSituDirEntry(p) => {
|
||||||
|
heap.append(functor!(
|
||||||
|
"in_situ_dir_entry",
|
||||||
|
1,
|
||||||
|
[heap_integer!(Integer::from(*p))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
LocalCodePtr::TopLevel(chunk_num, offset) => {
|
||||||
|
heap.append(functor!(
|
||||||
|
"top_level",
|
||||||
|
2,
|
||||||
|
[heap_integer!(Integer::from(*chunk_num)),
|
||||||
|
heap_integer!(Integer::from(*offset))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
LocalCodePtr::UserGoalExpansion(p) => {
|
||||||
|
heap.append(functor!(
|
||||||
|
"user_goal_expansion",
|
||||||
|
1,
|
||||||
|
[heap_integer!(Integer::from(*p))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
LocalCodePtr::UserTermExpansion(p) => {
|
||||||
|
heap.append(functor!(
|
||||||
|
"user_term_expansion",
|
||||||
|
1,
|
||||||
|
[heap_integer!(Integer::from(*p))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd<CodePtr> for CodePtr {
|
impl PartialOrd<CodePtr> for CodePtr {
|
||||||
@@ -397,6 +518,25 @@ impl Add<usize> for LocalCodePtr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Sub<usize> for LocalCodePtr {
|
||||||
|
type Output = Option<LocalCodePtr>;
|
||||||
|
|
||||||
|
fn sub(self, rhs: usize) -> Self::Output {
|
||||||
|
match self {
|
||||||
|
LocalCodePtr::InSituDirEntry(p) =>
|
||||||
|
p.checked_sub(rhs).map(LocalCodePtr::InSituDirEntry),
|
||||||
|
LocalCodePtr::DirEntry(p) =>
|
||||||
|
p.checked_sub(rhs).map(LocalCodePtr::DirEntry),
|
||||||
|
LocalCodePtr::TopLevel(cn, p) =>
|
||||||
|
p.checked_sub(rhs).map(|r| LocalCodePtr::TopLevel(cn, r)),
|
||||||
|
LocalCodePtr::UserTermExpansion(p) =>
|
||||||
|
p.checked_sub(rhs).map(LocalCodePtr::UserTermExpansion),
|
||||||
|
LocalCodePtr::UserGoalExpansion(p) =>
|
||||||
|
p.checked_sub(rhs).map(LocalCodePtr::UserGoalExpansion),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AddAssign<usize> for LocalCodePtr {
|
impl AddAssign<usize> for LocalCodePtr {
|
||||||
fn add_assign(&mut self, rhs: usize) {
|
fn add_assign(&mut self, rhs: usize) {
|
||||||
match self {
|
match self {
|
||||||
@@ -418,7 +558,7 @@ impl Add<usize> for CodePtr {
|
|||||||
| p @ CodePtr::VerifyAttrInterrupt(_)
|
| p @ CodePtr::VerifyAttrInterrupt(_)
|
||||||
| p @ CodePtr::DynamicTransaction(..) => p,
|
| p @ CodePtr::DynamicTransaction(..) => p,
|
||||||
CodePtr::Local(local) => CodePtr::Local(local + rhs),
|
CodePtr::Local(local) => CodePtr::Local(local + rhs),
|
||||||
CodePtr::CallN(_, local) | CodePtr::BuiltInClause(_, local) => {
|
CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => {
|
||||||
CodePtr::Local(local + rhs)
|
CodePtr::Local(local + rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -452,22 +592,41 @@ impl Default for DynamicPredicateInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub type InSituCodeDir = IndexMap<PredicateKey, usize>;
|
pub type InSituCodeDir = IndexMap<PredicateKey, usize>;
|
||||||
|
|
||||||
// key type: module name, predicate indicator.
|
// key type: module name, predicate indicator.
|
||||||
pub type DynamicCodeDir = IndexMap<(ClauseName, ClauseName, usize), DynamicPredicateInfo>;
|
pub type DynamicCodeDir = IndexMap<(ClauseName, ClauseName, usize), DynamicPredicateInfo>;
|
||||||
|
|
||||||
pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<usize>)>;
|
pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<usize>)>;
|
||||||
|
|
||||||
|
pub(crate) struct ModuleStub {
|
||||||
|
pub(crate) atom_tbl: TabledData<Atom>,
|
||||||
|
pub(crate) in_situ_code_dir: InSituCodeDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleStub {
|
||||||
|
pub(crate) fn new(atom_tbl: TabledData<Atom>) -> Self {
|
||||||
|
ModuleStub {
|
||||||
|
atom_tbl,
|
||||||
|
in_situ_code_dir: InSituCodeDir::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
|
||||||
|
|
||||||
pub struct IndexStore {
|
pub struct IndexStore {
|
||||||
pub(super) atom_tbl: TabledData<Atom>,
|
pub(super) atom_tbl: TabledData<Atom>,
|
||||||
pub(super) code_dir: CodeDir,
|
pub(super) code_dir: CodeDir,
|
||||||
|
pub(super) module_dir: ModuleDir,
|
||||||
pub(super) dynamic_code_dir: DynamicCodeDir,
|
pub(super) dynamic_code_dir: DynamicCodeDir,
|
||||||
pub(super) global_variables: GlobalVarDir,
|
pub(super) global_variables: GlobalVarDir,
|
||||||
pub(super) in_situ_code_dir: InSituCodeDir,
|
pub(super) in_situ_code_dir: InSituCodeDir,
|
||||||
|
pub(super) in_situ_module_dir: ModuleStubDir,
|
||||||
pub(super) modules: ModuleDir,
|
pub(super) modules: ModuleDir,
|
||||||
pub(super) op_dir: OpDir,
|
pub(super) op_dir: OpDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexStore {
|
impl IndexStore {
|
||||||
pub fn predicate_exists(
|
pub fn predicate_exists(
|
||||||
&self,
|
&self,
|
||||||
name: ClauseName,
|
name: ClauseName,
|
||||||
@@ -491,6 +650,19 @@ impl IndexStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_term_and_goal_expansion_indices(&mut self) {
|
||||||
|
self.code_dir.insert((clause_name!("term_expansion"), 2),
|
||||||
|
CodeIndex(Rc::new(RefCell::new(
|
||||||
|
(IndexPtr::UserTermExpansion,
|
||||||
|
clause_name!("user"))
|
||||||
|
))));
|
||||||
|
self.code_dir.insert((clause_name!("goal_expansion"), 2),
|
||||||
|
CodeIndex(Rc::new(RefCell::new(
|
||||||
|
(IndexPtr::UserGoalExpansion,
|
||||||
|
clause_name!("user"))
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn remove_clause_subsection(&mut self, module: ClauseName, name: ClauseName, arity: usize) {
|
pub fn remove_clause_subsection(&mut self, module: ClauseName, name: ClauseName, arity: usize) {
|
||||||
self.dynamic_code_dir.swap_remove(&(module, name, arity));
|
self.dynamic_code_dir.swap_remove(&(module, name, arity));
|
||||||
@@ -506,6 +678,16 @@ impl IndexStore {
|
|||||||
self.dynamic_code_dir.get(&(module, name, arity)).cloned()
|
self.dynamic_code_dir.get(&(module, name, arity)).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn take_in_situ_module_dir(&mut self) -> ModuleStubDir {
|
||||||
|
mem::replace(&mut self.in_situ_module_dir, ModuleStubDir::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn take_in_situ_code_dir(&mut self) -> InSituCodeDir {
|
||||||
|
mem::replace(&mut self.in_situ_code_dir, InSituCodeDir::new())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn take_module(&mut self, name: ClauseName) -> Option<Module> {
|
pub fn take_module(&mut self, name: ClauseName) -> Option<Module> {
|
||||||
self.modules.swap_remove(&name)
|
self.modules.swap_remove(&name)
|
||||||
@@ -521,12 +703,13 @@ impl IndexStore {
|
|||||||
IndexStore {
|
IndexStore {
|
||||||
atom_tbl: TabledData::new(Rc::new("user".to_string())),
|
atom_tbl: TabledData::new(Rc::new("user".to_string())),
|
||||||
code_dir: CodeDir::new(),
|
code_dir: CodeDir::new(),
|
||||||
|
module_dir: ModuleDir::new(),
|
||||||
dynamic_code_dir: DynamicCodeDir::new(),
|
dynamic_code_dir: DynamicCodeDir::new(),
|
||||||
global_variables: GlobalVarDir::new(),
|
global_variables: GlobalVarDir::new(),
|
||||||
in_situ_code_dir: InSituCodeDir::new(),
|
in_situ_code_dir: InSituCodeDir::new(),
|
||||||
|
in_situ_module_dir: ModuleStubDir::new(),
|
||||||
op_dir: default_op_dir(),
|
op_dir: default_op_dir(),
|
||||||
modules: ModuleDir::new(),
|
modules: ModuleDir::new(),
|
||||||
// parsing_stream: readline::parsing_stream(String::new())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,6 +762,77 @@ impl IndexStore {
|
|||||||
pub type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
|
pub type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
|
||||||
pub type TermDir = IndexMap<PredicateKey, (Predicate, VecDeque<TopLevel>)>;
|
pub type TermDir = IndexMap<PredicateKey, (Predicate, VecDeque<TopLevel>)>;
|
||||||
|
|
||||||
|
pub struct TermDirQuantumEntry {
|
||||||
|
pub old_terms: (Predicate, VecDeque<TopLevel>),
|
||||||
|
pub new_terms: (Predicate, VecDeque<TopLevel>),
|
||||||
|
pub is_fresh: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TermDirQuantumEntry {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
TermDirQuantumEntry {
|
||||||
|
old_terms: (Predicate::new(), VecDeque::new()),
|
||||||
|
new_terms: (Predicate::new(), VecDeque::new()),
|
||||||
|
is_fresh: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from(preds: &Predicate, queue: &VecDeque<TopLevel>) -> Self
|
||||||
|
{
|
||||||
|
let mut entry = TermDirQuantumEntry::new();
|
||||||
|
entry.is_fresh = false;
|
||||||
|
|
||||||
|
(entry.old_terms.0).0.extend(preds.0.iter().cloned());
|
||||||
|
entry.old_terms.1.extend(queue.iter().cloned());
|
||||||
|
|
||||||
|
entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TermDirQuantum(IndexMap<PredicateKey, TermDirQuantumEntry>);
|
||||||
|
|
||||||
|
impl TermDirQuantum {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
TermDirQuantum(IndexMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn insert_or_refresh(&mut self, key: PredicateKey, mut entry: TermDirQuantumEntry) {
|
||||||
|
if let Some(prev_entry) = self.get_mut(&key) {
|
||||||
|
prev_entry.is_fresh = true;
|
||||||
|
} else {
|
||||||
|
entry.is_fresh = true;
|
||||||
|
self.0.insert(key, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn insert(&mut self, key: PredicateKey, entry: TermDirQuantumEntry) {
|
||||||
|
self.0.insert(key, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_mut(&mut self, key: &PredicateKey) -> Option<&mut TermDirQuantumEntry> {
|
||||||
|
self.0.get_mut(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consolidate(self) -> TermDir {
|
||||||
|
let mut term_dir = TermDir::new();
|
||||||
|
|
||||||
|
for (key, entry) in self.0 {
|
||||||
|
let (preds, queue) =
|
||||||
|
term_dir.entry(key).or_insert((Predicate::new(), VecDeque::new()));
|
||||||
|
|
||||||
|
preds.0.extend((entry.new_terms.0).0.into_iter());
|
||||||
|
queue.extend(entry.new_terms.1.into_iter());
|
||||||
|
}
|
||||||
|
|
||||||
|
term_dir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
||||||
pub enum CompileTimeHook {
|
pub enum CompileTimeHook {
|
||||||
GoalExpansion,
|
GoalExpansion,
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
use prolog_parser::ast::*;
|
use prolog_parser::ast::*;
|
||||||
use prolog_parser::string_list::*;
|
|
||||||
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::prolog::clause_types::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::prolog::forms::*;
|
||||||
use crate::prolog::machine::and_stack::*;
|
|
||||||
use crate::prolog::machine::attributed_variables::*;
|
use crate::prolog::machine::attributed_variables::*;
|
||||||
use crate::prolog::machine::copier::*;
|
use crate::prolog::machine::copier::*;
|
||||||
use crate::prolog::machine::heap::*;
|
use crate::prolog::machine::heap::*;
|
||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::prolog::machine::machine_errors::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::prolog::machine::machine_indices::*;
|
||||||
use crate::prolog::machine::modules::*;
|
use crate::prolog::machine::modules::*;
|
||||||
use crate::prolog::machine::or_stack::*;
|
use crate::prolog::machine::stack::*;
|
||||||
use crate::prolog::read::PrologStream;
|
use crate::prolog::read::PrologStream;
|
||||||
use crate::prolog::rug::Integer;
|
use crate::prolog::rug::Integer;
|
||||||
|
|
||||||
@@ -22,47 +20,54 @@ use std::mem;
|
|||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
pub struct Ball {
|
pub struct Ball {
|
||||||
pub(super) boundary: usize, // ball.0
|
pub(super) boundary: usize,
|
||||||
pub(super) stub: MachineStub, // ball.1
|
pub(super) stub: Heap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ball {
|
impl Ball {
|
||||||
pub(super) fn new() -> Self {
|
pub(super)
|
||||||
|
fn new() -> Self {
|
||||||
Ball {
|
Ball {
|
||||||
boundary: 0,
|
boundary: 0,
|
||||||
stub: MachineStub::new(),
|
stub: Heap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn reset(&mut self) {
|
pub(super)
|
||||||
|
fn reset(&mut self) {
|
||||||
self.boundary = 0;
|
self.boundary = 0;
|
||||||
self.stub.clear();
|
self.stub.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn take(&mut self) -> Ball {
|
pub(super)
|
||||||
|
fn take(&mut self) -> Ball {
|
||||||
let boundary = self.boundary;
|
let boundary = self.boundary;
|
||||||
self.boundary = 0;
|
self.boundary = 0;
|
||||||
|
|
||||||
Ball {
|
Ball {
|
||||||
boundary,
|
boundary,
|
||||||
stub: mem::replace(&mut self.stub, vec![]),
|
stub: self.stub.take(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn copy_and_align(&self, h: usize) -> MachineStub {
|
pub(super)
|
||||||
|
fn copy_and_align(&self, h: usize) -> Heap {
|
||||||
let diff = self.boundary as i64 - h as i64;
|
let diff = self.boundary as i64 - h as i64;
|
||||||
let mut stub = vec![];
|
let mut stub = Heap::new();
|
||||||
|
|
||||||
for index in 0..self.stub.len() {
|
|
||||||
let heap_value = self.stub[index].clone();
|
|
||||||
|
|
||||||
|
for heap_value in self.stub.iter_from(0) {
|
||||||
stub.push(match heap_value {
|
stub.push(match heap_value {
|
||||||
HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff),
|
HeapCellValue::Addr(ref addr) => HeapCellValue::Addr(addr.clone() - diff),
|
||||||
_ => heap_value,
|
HeapCellValue::PartialString(ref pstr) => {
|
||||||
|
let mut new_pstr = pstr.clone();
|
||||||
|
new_pstr.tail = pstr.tail.clone() - diff;
|
||||||
|
HeapCellValue::PartialString(new_pstr)
|
||||||
|
}
|
||||||
|
heap_value => heap_value.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
stub
|
stub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +98,7 @@ impl<'a> IndexMut<usize> for CopyTerm<'a> {
|
|||||||
// the ordinary, heap term copier, used by duplicate_term.
|
// the ordinary, heap term copier, used by duplicate_term.
|
||||||
impl<'a> CopierTarget for CopyTerm<'a> {
|
impl<'a> CopierTarget for CopyTerm<'a> {
|
||||||
fn threshold(&self) -> usize {
|
fn threshold(&self) -> usize {
|
||||||
self.state.heap.h
|
self.state.heap.h()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, hcv: HeapCellValue) {
|
fn push(&mut self, hcv: HeapCellValue) {
|
||||||
@@ -108,27 +113,28 @@ impl<'a> CopierTarget for CopyTerm<'a> {
|
|||||||
self.state.deref(a)
|
self.state.deref(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stack(&mut self) -> &mut AndStack {
|
fn stack(&mut self) -> &mut Stack {
|
||||||
&mut self.state.and_stack
|
&mut self.state.stack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct CopyBallTerm<'a> {
|
pub(super) struct CopyBallTerm<'a> {
|
||||||
and_stack: &'a mut AndStack,
|
stack: &'a mut Stack,
|
||||||
heap: &'a mut Heap,
|
heap: &'a mut Heap,
|
||||||
heap_boundary: usize,
|
heap_boundary: usize,
|
||||||
stub: &'a mut MachineStub,
|
stub: &'a mut Heap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CopyBallTerm<'a> {
|
impl<'a> CopyBallTerm<'a> {
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
and_stack: &'a mut AndStack,
|
stack: &'a mut Stack,
|
||||||
heap: &'a mut Heap,
|
heap: &'a mut Heap,
|
||||||
stub: &'a mut MachineStub,
|
stub: &'a mut Heap,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let hb = heap.len();
|
let hb = heap.h();
|
||||||
|
|
||||||
CopyBallTerm {
|
CopyBallTerm {
|
||||||
and_stack,
|
stack,
|
||||||
heap,
|
heap,
|
||||||
heap_boundary: hb,
|
heap_boundary: hb,
|
||||||
stub,
|
stub,
|
||||||
@@ -163,7 +169,7 @@ impl<'a> IndexMut<usize> for CopyBallTerm<'a> {
|
|||||||
// the ordinary, heap term copier, used by duplicate_term.
|
// the ordinary, heap term copier, used by duplicate_term.
|
||||||
impl<'a> CopierTarget for CopyBallTerm<'a> {
|
impl<'a> CopierTarget for CopyBallTerm<'a> {
|
||||||
fn threshold(&self) -> usize {
|
fn threshold(&self) -> usize {
|
||||||
self.heap_boundary + self.stub.len()
|
self.heap_boundary + self.stub.h()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, value: HeapCellValue) {
|
fn push(&mut self, value: HeapCellValue) {
|
||||||
@@ -179,7 +185,7 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
|
|||||||
let index = h - self.heap_boundary;
|
let index = h - self.heap_boundary;
|
||||||
self.stub[index].as_addr(h)
|
self.stub[index].as_addr(h)
|
||||||
}
|
}
|
||||||
Addr::StackCell(fr, sc) => self.and_stack[fr][sc].clone(),
|
Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc].clone(),
|
||||||
addr => addr,
|
addr => addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,8 +203,8 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stack(&mut self) -> &mut AndStack {
|
fn stack(&mut self) -> &mut Stack {
|
||||||
self.and_stack
|
self.stack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +216,7 @@ impl Index<RegType> for MachineState {
|
|||||||
RegType::Temp(temp) => &self.registers[temp],
|
RegType::Temp(temp) => &self.registers[temp],
|
||||||
RegType::Perm(perm) => {
|
RegType::Perm(perm) => {
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
&self.and_stack[e][perm]
|
&self.stack.index_and_frame(e)[perm]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +228,7 @@ impl IndexMut<RegType> for MachineState {
|
|||||||
RegType::Temp(temp) => &mut self.registers[temp],
|
RegType::Temp(temp) => &mut self.registers[temp],
|
||||||
RegType::Perm(perm) => {
|
RegType::Perm(perm) => {
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
&mut self.and_stack[e][perm]
|
&mut self.stack.index_and_frame_mut(e)[perm]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,90 +254,74 @@ pub struct MachineState {
|
|||||||
pub(super) fail: bool,
|
pub(super) fail: bool,
|
||||||
pub(crate) heap: Heap,
|
pub(crate) heap: Heap,
|
||||||
pub(super) mode: MachineMode,
|
pub(super) mode: MachineMode,
|
||||||
pub(crate) and_stack: AndStack,
|
pub(crate) stack: Stack,
|
||||||
pub(super) or_stack: OrStack,
|
|
||||||
pub(super) registers: Registers,
|
pub(super) registers: Registers,
|
||||||
pub(super) trail: Vec<TrailRef>,
|
pub(super) trail: Vec<TrailRef>,
|
||||||
pub(super) pstr_trail: Vec<(usize, StringList, usize)>, // b, String, trunc_pt
|
|
||||||
pub(super) pstr_tr: usize,
|
|
||||||
pub(super) tr: usize,
|
pub(super) tr: usize,
|
||||||
pub(super) hb: usize,
|
pub(super) hb: usize,
|
||||||
pub(super) block: usize, // an offset into the OR stack.
|
pub(super) block: usize, // an offset into the OR stack.
|
||||||
pub(super) ball: Ball,
|
pub(super) ball: Ball,
|
||||||
pub(super) lifted_heap: Vec<HeapCellValue>,
|
pub(super) lifted_heap: Heap,
|
||||||
pub(super) interms: Vec<Number>, // intermediate numbers.
|
pub(super) interms: Vec<Number>, // intermediate numbers.
|
||||||
pub(super) last_call: bool,
|
pub(super) last_call: bool,
|
||||||
pub(crate) heap_locs: HeapVarDict,
|
pub(crate) heap_locs: HeapVarDict,
|
||||||
pub(crate) flags: MachineFlags,
|
pub(crate) flags: MachineFlags,
|
||||||
|
pub(crate) at_end_of_expansion: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
pub(super) fn try_char_list(&self, addrs: Vec<Addr>) -> Result<String, MachineError> {
|
pub(super)
|
||||||
|
fn try_char_list(&self, addrs: Vec<Addr>) -> Result<String, MachineError> {
|
||||||
let mut chars = String::new();
|
let mut chars = String::new();
|
||||||
let mut iter = addrs.iter();
|
let mut iter = addrs.iter();
|
||||||
|
|
||||||
while let Some(addr) = iter.next() {
|
while let Some(addr) = iter.next() {
|
||||||
match addr {
|
match addr {
|
||||||
&Addr::Con(Constant::String(ref s)) if self.flags.double_quotes.is_chars() => {
|
&Addr::Con(Constant::String(n, ref s))
|
||||||
chars += s.borrow().as_str();
|
if self.flags.double_quotes.is_chars() => {
|
||||||
|
if s.len() < n {
|
||||||
|
chars += &s[n ..];
|
||||||
|
}
|
||||||
|
|
||||||
if iter.next().is_some() {
|
if iter.next().is_some() {
|
||||||
return Err(MachineError::type_error(ValidType::Character, addr.clone()));
|
return Err(MachineError::type_error(ValidType::Character, addr.clone()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
&Addr::Con(Constant::Char(c)) => {
|
||||||
|
chars.push(c);
|
||||||
}
|
}
|
||||||
&Addr::Con(Constant::Char(c)) => chars.push(c),
|
&Addr::Con(Constant::Atom(ref name, _))
|
||||||
&Addr::Con(Constant::Atom(ref name, _)) if name.as_str().len() == 1 => {
|
if name.as_str().len() == 1 => {
|
||||||
chars += name.as_str();
|
chars += name.as_str();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(
|
||||||
|
MachineError::type_error(ValidType::Character, addr.clone())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => return Err(MachineError::type_error(ValidType::Character, addr.clone())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(chars)
|
Ok(chars)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn try_code_list(&self, addrs: Vec<Addr>) -> Result<Vec<u8>, MachineError> {
|
pub(super)
|
||||||
let mut codes = vec![];
|
fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) {
|
||||||
let mut iter = addrs.iter();
|
|
||||||
|
|
||||||
while let Some(addr) = iter.next() {
|
|
||||||
match addr {
|
|
||||||
&Addr::Con(Constant::String(ref s)) if self.flags.double_quotes.is_codes() => {
|
|
||||||
codes.extend(s.borrow().chars().map(|c| c as u8));
|
|
||||||
|
|
||||||
if iter.next().is_some() {
|
|
||||||
return Err(MachineError::representation_error(RepFlag::CharacterCode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&Addr::Con(Constant::CharCode(c)) => codes.push(c),
|
|
||||||
&Addr::Con(Constant::Integer(ref n)) => {
|
|
||||||
if let Some(c) = n.to_u8() {
|
|
||||||
codes.push(c);
|
|
||||||
} else {
|
|
||||||
return Err(MachineError::representation_error(RepFlag::CharacterCode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return Err(MachineError::representation_error(RepFlag::CharacterCode)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(codes)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn call_at_index(&mut self, arity: usize, p: usize) {
|
|
||||||
self.cp.assign_if_local(self.p.clone() + 1);
|
self.cp.assign_if_local(self.p.clone() + 1);
|
||||||
self.num_of_args = arity;
|
self.num_of_args = arity;
|
||||||
self.b0 = self.b;
|
self.b0 = self.b;
|
||||||
self.p = dir_entry!(p);
|
self.p = CodePtr::Local(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn execute_at_index(&mut self, arity: usize, p: usize) {
|
pub(super)
|
||||||
|
fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) {
|
||||||
self.num_of_args = arity;
|
self.num_of_args = arity;
|
||||||
self.b0 = self.b;
|
self.b0 = self.b;
|
||||||
self.p = dir_entry!(p);
|
self.p = CodePtr::Local(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn module_lookup(
|
pub(super)
|
||||||
|
fn module_lookup(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &IndexStore,
|
indices: &IndexStore,
|
||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
@@ -344,9 +334,9 @@ impl MachineState {
|
|||||||
match idx.0.borrow().0 {
|
match idx.0.borrow().0 {
|
||||||
IndexPtr::Index(compiled_tl_index) => {
|
IndexPtr::Index(compiled_tl_index) => {
|
||||||
if last_call {
|
if last_call {
|
||||||
self.execute_at_index(arity, compiled_tl_index);
|
self.execute_at_index(arity, dir_entry!(compiled_tl_index));
|
||||||
} else {
|
} else {
|
||||||
self.call_at_index(arity, compiled_tl_index);
|
self.call_at_index(arity, dir_entry!(compiled_tl_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -355,11 +345,38 @@ impl MachineState {
|
|||||||
self.fail = true;
|
self.fail = true;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
IndexPtr::UserTermExpansion => {
|
||||||
|
if last_call {
|
||||||
|
self.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0));
|
||||||
|
} else {
|
||||||
|
self.call_at_index(arity, LocalCodePtr::UserTermExpansion(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
IndexPtr::UserGoalExpansion => {
|
||||||
|
if last_call {
|
||||||
|
self.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
|
||||||
|
} else {
|
||||||
|
self.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
IndexPtr::InSituDirEntry(p) => {
|
||||||
|
if last_call {
|
||||||
|
self.execute_at_index(arity, LocalCodePtr::InSituDirEntry(p));
|
||||||
|
} else {
|
||||||
|
self.call_at_index(arity, LocalCodePtr::InSituDirEntry(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let h = self.heap.h;
|
let h = self.heap.h();
|
||||||
let stub = MachineError::functor_stub(name.clone(), arity);
|
let stub = MachineError::functor_stub(name.clone(), arity);
|
||||||
let err = MachineError::module_resolution_error(h, module_name, name, arity);
|
let err = MachineError::module_resolution_error(h, module_name, name, arity);
|
||||||
|
|
||||||
@@ -367,19 +384,21 @@ 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<usize>
|
||||||
|
{
|
||||||
match indices.in_situ_code_dir.get(&(name.clone(), arity)) {
|
match indices.in_situ_code_dir.get(&(name.clone(), arity)) {
|
||||||
Some(p) => Some(*p),
|
Some(p) => Some(*p),
|
||||||
None => match indices.code_dir.get(&(name, arity)) {
|
None =>
|
||||||
Some(ref idx) => {
|
match indices.code_dir.get(&(name, arity)) {
|
||||||
if let &IndexPtr::Index(p) = &idx.0.borrow().0 {
|
Some(ref idx) => {
|
||||||
Some(p)
|
if let IndexPtr::Index(p) = idx.0.borrow().0 {
|
||||||
} else {
|
Some(p)
|
||||||
None
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
_ => None,
|
||||||
_ => None,
|
},
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,16 +411,16 @@ fn try_in_situ(
|
|||||||
) -> CallResult {
|
) -> CallResult {
|
||||||
if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) {
|
if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) {
|
||||||
if last_call {
|
if last_call {
|
||||||
machine_st.execute_at_index(arity, p);
|
machine_st.execute_at_index(arity, LocalCodePtr::DirEntry(p));
|
||||||
} else {
|
} else {
|
||||||
machine_st.call_at_index(arity, p);
|
machine_st.call_at_index(arity, LocalCodePtr::DirEntry(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_st.p = in_situ_dir_entry!(p);
|
machine_st.p = in_situ_dir_entry!(p);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let stub = MachineError::functor_stub(name.clone(), arity);
|
let stub = MachineError::functor_stub(name.clone(), arity);
|
||||||
let h = machine_st.heap.h;
|
let h = machine_st.heap.h();
|
||||||
let key = ExistenceError::Procedure(name, arity);
|
let key = ExistenceError::Procedure(name, arity);
|
||||||
|
|
||||||
Err(machine_st.error_form(MachineError::existence_error(h, key), stub))
|
Err(machine_st.error_form(MachineError::existence_error(h, key), stub))
|
||||||
@@ -412,186 +431,155 @@ pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
|
|||||||
|
|
||||||
pub(crate) trait CallPolicy: Any {
|
pub(crate) trait CallPolicy: Any {
|
||||||
fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
|
fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
|
||||||
let b = machine_st.b - 1;
|
let b = machine_st.b;
|
||||||
let n = machine_st.or_stack[b].num_args();
|
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
|
||||||
|
|
||||||
for i in 1..n + 1 {
|
for i in 1 .. n + 1 {
|
||||||
machine_st.registers[i] = machine_st.or_stack[b][i].clone();
|
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_st.num_of_args = n;
|
machine_st.num_of_args = n;
|
||||||
machine_st.e = machine_st.or_stack[b].e;
|
machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
|
||||||
machine_st.cp = machine_st.or_stack[b].cp.clone();
|
machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
|
||||||
|
|
||||||
machine_st.pop_stack_frames();
|
machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + offset;
|
||||||
|
|
||||||
machine_st.or_stack[b].bp = machine_st.p.clone() + offset;
|
|
||||||
|
|
||||||
let old_tr = machine_st.or_stack[b].tr;
|
let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||||
let curr_tr = machine_st.tr;
|
let curr_tr = machine_st.tr;
|
||||||
|
|
||||||
machine_st.unwind_trail(old_tr, curr_tr);
|
machine_st.unwind_trail(old_tr, curr_tr);
|
||||||
machine_st.tr = machine_st.or_stack[b].tr;
|
machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||||
|
|
||||||
machine_st.trail.truncate(machine_st.tr);
|
machine_st.trail.truncate(machine_st.tr);
|
||||||
|
machine_st.heap.truncate(machine_st.stack.index_or_frame(b).prelude.h);
|
||||||
|
|
||||||
let old_pstr_tr = machine_st.or_stack[b].pstr_tr;
|
let attr_var_init_queue_b =
|
||||||
let curr_pstr_tr = machine_st.pstr_tr;
|
machine_st.stack.index_or_frame(b).prelude.attr_var_init_queue_b;
|
||||||
|
let attr_var_init_bindings_b =
|
||||||
|
machine_st.stack.index_or_frame(b).prelude.attr_var_init_bindings_b;
|
||||||
|
|
||||||
machine_st.unwind_pstr_trail(old_pstr_tr, curr_pstr_tr);
|
machine_st.attr_var_init.backtrack(
|
||||||
machine_st.pstr_tr = machine_st.or_stack[b].pstr_tr;
|
attr_var_init_queue_b,
|
||||||
|
attr_var_init_bindings_b,
|
||||||
|
);
|
||||||
|
|
||||||
machine_st.pstr_trail.truncate(machine_st.pstr_tr);
|
machine_st.hb = machine_st.heap.h();
|
||||||
|
|
||||||
machine_st.heap.truncate(machine_st.or_stack[b].h);
|
|
||||||
|
|
||||||
let attr_var_init_b = machine_st.or_stack[b].attr_var_init_b;
|
|
||||||
machine_st
|
|
||||||
.attr_var_init
|
|
||||||
.attr_var_queue
|
|
||||||
.truncate(attr_var_init_b);
|
|
||||||
|
|
||||||
machine_st.hb = machine_st.heap.h;
|
|
||||||
machine_st.p += 1;
|
machine_st.p += 1;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
|
fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
|
||||||
let b = machine_st.b - 1;
|
let b = machine_st.b;
|
||||||
let n = machine_st.or_stack[b].num_args();
|
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
|
||||||
|
|
||||||
for i in 1..n + 1 {
|
for i in 1 .. n + 1 {
|
||||||
machine_st.registers[i] = machine_st.or_stack[b][i].clone();
|
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_st.num_of_args = n;
|
machine_st.num_of_args = n;
|
||||||
machine_st.e = machine_st.or_stack[b].e;
|
machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
|
||||||
machine_st.cp = machine_st.or_stack[b].cp.clone();
|
machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
|
||||||
|
|
||||||
machine_st.pop_stack_frames();
|
machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + 1;
|
||||||
|
|
||||||
machine_st.or_stack[b].bp = machine_st.p.clone() + 1;
|
|
||||||
|
|
||||||
let old_tr = machine_st.or_stack[b].tr;
|
let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||||
let curr_tr = machine_st.tr;
|
let curr_tr = machine_st.tr;
|
||||||
|
|
||||||
machine_st.unwind_trail(old_tr, curr_tr);
|
machine_st.unwind_trail(old_tr, curr_tr);
|
||||||
machine_st.tr = machine_st.or_stack[b].tr;
|
machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||||
|
|
||||||
machine_st.trail.truncate(machine_st.tr);
|
machine_st.trail.truncate(machine_st.tr);
|
||||||
|
machine_st.heap.truncate(machine_st.stack.index_or_frame(b).prelude.h);
|
||||||
|
|
||||||
let old_pstr_tr = machine_st.or_stack[b].pstr_tr;
|
let attr_var_init_queue_b =
|
||||||
let curr_pstr_tr = machine_st.pstr_tr;
|
machine_st.stack.index_or_frame(b).prelude.attr_var_init_queue_b;
|
||||||
|
let attr_var_init_bindings_b =
|
||||||
|
machine_st.stack.index_or_frame(b).prelude.attr_var_init_bindings_b;
|
||||||
|
|
||||||
machine_st.unwind_pstr_trail(old_pstr_tr, curr_pstr_tr);
|
machine_st.attr_var_init.backtrack(attr_var_init_queue_b, attr_var_init_bindings_b);
|
||||||
machine_st.pstr_tr = machine_st.or_stack[b].pstr_tr;
|
|
||||||
|
|
||||||
machine_st.pstr_trail.truncate(machine_st.pstr_tr);
|
machine_st.hb = machine_st.heap.h();
|
||||||
|
|
||||||
machine_st.heap.truncate(machine_st.or_stack[b].h);
|
|
||||||
|
|
||||||
let attr_var_init_b = machine_st.or_stack[b].attr_var_init_b;
|
|
||||||
machine_st
|
|
||||||
.attr_var_init
|
|
||||||
.attr_var_queue
|
|
||||||
.truncate(attr_var_init_b);
|
|
||||||
|
|
||||||
machine_st.hb = machine_st.heap.h;
|
|
||||||
machine_st.p += offset;
|
machine_st.p += offset;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
|
fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult {
|
||||||
let b = machine_st.b - 1;
|
let b = machine_st.b;
|
||||||
let n = machine_st.or_stack[b].num_args();
|
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
|
||||||
|
|
||||||
for i in 1..n + 1 {
|
for i in 1 .. n + 1 {
|
||||||
machine_st.registers[i] = machine_st.or_stack[b][i].clone();
|
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_st.num_of_args = n;
|
machine_st.num_of_args = n;
|
||||||
machine_st.e = machine_st.or_stack[b].e;
|
machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
|
||||||
machine_st.cp = machine_st.or_stack[b].cp.clone();
|
machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
|
||||||
|
|
||||||
let old_tr = machine_st.or_stack[b].tr;
|
let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||||
let curr_tr = machine_st.tr;
|
let curr_tr = machine_st.tr;
|
||||||
|
|
||||||
machine_st.unwind_trail(old_tr, curr_tr);
|
machine_st.unwind_trail(old_tr, curr_tr);
|
||||||
machine_st.tr = machine_st.or_stack[b].tr;
|
machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||||
|
|
||||||
machine_st.trail.truncate(machine_st.tr);
|
machine_st.trail.truncate(machine_st.tr);
|
||||||
|
machine_st.heap.truncate(machine_st.stack.index_or_frame(b).prelude.h);
|
||||||
|
|
||||||
let old_pstr_tr = machine_st.or_stack[b].pstr_tr;
|
let attr_var_init_queue_b =
|
||||||
let curr_pstr_tr = machine_st.pstr_tr;
|
machine_st.stack.index_or_frame(b).prelude.attr_var_init_queue_b;
|
||||||
|
let attr_var_init_bindings_b =
|
||||||
|
machine_st.stack.index_or_frame(b).prelude.attr_var_init_bindings_b;
|
||||||
|
|
||||||
machine_st.unwind_pstr_trail(old_pstr_tr, curr_pstr_tr);
|
machine_st.attr_var_init.backtrack(
|
||||||
machine_st.pstr_tr = machine_st.or_stack[b].pstr_tr;
|
attr_var_init_queue_b,
|
||||||
|
attr_var_init_bindings_b,
|
||||||
|
);
|
||||||
|
|
||||||
machine_st.pstr_trail.truncate(machine_st.pstr_tr);
|
machine_st.stack.truncate(machine_st.b);
|
||||||
|
machine_st.b = machine_st.stack.index_or_frame(b).prelude.b;
|
||||||
|
|
||||||
machine_st.heap.truncate(machine_st.or_stack[b].h);
|
machine_st.hb = machine_st.heap.h();
|
||||||
|
|
||||||
let attr_var_init_b = machine_st.or_stack[b].attr_var_init_b;
|
|
||||||
machine_st
|
|
||||||
.attr_var_init
|
|
||||||
.attr_var_queue
|
|
||||||
.truncate(attr_var_init_b);
|
|
||||||
|
|
||||||
machine_st.b = machine_st.or_stack[b].b;
|
|
||||||
machine_st.or_stack.truncate(machine_st.b);
|
|
||||||
|
|
||||||
machine_st.pop_stack_frames();
|
|
||||||
|
|
||||||
machine_st.hb = machine_st.heap.h;
|
|
||||||
machine_st.p += offset;
|
machine_st.p += offset;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult {
|
fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult {
|
||||||
let b = machine_st.b - 1;
|
let b = machine_st.b;
|
||||||
let n = machine_st.or_stack[b].num_args();
|
let n = machine_st.stack.index_or_frame(b).prelude.univ_prelude.num_cells;
|
||||||
|
|
||||||
for i in 1..n + 1 {
|
for i in 1 .. n + 1 {
|
||||||
machine_st.registers[i] = machine_st.or_stack[b][i].clone();
|
machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i-1].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_st.num_of_args = n;
|
machine_st.num_of_args = n;
|
||||||
machine_st.e = machine_st.or_stack[b].e;
|
machine_st.e = machine_st.stack.index_or_frame(b).prelude.e;
|
||||||
machine_st.cp = machine_st.or_stack[b].cp.clone();
|
machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp;
|
||||||
|
|
||||||
let old_tr = machine_st.or_stack[b].tr;
|
let old_tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||||
let curr_tr = machine_st.tr;
|
let curr_tr = machine_st.tr;
|
||||||
|
|
||||||
machine_st.unwind_trail(old_tr, curr_tr);
|
machine_st.unwind_trail(old_tr, curr_tr);
|
||||||
machine_st.tr = machine_st.or_stack[b].tr;
|
machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr;
|
||||||
|
|
||||||
machine_st.trail.truncate(machine_st.tr);
|
machine_st.trail.truncate(machine_st.tr);
|
||||||
|
machine_st.heap.truncate(machine_st.stack.index_or_frame(b).prelude.h);
|
||||||
|
|
||||||
let old_pstr_tr = machine_st.or_stack[b].pstr_tr;
|
let attr_var_init_queue_b =
|
||||||
let curr_pstr_tr = machine_st.pstr_tr;
|
machine_st.stack.index_or_frame(b).prelude.attr_var_init_queue_b;
|
||||||
|
let attr_var_init_bindings_b =
|
||||||
|
machine_st.stack.index_or_frame(b).prelude.attr_var_init_bindings_b;
|
||||||
|
|
||||||
machine_st.unwind_pstr_trail(old_pstr_tr, curr_pstr_tr);
|
machine_st.attr_var_init.backtrack(
|
||||||
machine_st.pstr_tr = machine_st.or_stack[b].pstr_tr;
|
attr_var_init_queue_b,
|
||||||
|
attr_var_init_bindings_b,
|
||||||
|
);
|
||||||
|
|
||||||
machine_st.pstr_trail.truncate(machine_st.pstr_tr);
|
machine_st.stack.truncate(machine_st.b);
|
||||||
|
machine_st.b = machine_st.stack.index_or_frame(b).prelude.b;
|
||||||
|
|
||||||
machine_st.heap.truncate(machine_st.or_stack[b].h);
|
machine_st.hb = machine_st.heap.h();
|
||||||
|
|
||||||
let attr_var_init_b = machine_st.or_stack[b].attr_var_init_b;
|
|
||||||
machine_st
|
|
||||||
.attr_var_init
|
|
||||||
.attr_var_queue
|
|
||||||
.truncate(attr_var_init_b);
|
|
||||||
|
|
||||||
machine_st.b = machine_st.or_stack[b].b;
|
|
||||||
machine_st.or_stack.truncate(machine_st.b);
|
|
||||||
|
|
||||||
machine_st.pop_stack_frames();
|
|
||||||
|
|
||||||
machine_st.hb = machine_st.heap.h;
|
|
||||||
machine_st.p += 1;
|
machine_st.p += 1;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -621,12 +609,23 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
indices: &IndexStore,
|
indices: &IndexStore,
|
||||||
) -> CallResult {
|
) -> CallResult {
|
||||||
match idx.0.borrow().0 {
|
match idx.0.borrow().0 {
|
||||||
IndexPtr::DynamicUndefined =>
|
IndexPtr::DynamicUndefined => {
|
||||||
machine_st.fail = true,
|
machine_st.fail = true;
|
||||||
IndexPtr::Undefined =>
|
}
|
||||||
return try_in_situ(machine_st, name, arity, indices, false),
|
IndexPtr::Undefined => {
|
||||||
|
return try_in_situ(machine_st, name, arity, indices, false);
|
||||||
|
}
|
||||||
IndexPtr::Index(compiled_tl_index) => {
|
IndexPtr::Index(compiled_tl_index) => {
|
||||||
machine_st.call_at_index(arity, compiled_tl_index)
|
machine_st.call_at_index(arity, LocalCodePtr::DirEntry(compiled_tl_index))
|
||||||
|
}
|
||||||
|
IndexPtr::UserTermExpansion => {
|
||||||
|
machine_st.call_at_index(arity, LocalCodePtr::UserTermExpansion(0));
|
||||||
|
}
|
||||||
|
IndexPtr::UserGoalExpansion => {
|
||||||
|
machine_st.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
|
||||||
|
}
|
||||||
|
IndexPtr::InSituDirEntry(p) => {
|
||||||
|
machine_st.call_at_index(arity, LocalCodePtr::InSituDirEntry(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,7 +646,16 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
IndexPtr::Undefined =>
|
IndexPtr::Undefined =>
|
||||||
return try_in_situ(machine_st, name, arity, indices, true),
|
return try_in_situ(machine_st, name, arity, indices, true),
|
||||||
IndexPtr::Index(compiled_tl_index) => {
|
IndexPtr::Index(compiled_tl_index) => {
|
||||||
machine_st.execute_at_index(arity, compiled_tl_index)
|
machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
|
||||||
|
}
|
||||||
|
IndexPtr::UserTermExpansion => {
|
||||||
|
machine_st.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0));
|
||||||
|
}
|
||||||
|
IndexPtr::UserGoalExpansion => {
|
||||||
|
machine_st.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
|
||||||
|
}
|
||||||
|
IndexPtr::InSituDirEntry(p) => {
|
||||||
|
machine_st.execute_at_index(arity, LocalCodePtr::InSituDirEntry(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,7 +725,7 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
machine_st.unify(addr, Addr::HeapCell(offset.heap_loc));
|
machine_st.unify(addr, Addr::HeapCell(offset.heap_loc));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let h = machine_st.heap.h;
|
let h = machine_st.heap.h();
|
||||||
let stub = MachineError::functor_stub(clause_name!("read"), 1);
|
let stub = MachineError::functor_stub(clause_name!("read"), 1);
|
||||||
let err = MachineError::syntax_error(h, e);
|
let err = MachineError::syntax_error(h, e);
|
||||||
let err = machine_st.error_form(err, stub);
|
let err = machine_st.error_form(err, stub);
|
||||||
@@ -729,7 +737,7 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
return_from_clause!(machine_st.last_call, machine_st)
|
return_from_clause!(machine_st.last_call, machine_st)
|
||||||
}
|
}
|
||||||
&BuiltInClauseType::CopyTerm => {
|
&BuiltInClauseType::CopyTerm => {
|
||||||
machine_st.copy_term();
|
machine_st.copy_term(AttrVarPolicy::DeepCopy);
|
||||||
return_from_clause!(machine_st.last_call, machine_st)
|
return_from_clause!(machine_st.last_call, machine_st)
|
||||||
}
|
}
|
||||||
&BuiltInClauseType::Eq => {
|
&BuiltInClauseType::Eq => {
|
||||||
@@ -759,15 +767,6 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
|
|
||||||
return_from_clause!(machine_st.last_call, machine_st)
|
return_from_clause!(machine_st.last_call, machine_st)
|
||||||
}
|
}
|
||||||
&BuiltInClauseType::PartialString => {
|
|
||||||
let s = machine_st.try_string_list(temp_v!(1))?;
|
|
||||||
let a2 = machine_st[temp_v!(2)].clone();
|
|
||||||
|
|
||||||
s.set_expandable(true);
|
|
||||||
machine_st.write_constant_to_var(a2, Constant::String(s));
|
|
||||||
|
|
||||||
return_from_clause!(machine_st.last_call, machine_st)
|
|
||||||
}
|
|
||||||
&BuiltInClauseType::Sort => {
|
&BuiltInClauseType::Sort => {
|
||||||
machine_st.check_sort_errors()?;
|
machine_st.check_sort_errors()?;
|
||||||
|
|
||||||
@@ -847,6 +846,10 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
) -> CallResult {
|
) -> CallResult {
|
||||||
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
||||||
match ClauseType::from(name.clone(), arity, None) {
|
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)?;
|
||||||
|
}
|
||||||
ClauseType::CallN => {
|
ClauseType::CallN => {
|
||||||
machine_st.handle_internal_call_n(arity);
|
machine_st.handle_internal_call_n(arity);
|
||||||
|
|
||||||
@@ -854,11 +857,7 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
machine_st.p = CodePtr::CallN(arity, machine_st.p.local());
|
machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call);
|
||||||
}
|
|
||||||
ClauseType::BuiltIn(built_in) => {
|
|
||||||
machine_st.setup_built_in_call(built_in.clone());
|
|
||||||
self.call_builtin(machine_st, &built_in, indices, parsing_stream)?;
|
|
||||||
}
|
}
|
||||||
ClauseType::Inlined(inlined) => {
|
ClauseType::Inlined(inlined) => {
|
||||||
machine_st.execute_inlined(&inlined);
|
machine_st.execute_inlined(&inlined);
|
||||||
@@ -873,13 +872,7 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
if let Some(idx) = indices.get_code_index((name.clone(), arity), module) {
|
if let Some(idx) = indices.get_code_index((name.clone(), arity), module) {
|
||||||
self.context_call(machine_st, name, arity, idx, indices)?;
|
self.context_call(machine_st, name, arity, idx, indices)?;
|
||||||
} else {
|
} else {
|
||||||
let h = machine_st.heap.h;
|
try_in_situ(machine_st, name, arity, indices, machine_st.last_call)?;
|
||||||
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
|
|
||||||
let key = ExistenceError::Procedure(name, arity);
|
|
||||||
|
|
||||||
return Err(
|
|
||||||
machine_st.error_form(MachineError::existence_error(h, key), stub)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClauseType::Hook(_) | ClauseType::System(_) => {
|
ClauseType::Hook(_) | ClauseType::System(_) => {
|
||||||
@@ -887,7 +880,7 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
|
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
|
||||||
|
|
||||||
return Err(machine_st
|
return Err(machine_st
|
||||||
.error_form(MachineError::type_error(ValidType::Callable, name), stub));
|
.error_form(MachineError::type_error(ValidType::Callable, name), stub));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -983,7 +976,7 @@ impl CWILCallPolicy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn increment(&mut self, machine_st: &MachineState) -> CallResult {
|
fn increment(&mut self, machine_st: &MachineState) -> CallResult {
|
||||||
if self.inference_limit_exceeded || machine_st.ball.stub.len() > 0 {
|
if self.inference_limit_exceeded || machine_st.ball.stub.h() > 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1045,17 +1038,18 @@ 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;
|
let b = machine_st.b;
|
||||||
|
|
||||||
if let Addr::Con(Constant::Usize(b0)) = addr {
|
match addr {
|
||||||
if b > b0 {
|
Addr::Con(Constant::CutPoint(b0)) | Addr::Con(Constant::Usize(b0)) => {
|
||||||
machine_st.b = b0;
|
if b > b0 {
|
||||||
machine_st.tidy_trail();
|
machine_st.b = b0;
|
||||||
machine_st.tidy_pstr_trail();
|
machine_st.tidy_trail();
|
||||||
machine_st.or_stack.truncate(machine_st.b);
|
}
|
||||||
}
|
}
|
||||||
} else {
|
_ => {
|
||||||
machine_st.fail = true;
|
machine_st.fail = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@@ -1106,10 +1100,10 @@ impl SCCCutPolicy {
|
|||||||
if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() {
|
if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() {
|
||||||
if machine_st.b < b_cutoff {
|
if machine_st.b < b_cutoff {
|
||||||
let (idx, arity) = if machine_st.block < prev_block {
|
let (idx, arity) = if machine_st.block < prev_block {
|
||||||
(self.r_c_w_h, 0)
|
(dir_entry!(self.r_c_w_h), 0)
|
||||||
} else {
|
} else {
|
||||||
machine_st[temp_v!(1)] = Addr::Con(Constant::Usize(b_cutoff));
|
machine_st[temp_v!(1)] = Addr::Con(Constant::Usize(b_cutoff));
|
||||||
(self.r_c_wo_h, 1)
|
(dir_entry!(self.r_c_wo_h), 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
if machine_st.last_call {
|
if machine_st.last_call {
|
||||||
@@ -1130,16 +1124,17 @@ impl CutPolicy for SCCCutPolicy {
|
|||||||
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
|
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
|
||||||
let b = machine_st.b;
|
let b = machine_st.b;
|
||||||
|
|
||||||
if let Addr::Con(Constant::Usize(b0)) = machine_st[r].clone() {
|
match machine_st[r].clone() {
|
||||||
if b > b0 {
|
Addr::Con(Constant::Usize(b0)) | Addr::Con(Constant::CutPoint(b0)) => {
|
||||||
machine_st.b = b0;
|
if b > b0 {
|
||||||
machine_st.tidy_trail();
|
machine_st.b = b0;
|
||||||
machine_st.tidy_pstr_trail();
|
machine_st.tidy_trail();
|
||||||
machine_st.or_stack.truncate(machine_st.b);
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
machine_st.fail = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
machine_st.fail = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.run_cleaners(machine_st)
|
self.run_cleaners(machine_st)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,12 +5,12 @@ use crate::prolog::clause_types::*;
|
|||||||
use crate::prolog::forms::*;
|
use crate::prolog::forms::*;
|
||||||
use crate::prolog::heap_print::*;
|
use crate::prolog::heap_print::*;
|
||||||
use crate::prolog::instructions::*;
|
use crate::prolog::instructions::*;
|
||||||
use crate::prolog::machine::heap::Heap;
|
use crate::prolog::machine::heap::*;
|
||||||
use crate::prolog::read::*;
|
use crate::prolog::read::*;
|
||||||
|
|
||||||
mod and_stack;
|
|
||||||
mod attributed_variables;
|
mod attributed_variables;
|
||||||
pub(super) mod code_repo;
|
pub(super) mod code_repo;
|
||||||
|
pub mod code_walker;
|
||||||
pub mod compile;
|
pub mod compile;
|
||||||
mod copier;
|
mod copier;
|
||||||
mod dynamic_database;
|
mod dynamic_database;
|
||||||
@@ -19,7 +19,9 @@ pub mod machine_errors;
|
|||||||
pub mod machine_indices;
|
pub mod machine_indices;
|
||||||
pub(super) mod machine_state;
|
pub(super) mod machine_state;
|
||||||
pub mod modules;
|
pub mod modules;
|
||||||
mod or_stack;
|
mod partial_string;
|
||||||
|
mod raw_block;
|
||||||
|
mod stack;
|
||||||
pub(super) mod term_expansion;
|
pub(super) mod term_expansion;
|
||||||
pub mod toplevel;
|
pub mod toplevel;
|
||||||
|
|
||||||
@@ -34,6 +36,7 @@ use crate::prolog::machine::machine_errors::*;
|
|||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::prolog::machine::machine_indices::*;
|
||||||
use crate::prolog::machine::machine_state::*;
|
use crate::prolog::machine::machine_state::*;
|
||||||
use crate::prolog::machine::modules::*;
|
use crate::prolog::machine::modules::*;
|
||||||
|
use crate::prolog::machine::toplevel::*;
|
||||||
use crate::prolog::read::PrologStream;
|
use crate::prolog::read::PrologStream;
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
@@ -43,6 +46,7 @@ use std::fs::File;
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
@@ -106,13 +110,35 @@ impl SubModuleUser for IndexStore {
|
|||||||
&mut self.op_dir
|
&mut self.op_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_code_index(&self, key: PredicateKey, module: ClauseName) -> Option<CodeIndex> {
|
fn get_code_index(&self, key: PredicateKey, module_name: ClauseName) -> Option<CodeIndex> {
|
||||||
match module.as_str() {
|
match module_name.as_str() {
|
||||||
"user" | "builtin" => self.code_dir.get(&key).cloned(),
|
"user" => {
|
||||||
_ => self
|
self.code_dir.get(&key).cloned()
|
||||||
.modules
|
}
|
||||||
.get(&module)
|
_ => {
|
||||||
.and_then(|ref module| module.code_dir.get(&key).cloned().map(CodeIndex::from)),
|
match self.in_situ_module_dir.get(&module_name) {
|
||||||
|
Some(ref module_stub) => {
|
||||||
|
match module_stub.in_situ_code_dir.get(&key) {
|
||||||
|
Some(p) => {
|
||||||
|
return Some(CodeIndex::new(
|
||||||
|
IndexPtr::InSituDirEntry(*p),
|
||||||
|
module_name.clone()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.modules
|
||||||
|
.get(&module_name)
|
||||||
|
.and_then(|ref module| {
|
||||||
|
module.code_dir.get(&key).cloned()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,33 +157,33 @@ impl SubModuleUser for IndexStore {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.code_dir.insert((name, arity), idx);
|
self.code_dir.insert((name.clone(), arity), idx.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_qualified_module(
|
fn use_qualified_module(
|
||||||
&mut self,
|
&mut self,
|
||||||
code_repo: &mut CodeRepo,
|
code_repo: &mut CodeRepo,
|
||||||
flags: MachineFlags,
|
_: MachineFlags,
|
||||||
submodule: &Module,
|
submodule: &Module,
|
||||||
exports: &Vec<PredicateKey>,
|
exports: &Vec<ModuleExport>,
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
use_qualified_module(self, submodule, exports)?;
|
use_qualified_module(self, submodule, exports)?;
|
||||||
submodule
|
submodule
|
||||||
.dump_expansions(code_repo, flags)
|
.dump_expansions(code_repo)
|
||||||
.map_err(SessionError::from)
|
.map_err(SessionError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_module(
|
fn use_module(
|
||||||
&mut self,
|
&mut self,
|
||||||
code_repo: &mut CodeRepo,
|
code_repo: &mut CodeRepo,
|
||||||
flags: MachineFlags,
|
_: MachineFlags,
|
||||||
submodule: &Module,
|
submodule: &Module,
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
use_module(self, submodule)?;
|
use_module(self, submodule)?;
|
||||||
|
|
||||||
if !submodule.inserted_expansions {
|
if !submodule.inserted_expansions {
|
||||||
submodule
|
submodule
|
||||||
.dump_expansions(code_repo, flags)
|
.dump_expansions(code_repo)
|
||||||
.map_err(SessionError::from)
|
.map_err(SessionError::from)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -165,14 +191,26 @@ impl SubModuleUser for IndexStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn current_dir() -> std::path::PathBuf {
|
||||||
|
let mut path_buf = std::path::PathBuf::from(file!());
|
||||||
|
path_buf.pop();
|
||||||
|
path_buf
|
||||||
|
}
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
|
include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
|
||||||
|
|
||||||
static TOPLEVEL: &str = include_str!("../toplevel.pl");
|
static TOPLEVEL: &str = include_str!("../toplevel.pl");
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
fn compile_special_forms(&mut self) {
|
fn compile_special_forms(&mut self)
|
||||||
let verify_attrs_src = clause_name!("verify_attrs.pl");
|
{
|
||||||
let project_attrs_src = clause_name!("project_attributes.pl");
|
let current_dir = current_dir();
|
||||||
|
|
||||||
|
let verify_attrs_src = ListingSource::from_file_and_path(
|
||||||
|
clause_name!("attributed_variables.pl"),
|
||||||
|
current_dir.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
match compile_special_form(self, parsing_stream(VERIFY_ATTRS.as_bytes()), verify_attrs_src)
|
match compile_special_form(self, parsing_stream(VERIFY_ATTRS.as_bytes()), verify_attrs_src)
|
||||||
{
|
{
|
||||||
@@ -183,6 +221,11 @@ impl Machine {
|
|||||||
panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"),
|
panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let project_attrs_src = ListingSource::from_file_and_path(
|
||||||
|
clause_name!("project_attributes.pl"),
|
||||||
|
current_dir,
|
||||||
|
);
|
||||||
|
|
||||||
match compile_special_form(self, parsing_stream(PROJECT_ATTRS.as_bytes()), project_attrs_src)
|
match compile_special_form(self, parsing_stream(PROJECT_ATTRS.as_bytes()), project_attrs_src)
|
||||||
{
|
{
|
||||||
Ok(p) => {
|
Ok(p) => {
|
||||||
@@ -196,8 +239,21 @@ impl Machine {
|
|||||||
fn compile_top_level(&mut self) -> Result<(), SessionError>
|
fn compile_top_level(&mut self) -> Result<(), SessionError>
|
||||||
{
|
{
|
||||||
self.toplevel_idx = self.code_repo.code.len();
|
self.toplevel_idx = self.code_repo.code.len();
|
||||||
compile_user_module(self, parsing_stream(TOPLEVEL.as_bytes()),
|
|
||||||
true, clause_name!("toplevel.pl"));
|
let mut current_dir = current_dir();
|
||||||
|
current_dir.pop();
|
||||||
|
|
||||||
|
let top_lvl_src = ListingSource::from_file_and_path(
|
||||||
|
clause_name!("toplevel.pl"),
|
||||||
|
current_dir,
|
||||||
|
);
|
||||||
|
|
||||||
|
compile_user_module(
|
||||||
|
self,
|
||||||
|
parsing_stream(TOPLEVEL.as_bytes()),
|
||||||
|
true,
|
||||||
|
top_lvl_src,
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(module) = self.indices.take_module(clause_name!("$toplevel")) {
|
if let Some(module) = self.indices.take_module(clause_name!("$toplevel")) {
|
||||||
self.indices.use_module(
|
self.indices.use_module(
|
||||||
@@ -226,8 +282,12 @@ impl Machine {
|
|||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
compile_user_module(self, file_src, true,
|
let rc_src = ListingSource::from_file_and_path(
|
||||||
clause_name!("$HOME/.scryerrc"));
|
clause_name!(".scryerrc"),
|
||||||
|
path.to_path_buf(),
|
||||||
|
);
|
||||||
|
|
||||||
|
compile_user_module(self, file_src, true, rc_src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +300,7 @@ impl Machine {
|
|||||||
|
|
||||||
pub fn run_init_code(&mut self, code: Code) -> bool {
|
pub fn run_init_code(&mut self, code: Code) -> bool {
|
||||||
let old_machine_st = self.sink_to_snapshot();
|
let old_machine_st = self.sink_to_snapshot();
|
||||||
self.machine_st.reset();
|
self.machine_st.reset();
|
||||||
|
|
||||||
self.code_repo.cached_query = code;
|
self.code_repo.cached_query = code;
|
||||||
self.run_query();
|
self.run_query();
|
||||||
@@ -272,10 +332,11 @@ impl Machine {
|
|||||||
self.run_query();
|
self.run_query();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(prolog_stream: PrologStream) -> Self {
|
pub fn new(prolog_stream: PrologStream) -> Self
|
||||||
|
{
|
||||||
let mut wam = Machine {
|
let mut wam = Machine {
|
||||||
machine_st: MachineState::new(),
|
machine_st: MachineState::new(),
|
||||||
inner_heap: Heap::with_capacity(256 * 256),
|
inner_heap: Heap::new(),
|
||||||
policies: MachinePolicies::new(),
|
policies: MachinePolicies::new(),
|
||||||
indices: IndexStore::new(),
|
indices: IndexStore::new(),
|
||||||
code_repo: CodeRepo::new(),
|
code_repo: CodeRepo::new(),
|
||||||
@@ -284,25 +345,50 @@ impl Machine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let atom_tbl = wam.indices.atom_tbl.clone();
|
let atom_tbl = wam.indices.atom_tbl.clone();
|
||||||
|
let mut lib_path = current_dir();
|
||||||
|
|
||||||
|
lib_path.pop();
|
||||||
|
lib_path.push("lib");
|
||||||
|
|
||||||
|
wam.indices.add_term_and_goal_expansion_indices();
|
||||||
|
|
||||||
compile_listing(
|
compile_listing(
|
||||||
&mut wam,
|
&mut wam,
|
||||||
parsing_stream(BUILTINS.as_bytes()),
|
parsing_stream(BUILTINS.as_bytes()),
|
||||||
default_index_store!(atom_tbl.clone()),
|
default_index_store!(atom_tbl.clone()),
|
||||||
true,
|
true,
|
||||||
clause_name!("builtins.pl"),
|
ListingSource::from_file_and_path(
|
||||||
|
clause_name!("builtins.pl"),
|
||||||
|
lib_path.clone(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
wam.compile_special_forms();
|
wam.compile_special_forms();
|
||||||
|
|
||||||
compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()), true,
|
compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()), true,
|
||||||
clause_name!("error"));
|
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, parsing_stream(LISTS.as_bytes()), true,
|
||||||
clause_name!("lists"));
|
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, parsing_stream(NON_ISO.as_bytes()), true,
|
||||||
clause_name!("non_iso"));
|
ListingSource::from_file_and_path(
|
||||||
|
clause_name!("non_iso"),
|
||||||
|
lib_path.clone(),
|
||||||
|
)
|
||||||
|
);
|
||||||
compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true,
|
compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true,
|
||||||
clause_name!("si"));
|
ListingSource::from_file_and_path(
|
||||||
|
clause_name!("si"),
|
||||||
|
lib_path.clone(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
if wam.compile_top_level().is_err() {
|
if wam.compile_top_level().is_err() {
|
||||||
panic!("Loading '$toplevel' module failed");
|
panic!("Loading '$toplevel' module failed");
|
||||||
@@ -357,10 +443,10 @@ impl Machine {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_batched_code(&mut self, code: Code, code_dir: CodeDir) {
|
pub(crate) fn add_batched_code_dir(&mut self, code_dir: CodeDir) {
|
||||||
// error detection has finished, so update the master index of keys.
|
// error detection has finished, so update the master index of keys.
|
||||||
for (key, idx) in code_dir {
|
for (key, idx) in code_dir {
|
||||||
if let Some(ref mut master_idx) = self.indices.code_dir.get_mut(&key) {
|
if let Some(ref master_idx) = self.indices.code_dir.get(&key) {
|
||||||
// ensure we don't double borrow if master_idx == idx.
|
// ensure we don't double borrow if master_idx == idx.
|
||||||
// we don't need to modify anything in that case.
|
// we don't need to modify anything in that case.
|
||||||
if !Rc::ptr_eq(&master_idx.0, &idx.0) {
|
if !Rc::ptr_eq(&master_idx.0, &idx.0) {
|
||||||
@@ -372,25 +458,41 @@ impl Machine {
|
|||||||
|
|
||||||
self.indices.code_dir.insert(key, idx);
|
self.indices.code_dir.insert(key, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.code_repo.code.extend(code.into_iter());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn add_batched_ops(&mut self, op_dir: OpDir) {
|
pub(crate) fn add_batched_ops(&mut self, op_dir: OpDir) {
|
||||||
self.indices.op_dir.extend(op_dir.into_iter());
|
self.indices.op_dir.extend(op_dir.into_iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_in_situ_module_dir(&mut self, module_dir: ModuleDir) {
|
||||||
|
for (module_name, module_skeleton) in module_dir {
|
||||||
|
match self.indices.modules.get_mut(&module_name) {
|
||||||
|
Some(ref mut module) => {
|
||||||
|
for (key, idx) in module_skeleton.code_dir {
|
||||||
|
if let Some(existing_idx) = module.code_dir.get(&key) {
|
||||||
|
set_code_index!(existing_idx, idx.0.borrow().0, module_name.clone());
|
||||||
|
} else {
|
||||||
|
module.code_dir.insert(key, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.add_module(module_skeleton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn add_module(&mut self, module: Module, code: Code) {
|
pub fn add_module(&mut self, module: Module) {
|
||||||
self.indices
|
self.indices
|
||||||
.modules
|
.modules
|
||||||
.insert(module.module_decl.name.clone(), module);
|
.insert(module.module_decl.name.clone(), module);
|
||||||
self.code_repo.code.extend(code.into_iter());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
|
fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
|
||||||
let h = self.machine_st.heap.h;
|
let h = self.machine_st.heap.h();
|
||||||
|
|
||||||
let err = MachineError::session_error(h, err);
|
let err = MachineError::session_error(h, err);
|
||||||
let stub = MachineError::functor_stub(key.0, key.1);
|
let stub = MachineError::functor_stub(key.0, key.1);
|
||||||
@@ -400,30 +502,64 @@ impl Machine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_predicate_indicator_list(&mut self) -> Vec<PredicateKey>
|
fn extract_module_export_list(&mut self) -> Result<Vec<ModuleExport>, ParserError>
|
||||||
{
|
{
|
||||||
let export_list = self.machine_st[temp_v!(2)].clone();
|
let mut export_list = self.machine_st[temp_v!(2)].clone();
|
||||||
let mut export_list = self.machine_st.store(self.machine_st.deref(export_list));
|
|
||||||
let mut exports = vec![];
|
let mut exports = vec![];
|
||||||
|
|
||||||
while let Addr::Lis(l) = export_list {
|
while let Addr::Lis(l) = self.machine_st.store(self.machine_st.deref(export_list)) {
|
||||||
match &self.machine_st.heap[l] {
|
match &self.machine_st.heap[l] {
|
||||||
&HeapCellValue::Addr(Addr::Str(s)) => {
|
&HeapCellValue::Addr(Addr::Str(s)) => {
|
||||||
let name = match &self.machine_st.heap[s+1] {
|
match &self.machine_st.heap[s] {
|
||||||
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
|
HeapCellValue::NamedStr(arity, ref name, _)
|
||||||
name.clone(),
|
if *arity == 2 && name.as_str() == "/" => {
|
||||||
_ =>
|
let name = match &self.machine_st.heap[s+1] {
|
||||||
unreachable!()
|
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
|
||||||
};
|
name.clone(),
|
||||||
|
_ =>
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
let arity = match &self.machine_st.heap[s+2] {
|
let arity = match &self.machine_st.heap[s+2] {
|
||||||
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
|
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
|
||||||
arity.to_usize().unwrap(),
|
arity.to_usize().unwrap(),
|
||||||
_ =>
|
_ =>
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.push((name, arity));
|
exports.push(ModuleExport::PredicateKey((name, arity)));
|
||||||
|
}
|
||||||
|
HeapCellValue::NamedStr(arity, ref name, _)
|
||||||
|
if *arity == 3 && name.as_str() == "op" => {
|
||||||
|
let name = match &self.machine_st.heap[s+3] {
|
||||||
|
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
|
||||||
|
name.clone(),
|
||||||
|
_ =>
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let spec = match &self.machine_st.heap[s+2] {
|
||||||
|
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
|
||||||
|
name.clone(),
|
||||||
|
_ =>
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let prec = match &self.machine_st.heap[s+1] {
|
||||||
|
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
|
||||||
|
arity.to_usize().unwrap(),
|
||||||
|
_ =>
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.push(ModuleExport::OpDecl(to_op_decl(
|
||||||
|
prec,
|
||||||
|
spec.as_str(),
|
||||||
|
name,
|
||||||
|
)?));
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
@@ -431,7 +567,7 @@ impl Machine {
|
|||||||
export_list = self.machine_st.heap[l+1].as_addr(l+1);
|
export_list = self.machine_st.heap[l+1].as_addr(l+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
exports
|
Ok(exports)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_module<ToSource>(&mut self, to_src: ToSource)
|
fn use_module<ToSource>(&mut self, to_src: ToSource)
|
||||||
@@ -457,7 +593,7 @@ impl Machine {
|
|||||||
load_library(self, name, false)
|
load_library(self, name, false)
|
||||||
},
|
},
|
||||||
ModuleSource::File(name) =>
|
ModuleSource::File(name) =>
|
||||||
load_module_from_file(self, name.as_str(), false)
|
load_module_from_file(self, PathBuf::from(name.as_str()), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = load_result.and_then(|name| {
|
let result = load_result.and_then(|name| {
|
||||||
@@ -489,7 +625,13 @@ impl Machine {
|
|||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
let exports = self.extract_predicate_indicator_list();
|
let exports = match self.extract_module_export_list() {
|
||||||
|
Ok(exports) => exports,
|
||||||
|
Err(e) => {
|
||||||
|
self.throw_session_error(SessionError::from(e), (clause_name!("use_module"), 2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let load_result = match to_src(name) {
|
let load_result = match to_src(name) {
|
||||||
ModuleSource::Library(name) =>
|
ModuleSource::Library(name) =>
|
||||||
@@ -502,7 +644,7 @@ impl Machine {
|
|||||||
load_library(self, name, false)
|
load_library(self, name, false)
|
||||||
},
|
},
|
||||||
ModuleSource::File(name) =>
|
ModuleSource::File(name) =>
|
||||||
load_module_from_file(self, name.as_str(), false)
|
load_module_from_file(self, PathBuf::from(name.as_str()), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = load_result.and_then(|name| {
|
let result = load_result.and_then(|name| {
|
||||||
@@ -521,14 +663,14 @@ impl Machine {
|
|||||||
self.code_repo.cached_query = cached_query;
|
self.code_repo.cached_query = cached_query;
|
||||||
|
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
self.throw_session_error(e, (clause_name!("use_module"), 1));
|
self.throw_session_error(e, (clause_name!("use_module"), 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
|
fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
|
||||||
match code_ptr {
|
match code_ptr {
|
||||||
REPLCodePtr::CompileBatch => {
|
REPLCodePtr::CompileBatch => {
|
||||||
let user_src = clause_name!("user");
|
let user_src = ListingSource::User;
|
||||||
|
|
||||||
let src = readline::input_stream();
|
let src = readline::input_stream();
|
||||||
readline::set_prompt(false);
|
readline::set_prompt(false);
|
||||||
@@ -551,70 +693,53 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sink_to_snapshot(&mut self) -> MachineState {
|
fn sink_to_snapshot(&mut self) -> MachineState {
|
||||||
let mut snapshot = MachineState::with_capacity(0);
|
let mut snapshot = MachineState::with_small_heap();
|
||||||
|
|
||||||
snapshot.hb = self.machine_st.hb;
|
snapshot.hb = self.machine_st.hb;
|
||||||
snapshot.e = self.machine_st.e;
|
snapshot.e = self.machine_st.e;
|
||||||
snapshot.b = self.machine_st.b;
|
snapshot.b = self.machine_st.b;
|
||||||
snapshot.b0 = self.machine_st.b0;
|
snapshot.b0 = self.machine_st.b0;
|
||||||
snapshot.s = self.machine_st.s;
|
snapshot.s = self.machine_st.s;
|
||||||
snapshot.tr = self.machine_st.tr;
|
snapshot.tr = self.machine_st.tr;
|
||||||
snapshot.pstr_tr = self.machine_st.pstr_tr;
|
|
||||||
snapshot.p = self.machine_st.p.clone();
|
|
||||||
snapshot.cp = self.machine_st.cp;
|
|
||||||
snapshot.attr_var_init = mem::replace(
|
|
||||||
&mut self.machine_st.attr_var_init,
|
|
||||||
AttrVarInitializer::new(0, 0)
|
|
||||||
);
|
|
||||||
snapshot.num_of_args = self.machine_st.num_of_args;
|
snapshot.num_of_args = self.machine_st.num_of_args;
|
||||||
|
|
||||||
snapshot.fail = self.machine_st.fail;
|
snapshot.fail = self.machine_st.fail;
|
||||||
snapshot.trail = mem::replace(&mut self.machine_st.trail, vec![]);
|
snapshot.trail = mem::replace(&mut self.machine_st.trail, vec![]);
|
||||||
snapshot.pstr_trail = mem::replace(&mut self.machine_st.pstr_trail, vec![]);
|
|
||||||
snapshot.heap = self.machine_st.heap.take();
|
snapshot.heap = self.machine_st.heap.take();
|
||||||
snapshot.mode = self.machine_st.mode;
|
snapshot.mode = self.machine_st.mode;
|
||||||
snapshot.and_stack = self.machine_st.and_stack.take();
|
snapshot.stack = self.machine_st.stack.take();
|
||||||
snapshot.or_stack = self.machine_st.or_stack.take();
|
|
||||||
snapshot.registers = mem::replace(&mut self.machine_st.registers, vec![]);
|
snapshot.registers = mem::replace(&mut self.machine_st.registers, vec![]);
|
||||||
snapshot.block = self.machine_st.block;
|
snapshot.block = self.machine_st.block;
|
||||||
|
|
||||||
snapshot.ball = self.machine_st.ball.take();
|
snapshot.ball = self.machine_st.ball.take();
|
||||||
snapshot.heap_locs = mem::replace(&mut self.machine_st.heap_locs, IndexMap::new());
|
snapshot.lifted_heap = self.machine_st.lifted_heap.take();
|
||||||
snapshot.lifted_heap = mem::replace(&mut self.machine_st.lifted_heap, vec![]);
|
|
||||||
|
|
||||||
snapshot
|
snapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
fn absorb_snapshot(&mut self, mut snapshot: MachineState) {
|
fn absorb_snapshot(&mut self, mut snapshot: MachineState) {
|
||||||
self.machine_st.hb = snapshot.hb;
|
self.machine_st.hb = snapshot.hb;
|
||||||
self.machine_st.e = snapshot.e;
|
self.machine_st.e = snapshot.e;
|
||||||
self.machine_st.b = snapshot.b;
|
self.machine_st.b = snapshot.b;
|
||||||
self.machine_st.b0 = snapshot.b0;
|
self.machine_st.b0 = snapshot.b0;
|
||||||
self.machine_st.s = snapshot.s;
|
self.machine_st.s = snapshot.s;
|
||||||
self.machine_st.tr = snapshot.tr;
|
self.machine_st.tr = snapshot.tr;
|
||||||
self.machine_st.pstr_tr = snapshot.pstr_tr;
|
|
||||||
self.machine_st.p = snapshot.p;
|
|
||||||
self.machine_st.cp = snapshot.cp;
|
|
||||||
self.machine_st.attr_var_init = snapshot.attr_var_init;
|
|
||||||
self.machine_st.num_of_args = snapshot.num_of_args;
|
self.machine_st.num_of_args = snapshot.num_of_args;
|
||||||
|
|
||||||
self.machine_st.fail = snapshot.fail;
|
self.machine_st.fail = snapshot.fail;
|
||||||
self.machine_st.trail = mem::replace(&mut snapshot.trail, vec![]);
|
self.machine_st.trail = mem::replace(&mut snapshot.trail, vec![]);
|
||||||
self.machine_st.pstr_trail = mem::replace(&mut snapshot.pstr_trail, vec![]);
|
|
||||||
|
|
||||||
self.inner_heap = self.machine_st.heap.take();
|
self.inner_heap = self.machine_st.heap.take();
|
||||||
self.inner_heap.truncate(0);
|
self.inner_heap.truncate(0);
|
||||||
|
|
||||||
self.machine_st.heap = snapshot.heap.take();
|
self.machine_st.heap = snapshot.heap.take();
|
||||||
self.machine_st.mode = snapshot.mode;
|
self.machine_st.mode = snapshot.mode;
|
||||||
self.machine_st.and_stack = snapshot.and_stack.take();
|
self.machine_st.stack = snapshot.stack;
|
||||||
self.machine_st.or_stack = snapshot.or_stack.take();
|
|
||||||
self.machine_st.registers = mem::replace(&mut snapshot.registers, vec![]);
|
self.machine_st.registers = mem::replace(&mut snapshot.registers, vec![]);
|
||||||
self.machine_st.block = snapshot.block;
|
self.machine_st.block = snapshot.block;
|
||||||
|
|
||||||
self.machine_st.ball = snapshot.ball.take();
|
self.machine_st.ball = snapshot.ball.take();
|
||||||
self.machine_st.heap_locs = mem::replace(&mut snapshot.heap_locs, IndexMap::new());
|
self.machine_st.lifted_heap = snapshot.lifted_heap.take();
|
||||||
self.machine_st.lifted_heap = mem::replace(&mut snapshot.lifted_heap, vec![]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn run_query(&mut self) {
|
pub(super) fn run_query(&mut self) {
|
||||||
@@ -637,37 +762,19 @@ impl Machine {
|
|||||||
// so hold onto it locally and restore it after the compiler has finished.
|
// so hold onto it locally and restore it after the compiler has finished.
|
||||||
self.machine_st.fail = false;
|
self.machine_st.fail = false;
|
||||||
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
|
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
|
||||||
|
|
||||||
self.dynamic_transaction(trans_type, p);
|
self.dynamic_transaction(trans_type, p);
|
||||||
|
self.code_repo.cached_query = cached_query;
|
||||||
|
|
||||||
if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p {
|
if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p {
|
||||||
self.code_repo.cached_query = cached_query;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.code_repo.cached_query = cached_query;
|
|
||||||
}
|
}
|
||||||
_ =>
|
_ =>
|
||||||
break
|
break
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn test_heap_view<Outputter>(&self, mut output: Outputter) -> Outputter
|
|
||||||
where
|
|
||||||
Outputter: HCValueOutputter,
|
|
||||||
{
|
|
||||||
for (var, addr) in self.machine_st.heap_locs.iter() {
|
|
||||||
output = self.machine_st.print_var_eq(
|
|
||||||
var.clone(),
|
|
||||||
addr.clone(),
|
|
||||||
&self.indices.op_dir,
|
|
||||||
output,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
@@ -727,10 +834,10 @@ impl MachineState {
|
|||||||
|
|
||||||
fn backtrack(&mut self) {
|
fn backtrack(&mut self) {
|
||||||
if self.b > 0 {
|
if self.b > 0 {
|
||||||
let b = self.b - 1;
|
let b = self.b;
|
||||||
|
|
||||||
self.b0 = self.or_stack[b].b0;
|
self.b0 = self.stack.index_or_frame(b).prelude.b0;
|
||||||
self.p = self.or_stack[b].bp.clone();
|
self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp);
|
||||||
|
|
||||||
if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.p {
|
if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.p {
|
||||||
self.fail = p == 0;
|
self.fail = p == 0;
|
||||||
|
|||||||
@@ -7,29 +7,37 @@ use crate::prolog::machine::machine_errors::*;
|
|||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::prolog::machine::machine_indices::*;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
// Module's and related types are defined in forms.
|
// Module's and related types are defined in forms.
|
||||||
impl Module {
|
impl Module {
|
||||||
pub fn new(module_decl: ModuleDecl, atom_tbl: TabledData<Atom>) -> Self
|
pub fn new(
|
||||||
|
module_decl: ModuleDecl,
|
||||||
|
atom_tbl: TabledData<Atom>,
|
||||||
|
listing_src: ListingSource,
|
||||||
|
) -> Self
|
||||||
{
|
{
|
||||||
Module {
|
Module {
|
||||||
module_decl,
|
|
||||||
atom_tbl,
|
atom_tbl,
|
||||||
|
module_decl,
|
||||||
|
term_dir: TermDir::new(),
|
||||||
user_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
user_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||||
user_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
user_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||||
term_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
term_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||||
goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||||
|
local_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||||
|
local_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||||
code_dir: CodeDir::new(),
|
code_dir: CodeDir::new(),
|
||||||
op_dir: default_op_dir(),
|
op_dir: default_op_dir(),
|
||||||
inserted_expansions: false,
|
inserted_expansions: false,
|
||||||
is_impromptu_module: false,
|
is_impromptu_module: false,
|
||||||
|
listing_src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_expansions(
|
pub fn dump_expansions(
|
||||||
&self,
|
&self,
|
||||||
code_repo: &mut CodeRepo,
|
code_repo: &mut CodeRepo,
|
||||||
flags: MachineFlags,
|
|
||||||
) -> Result<(), ParserError> {
|
) -> Result<(), ParserError> {
|
||||||
{
|
{
|
||||||
let te = code_repo
|
let te = code_repo
|
||||||
@@ -55,13 +63,13 @@ impl Module {
|
|||||||
ge.1.extend(self.user_goal_expansions.1.iter().cloned());
|
ge.1.extend(self.user_goal_expansions.1.iter().cloned());
|
||||||
}
|
}
|
||||||
|
|
||||||
code_repo.compile_hook(CompileTimeHook::TermExpansion, flags)?;
|
code_repo.compile_hook(CompileTimeHook::TermExpansion)?;
|
||||||
code_repo.compile_hook(CompileTimeHook::GoalExpansion, flags)?;
|
code_repo.compile_hook(CompileTimeHook::GoalExpansion)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_module_expansion_record(
|
pub fn add_expansion_record(
|
||||||
&mut self,
|
&mut self,
|
||||||
hook: CompileTimeHook,
|
hook: CompileTimeHook,
|
||||||
clause: PredicateClause,
|
clause: PredicateClause,
|
||||||
@@ -78,6 +86,35 @@ impl Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_local_expansion(
|
||||||
|
&mut self,
|
||||||
|
hook: CompileTimeHook,
|
||||||
|
clause: PredicateClause,
|
||||||
|
queue: VecDeque<TopLevel>,
|
||||||
|
) {
|
||||||
|
match hook {
|
||||||
|
CompileTimeHook::TermExpansion => {
|
||||||
|
(self.local_term_expansions.0).0.push(clause);
|
||||||
|
self.local_term_expansions.1.extend(queue.into_iter());
|
||||||
|
}
|
||||||
|
CompileTimeHook::GoalExpansion => {
|
||||||
|
(self.local_goal_expansions.0).0.push(clause);
|
||||||
|
self.local_goal_expansions.1.extend(queue.into_iter());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_local_expansions(&mut self) -> Vec<(Predicate, VecDeque<TopLevel>)>
|
||||||
|
{
|
||||||
|
let term_expansions =
|
||||||
|
mem::replace(&mut self.local_term_expansions, (Predicate::new(), VecDeque::new()));
|
||||||
|
let goal_expansions =
|
||||||
|
mem::replace(&mut self.local_goal_expansions, (Predicate::new(), VecDeque::new()));
|
||||||
|
|
||||||
|
vec![term_expansions, goal_expansions]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SubModuleUser {
|
pub trait SubModuleUser {
|
||||||
@@ -95,64 +132,55 @@ pub trait SubModuleUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn remove_module(&mut self, mod_name: ClauseName, module: &Module) {
|
fn remove_module(&mut self, mod_name: ClauseName, module: &Module) {
|
||||||
for (name, arity) in module.module_decl.exports.iter().cloned() {
|
for export in module.module_decl.exports.iter().cloned() {
|
||||||
let name = name.defrock_brackets();
|
match export {
|
||||||
|
ModuleExport::PredicateKey((name, arity)) => {
|
||||||
|
let name = name.defrock_brackets();
|
||||||
|
|
||||||
match self.get_code_index((name.clone(), arity), mod_name.clone()) {
|
match self.get_code_index((name.clone(), arity), mod_name.clone()) {
|
||||||
Some(CodeIndex(ref code_idx)) => {
|
Some(CodeIndex(ref code_idx)) => {
|
||||||
if &code_idx.borrow().1 != &module.module_decl.name {
|
if &code_idx.borrow().1 != &module.module_decl.name {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
self.remove_code_index((name.clone(), arity));
|
|
||||||
|
|
||||||
// remove or respecify ops.
|
|
||||||
if arity == 2 {
|
|
||||||
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::In) {
|
|
||||||
if mod_name == module.module_decl.name {
|
|
||||||
self.op_dir().remove(&(name.clone(), Fixity::In));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if arity == 1 {
|
|
||||||
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Pre) {
|
|
||||||
if mod_name == module.module_decl.name {
|
|
||||||
self.op_dir().remove(&(name.clone(), Fixity::Pre));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Post)
|
self.remove_code_index((name.clone(), arity));
|
||||||
{
|
|
||||||
if mod_name == module.module_decl.name {
|
// remove or respecify ops.
|
||||||
self.op_dir().remove(&(name.clone(), Fixity::Post));
|
if arity == 2 {
|
||||||
|
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::In) {
|
||||||
|
if mod_name == module.module_decl.name {
|
||||||
|
self.op_dir().remove(&(name.clone(), Fixity::In));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if arity == 1 {
|
||||||
|
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Pre) {
|
||||||
|
if mod_name == module.module_decl.name {
|
||||||
|
self.op_dir().remove(&(name.clone(), Fixity::Pre));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Post)
|
||||||
|
{
|
||||||
|
if mod_name == module.module_decl.name {
|
||||||
|
self.op_dir().remove(&(name.clone(), Fixity::Post));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
_ => {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
ModuleExport::OpDecl(op_decl) => {
|
||||||
|
let op_dir = self.op_dir();
|
||||||
|
op_dir.remove(&(op_decl.name(), op_decl.fixity()));
|
||||||
}
|
}
|
||||||
_ => {}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true on successful import.
|
// returns true on successful import.
|
||||||
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
|
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
|
||||||
let name = name.defrock_brackets();
|
let name = name.defrock_brackets();
|
||||||
let mut found_op = false;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut insert_op_dir = |fix| {
|
|
||||||
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), fix)) {
|
|
||||||
self.op_dir().insert((name.clone(), fix), op_data.clone());
|
|
||||||
found_op = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if arity == 1 {
|
|
||||||
insert_op_dir(Fixity::Pre);
|
|
||||||
insert_op_dir(Fixity::Post);
|
|
||||||
} else if arity == 2 {
|
|
||||||
insert_op_dir(Fixity::In);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
|
if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
|
||||||
let name = name.with_table(submodule.atom_tbl.clone());
|
let name = name.with_table(submodule.atom_tbl.clone());
|
||||||
@@ -163,7 +191,7 @@ pub trait SubModuleUser {
|
|||||||
self.insert_dir_entry(name, arity, code_data.clone());
|
self.insert_dir_entry(name, arity, code_data.clone());
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
found_op || submodule.is_impromptu_module
|
submodule.is_impromptu_module
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,30 +200,63 @@ pub trait SubModuleUser {
|
|||||||
_: &mut CodeRepo,
|
_: &mut CodeRepo,
|
||||||
_: MachineFlags,
|
_: MachineFlags,
|
||||||
_: &Module,
|
_: &Module,
|
||||||
_: &Vec<PredicateKey>,
|
_: &Vec<ModuleExport>,
|
||||||
|
) -> Result<(), SessionError>;
|
||||||
|
|
||||||
|
fn use_module(
|
||||||
|
&mut self,
|
||||||
|
_: &mut CodeRepo,
|
||||||
|
_: MachineFlags,
|
||||||
|
_: &Module
|
||||||
) -> Result<(), SessionError>;
|
) -> Result<(), SessionError>;
|
||||||
fn use_module(&mut self, _: &mut CodeRepo, _: MachineFlags, _: &Module) -> Result<(), SessionError>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_qualified_module<User>(
|
pub fn use_qualified_module<User>(
|
||||||
user: &mut User,
|
user: &mut User,
|
||||||
submodule: &Module,
|
submodule: &Module,
|
||||||
exports: &Vec<PredicateKey>,
|
exports: &Vec<ModuleExport>,
|
||||||
) -> Result<(), SessionError>
|
) -> Result<(), SessionError>
|
||||||
where
|
where
|
||||||
User: SubModuleUser,
|
User: SubModuleUser,
|
||||||
{
|
{
|
||||||
for (name, arity) in exports.iter().cloned() {
|
for export in exports.iter().cloned() {
|
||||||
if !submodule
|
match export {
|
||||||
.module_decl
|
ModuleExport::PredicateKey((name, arity)) => {
|
||||||
.exports
|
if !submodule
|
||||||
.contains(&(name.clone(), arity))
|
.module_decl
|
||||||
{
|
.exports
|
||||||
continue;
|
.contains(&ModuleExport::PredicateKey((name.clone(), arity)))
|
||||||
}
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if !user.import_decl(name, arity, submodule) {
|
if !user.import_decl(name.clone(), arity, submodule) {
|
||||||
return Err(SessionError::ModuleDoesNotContainExport);
|
let submodule_name = submodule.module_decl.name.clone();
|
||||||
|
|
||||||
|
return Err(SessionError::ModuleDoesNotContainExport(
|
||||||
|
submodule_name,
|
||||||
|
(name, arity)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ModuleExport::OpDecl(op_decl) => {
|
||||||
|
if !submodule
|
||||||
|
.module_decl
|
||||||
|
.exports
|
||||||
|
.contains(&ModuleExport::OpDecl(op_decl.clone()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let op_dir = user.op_dir();
|
||||||
|
let prec = op_decl.0;
|
||||||
|
|
||||||
|
op_decl.insert_into_op_dir(
|
||||||
|
submodule.module_decl.name.clone(),
|
||||||
|
op_dir,
|
||||||
|
prec,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,9 +267,28 @@ pub fn use_module<User: SubModuleUser>(
|
|||||||
user: &mut User,
|
user: &mut User,
|
||||||
submodule: &Module,
|
submodule: &Module,
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
for (name, arity) in submodule.module_decl.exports.iter().cloned() {
|
for export in submodule.module_decl.exports.iter().cloned() {
|
||||||
if !user.import_decl(name, arity, submodule) {
|
match export {
|
||||||
return Err(SessionError::ModuleDoesNotContainExport);
|
ModuleExport::PredicateKey((name, arity)) => {
|
||||||
|
if !user.import_decl(name.clone(), arity, submodule) {
|
||||||
|
let submodule_name = submodule.module_decl.name.clone();
|
||||||
|
|
||||||
|
return Err(SessionError::ModuleDoesNotContainExport(
|
||||||
|
submodule_name,
|
||||||
|
(name, arity)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ModuleExport::OpDecl(op_decl) => {
|
||||||
|
let op_dir = user.op_dir();
|
||||||
|
let prec = op_decl.0;
|
||||||
|
|
||||||
|
op_decl.insert_into_op_dir(
|
||||||
|
submodule.module_decl.name.clone(),
|
||||||
|
op_dir,
|
||||||
|
prec,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +321,7 @@ impl SubModuleUser for Module {
|
|||||||
_: &mut CodeRepo,
|
_: &mut CodeRepo,
|
||||||
_: MachineFlags,
|
_: MachineFlags,
|
||||||
submodule: &Module,
|
submodule: &Module,
|
||||||
exports: &Vec<PredicateKey>,
|
exports: &Vec<ModuleExport>,
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
use_qualified_module(self, submodule, exports)?;
|
use_qualified_module(self, submodule, exports)?;
|
||||||
|
|
||||||
@@ -283,7 +363,7 @@ impl SubModuleUser for Module {
|
|||||||
self.user_goal_expansions
|
self.user_goal_expansions
|
||||||
.1
|
.1
|
||||||
.extend(submodule.goal_expansions.1.iter().cloned());
|
.extend(submodule.goal_expansions.1.iter().cloned());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,145 +0,0 @@
|
|||||||
use crate::prolog::machine::machine_indices::*;
|
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub struct Frame {
|
|
||||||
pub global_index: usize,
|
|
||||||
pub e: usize,
|
|
||||||
pub cp: LocalCodePtr,
|
|
||||||
pub attr_var_init_b: usize,
|
|
||||||
pub b: usize,
|
|
||||||
pub bp: CodePtr,
|
|
||||||
pub tr: usize,
|
|
||||||
pub pstr_tr: usize,
|
|
||||||
pub h: usize,
|
|
||||||
pub b0: usize,
|
|
||||||
args: Vec<Addr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(
|
|
||||||
global_index: usize,
|
|
||||||
e: usize,
|
|
||||||
cp: LocalCodePtr,
|
|
||||||
attr_var_init_b: usize,
|
|
||||||
b: usize,
|
|
||||||
bp: CodePtr,
|
|
||||||
tr: usize,
|
|
||||||
pstr_tr: usize,
|
|
||||||
h: usize,
|
|
||||||
b0: usize,
|
|
||||||
n: usize,
|
|
||||||
) -> Self {
|
|
||||||
Frame {
|
|
||||||
global_index,
|
|
||||||
e,
|
|
||||||
cp,
|
|
||||||
attr_var_init_b,
|
|
||||||
b,
|
|
||||||
bp,
|
|
||||||
tr,
|
|
||||||
pstr_tr,
|
|
||||||
h,
|
|
||||||
b0,
|
|
||||||
args: vec![Addr::HeapCell(0); n],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn num_args(&self) -> usize {
|
|
||||||
self.args.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OrStack(Vec<Frame>);
|
|
||||||
|
|
||||||
impl OrStack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
OrStack(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(
|
|
||||||
&mut self,
|
|
||||||
global_index: usize,
|
|
||||||
e: usize,
|
|
||||||
cp: LocalCodePtr,
|
|
||||||
attr_var_init_b: usize,
|
|
||||||
b: usize,
|
|
||||||
bp: CodePtr,
|
|
||||||
tr: usize,
|
|
||||||
pstr_tr: usize,
|
|
||||||
h: usize,
|
|
||||||
b0: usize,
|
|
||||||
n: usize,
|
|
||||||
) {
|
|
||||||
self.0.push(Frame::new(
|
|
||||||
global_index,
|
|
||||||
e,
|
|
||||||
cp,
|
|
||||||
attr_var_init_b,
|
|
||||||
b,
|
|
||||||
bp,
|
|
||||||
tr,
|
|
||||||
pstr_tr,
|
|
||||||
h,
|
|
||||||
b0,
|
|
||||||
n,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn take(&mut self) -> Self {
|
|
||||||
OrStack(mem::replace(&mut self.0, vec![]))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.0.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn top(&self) -> Option<&Frame> {
|
|
||||||
self.0.last()
|
|
||||||
}
|
|
||||||
|
|
||||||
// truncate expects a 1-indexed new_b, ie.
|
|
||||||
// the value b of MachineState.
|
|
||||||
pub fn truncate(&mut self, new_b: usize) {
|
|
||||||
self.0.truncate(new_b);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.0.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for OrStack {
|
|
||||||
type Output = Frame;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.0.index(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for OrStack {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.0.index_mut(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Frame {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.args.index(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Frame {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.args.index_mut(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
161
src/prolog/machine/partial_string.rs
Normal file
161
src/prolog/machine/partial_string.rs
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
use crate::prolog::machine::machine_indices::*;
|
||||||
|
use crate::prolog::machine::raw_block::*;
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::ptr;
|
||||||
|
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 {
|
||||||
|
pub(super) buf: RawBlock<PartialStringTraits>,
|
||||||
|
pub(super) tail: Addr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for PartialString {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
self.clone_from_offset(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for PartialString {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self as *const _ == other as *const _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scan_for_terminator(src: &str) -> usize {
|
||||||
|
let mut terminator_idx = 0;
|
||||||
|
|
||||||
|
for c in src.chars() {
|
||||||
|
if c == '\u{0}' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
terminator_idx += c.len_utf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
terminator_idx
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialString {
|
||||||
|
pub(super)
|
||||||
|
fn new(src: &str, h: usize) -> Option<(Self, &str)> {
|
||||||
|
let pstr = PartialString {
|
||||||
|
buf: RawBlock::with_capacity(src.len() + '\u{0}'.len_utf8()),
|
||||||
|
tail: Addr::PStrTail(h, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
pstr.append_chars(src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
|
||||||
|
let terminator_idx = scan_for_terminator(src);
|
||||||
|
|
||||||
|
if terminator_idx == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_top = self.buf.new_block(terminator_idx + '\u{0}'.len_utf8());
|
||||||
|
|
||||||
|
ptr::copy(
|
||||||
|
src.as_ptr(),
|
||||||
|
self.buf.top 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() {
|
||||||
|
(self, &src[terminator_idx + '\u{0}'.len_utf8() ..])
|
||||||
|
} else {
|
||||||
|
(self, "")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 mut pstr = PartialString {
|
||||||
|
buf: RawBlock::with_capacity(self.len() + '\u{0}'.len_utf8()),
|
||||||
|
tail: Addr::PStrTail(0, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let len = if self.len() > n { self.len() - n } else { 0 };
|
||||||
|
let new_top = pstr.buf.new_block(len + '\u{0}'.len_utf8());
|
||||||
|
|
||||||
|
if len > 0 {
|
||||||
|
ptr::copy(
|
||||||
|
(self.buf.base as usize + n) as *mut u8,
|
||||||
|
pstr.buf.base as *mut _,
|
||||||
|
len,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pstr.write_terminator_at(len);
|
||||||
|
pstr.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _;
|
||||||
|
}
|
||||||
|
|
||||||
|
pstr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super)
|
||||||
|
fn write_terminator_at(&mut self, index: usize) {
|
||||||
|
unsafe {
|
||||||
|
ptr::write(
|
||||||
|
(self.buf.base as usize + index) as *mut u8,
|
||||||
|
0u8,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn block_as_str(&self) -> &str {
|
||||||
|
unsafe {
|
||||||
|
let slice = slice::from_raw_parts(self.buf.base, self.len());
|
||||||
|
str::from_utf8(slice).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn tail_addr(&self) -> &Addr {
|
||||||
|
&self.tail
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.buf.top as usize - self.buf.base as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,8 +49,8 @@ call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :-
|
|||||||
|
|
||||||
call_query_var_goals([], _, []).
|
call_query_var_goals([], _, []).
|
||||||
call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
|
call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
|
||||||
( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0),
|
( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0)
|
||||||
atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals)
|
, atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals)
|
||||||
),
|
),
|
||||||
E,
|
E,
|
||||||
( '$print_attribute_goals_exception'(Module, E),
|
( '$print_attribute_goals_exception'(Module, E),
|
||||||
@@ -63,7 +63,7 @@ call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
|
|||||||
|
|
||||||
call_attr_var_goals([], _, []).
|
call_attr_var_goals([], _, []).
|
||||||
call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :-
|
call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :-
|
||||||
( catch(Module:attribute_goals(AttrVar, Goals, RGoals),
|
( catch(Module:attribute_goals(AttrVar, Goals, RGoals),
|
||||||
E,
|
E,
|
||||||
'$print_attribute_goals_exception'(Module, E)
|
'$print_attribute_goals_exception'(Module, E)
|
||||||
)
|
)
|
||||||
@@ -83,3 +83,26 @@ gather_modules_for_attrs(Attrs, Modules, Modules) :-
|
|||||||
gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :-
|
gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :-
|
||||||
'$module_of'(Module, Attr),
|
'$module_of'(Module, Attr),
|
||||||
gather_modules_for_attrs(Attrs, Modules, Modules0).
|
gather_modules_for_attrs(Attrs, Modules, Modules0).
|
||||||
|
|
||||||
|
module_prefixed_goals([], _, Gs, Gs).
|
||||||
|
module_prefixed_goals([G|Gs], Module, [MG|MGs], TailGs) :-
|
||||||
|
( G = _:_ -> MG = G
|
||||||
|
; MG = Module:G
|
||||||
|
),
|
||||||
|
module_prefixed_goals(Gs, Module, MGs, TailGs).
|
||||||
|
|
||||||
|
call_attribute_goals_with_module_prefix([], _, _, []).
|
||||||
|
call_attribute_goals_with_module_prefix([Module | Modules], GoalCaller, AttrVars, Goals) :-
|
||||||
|
call(GoalCaller, AttrVars, Module, Goals0),
|
||||||
|
enqueue_goals(Goals0),
|
||||||
|
module_prefixed_goals(Goals0, Module, Goals, Gs),
|
||||||
|
call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs).
|
||||||
|
|
||||||
|
copy_term(Source, Dest, Goals) :-
|
||||||
|
term_variables(Source, Vars),
|
||||||
|
gather_modules(Vars, Modules0, _),
|
||||||
|
sort(Modules0, Modules),
|
||||||
|
call_attribute_goals_with_module_prefix(Modules, call_query_var_goals, Vars, Goals0),
|
||||||
|
sort(Goals0, Goals1),
|
||||||
|
!,
|
||||||
|
'$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]).
|
||||||
|
|||||||
123
src/prolog/machine/raw_block.rs
Normal file
123
src/prolog/machine/raw_block.rs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use std::alloc;
|
||||||
|
use std::mem;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
pub(crate) trait RawBlockTraits {
|
||||||
|
fn init_size() -> usize;
|
||||||
|
fn align() -> usize;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn base_offset(base: *const u8) -> *const u8 {
|
||||||
|
base
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct RawBlock<T: RawBlockTraits> {
|
||||||
|
pub(crate) size: usize,
|
||||||
|
pub(crate) base: *const u8,
|
||||||
|
pub(crate) top: *const u8,
|
||||||
|
_marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RawBlockTraits> RawBlock<T> {
|
||||||
|
pub(crate)
|
||||||
|
fn new() -> Self {
|
||||||
|
let mut block = RawBlock { size: 0,
|
||||||
|
base: ptr::null(),
|
||||||
|
top: ptr::null(),
|
||||||
|
_marker: PhantomData };
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
block.grow();
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
self.base = alloc::alloc(layout) as *const _;
|
||||||
|
self.size = cap;
|
||||||
|
|
||||||
|
self.top = T::base_offset(self.base);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
unsafe fn grow(&mut self) {
|
||||||
|
if self.size == 0 {
|
||||||
|
self.init_at_size(T::init_size());
|
||||||
|
} else {
|
||||||
|
let layout = alloc::Layout::from_size_align_unchecked(T::init_size(), T::align());
|
||||||
|
let top_dist = self.top as usize - self.base as usize;
|
||||||
|
|
||||||
|
self.base = alloc::realloc(self.base as *mut _, layout, self.size*2) as *const _;
|
||||||
|
self.top = (self.base as usize + top_dist) as *const _;
|
||||||
|
self.size *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn empty_block() -> Self {
|
||||||
|
RawBlock { size: 0,
|
||||||
|
base: ptr::null(),
|
||||||
|
top: ptr::null(),
|
||||||
|
_marker: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn take(&mut self) -> Self {
|
||||||
|
mem::replace(self, Self::empty_block())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn free_space(&self) -> usize {
|
||||||
|
debug_assert!(self.top >= self.base,
|
||||||
|
"self.top = {:?} < {:?} = self.base",
|
||||||
|
self.top, self.base);
|
||||||
|
|
||||||
|
self.size - (self.top as usize - self.base as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
unsafe fn new_block(&mut self, size: usize) -> *const u8 {
|
||||||
|
loop {
|
||||||
|
if self.free_space() >= size {
|
||||||
|
return (self.top as usize + size) as *const _;
|
||||||
|
} else {
|
||||||
|
self.grow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
fn deallocate(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let layout = alloc::Layout::from_size_align_unchecked(self.size, T::align());
|
||||||
|
|
||||||
|
alloc::dealloc(self.base as *mut u8, layout);
|
||||||
|
|
||||||
|
self.top = ptr::null();
|
||||||
|
self.base = ptr::null();
|
||||||
|
self.size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
338
src/prolog/machine/stack.rs
Normal file
338
src/prolog/machine/stack.rs
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
use crate::prolog::machine::machine_indices::*;
|
||||||
|
use crate::prolog::machine::raw_block::*;
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::ops::{Index, IndexMut};
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
struct StackTraits {}
|
||||||
|
|
||||||
|
impl RawBlockTraits for StackTraits {
|
||||||
|
#[inline]
|
||||||
|
fn init_size() -> usize {
|
||||||
|
10 * 1024 * 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn align() -> usize {
|
||||||
|
mem::align_of::<Addr>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn base_offset(base: *const u8) -> *const u8 {
|
||||||
|
unsafe {
|
||||||
|
base.offset(Self::align() as isize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn prelude_size<Prelude>() -> usize {
|
||||||
|
let size = mem::size_of::<Prelude>();
|
||||||
|
let align = mem::align_of::<Addr>();
|
||||||
|
|
||||||
|
(size & !(align - 1)) + align
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Stack {
|
||||||
|
buf: RawBlock<StackTraits>,
|
||||||
|
_marker: PhantomData<Addr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Stack {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.drop_in_place();
|
||||||
|
self.buf.deallocate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct FramePrelude {
|
||||||
|
is_or_frame: u8,
|
||||||
|
pub num_cells: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AndFramePrelude {
|
||||||
|
pub univ_prelude: FramePrelude,
|
||||||
|
pub e: usize,
|
||||||
|
pub cp: LocalCodePtr,
|
||||||
|
pub interrupt_cp: LocalCodePtr,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AndFrame {
|
||||||
|
pub prelude: AndFramePrelude,
|
||||||
|
_marker: PhantomData<Addr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AndFrame {
|
||||||
|
pub fn size_of(num_cells: usize) -> usize {
|
||||||
|
prelude_size::<AndFramePrelude>() + num_cells * mem::size_of::<Addr>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for AndFrame {
|
||||||
|
type Output = Addr;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
let prelude_offset = prelude_size::<AndFramePrelude>();
|
||||||
|
let index_offset = (index - 1) * mem::size_of::<Addr>();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let ptr = mem::transmute::<&AndFrame, *const u8>(self);
|
||||||
|
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||||
|
|
||||||
|
&*(ptr as *const Addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for AndFrame {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
let prelude_offset = prelude_size::<AndFramePrelude>();
|
||||||
|
let index_offset = (index - 1) * mem::size_of::<Addr>();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
|
||||||
|
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||||
|
|
||||||
|
&mut *(ptr as *mut Addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
pub cp: LocalCodePtr,
|
||||||
|
pub b: usize,
|
||||||
|
pub bp: LocalCodePtr,
|
||||||
|
pub tr: usize,
|
||||||
|
pub pstr_tr: usize,
|
||||||
|
pub h: usize,
|
||||||
|
pub b0: usize,
|
||||||
|
pub attr_var_init_queue_b: usize,
|
||||||
|
pub attr_var_init_bindings_b: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OrFrame {
|
||||||
|
pub prelude: OrFramePrelude,
|
||||||
|
_marker: PhantomData<Addr>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for OrFrame {
|
||||||
|
type Output = Addr;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
let prelude_offset = prelude_size::<OrFramePrelude>();
|
||||||
|
let index_offset = index * mem::size_of::<Addr>();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let ptr = mem::transmute::<&OrFrame, *const u8>(self);
|
||||||
|
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||||
|
|
||||||
|
&*(ptr as *const Addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for OrFrame {
|
||||||
|
#[inline]
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
let prelude_offset = prelude_size::<OrFramePrelude>();
|
||||||
|
let index_offset = index * mem::size_of::<Addr>();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
|
||||||
|
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||||
|
|
||||||
|
&mut *(ptr as *mut Addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stack {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Stack { buf: RawBlock::new(), _marker: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_and_frame(&mut self, num_cells: usize) -> usize {
|
||||||
|
let frame_size = AndFrame::size_of(num_cells);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let new_top = self.buf.new_block(frame_size);
|
||||||
|
|
||||||
|
for idx in 0 .. num_cells {
|
||||||
|
let offset = prelude_size::<AndFramePrelude>() + idx * mem::size_of::<Addr>();
|
||||||
|
ptr::write((self.buf.top as usize + offset) as *mut Addr, Addr::StackCell(0,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
self.buf.top = new_top;
|
||||||
|
|
||||||
|
e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
|
||||||
|
let frame_size = OrFrame::size_of(num_cells);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let new_top = self.buf.new_block(frame_size);
|
||||||
|
|
||||||
|
for idx in 0 .. num_cells {
|
||||||
|
let offset = prelude_size::<OrFramePrelude>() + idx * mem::size_of::<Addr>();
|
||||||
|
ptr::write((self.buf.top as usize + offset) as *mut Addr, Addr::StackCell(0,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
self.buf.top = new_top;
|
||||||
|
|
||||||
|
b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn index_and_frame(&self, e: usize) -> &AndFrame {
|
||||||
|
unsafe {
|
||||||
|
let ptr = self.buf.base as usize + e;
|
||||||
|
&*(ptr as *const AndFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame {
|
||||||
|
unsafe {
|
||||||
|
let ptr = self.buf.base as usize + e;
|
||||||
|
&mut *(ptr as *mut AndFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn index_or_frame(&self, b: usize) -> &OrFrame {
|
||||||
|
unsafe {
|
||||||
|
let ptr = self.buf.base as usize + b;
|
||||||
|
&*(ptr as *const OrFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
|
||||||
|
unsafe {
|
||||||
|
let ptr = self.buf.base as usize + b;
|
||||||
|
&mut *(ptr as *mut OrFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take(&mut self) -> Self {
|
||||||
|
Stack { buf: self.buf.take(), _marker: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn truncate(&mut self, b: usize) {
|
||||||
|
if b == 0 {
|
||||||
|
self.inner_truncate(mem::align_of::<Addr>());
|
||||||
|
} else {
|
||||||
|
self.inner_truncate(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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>());
|
||||||
|
|
||||||
|
debug_assert!(if self.buf.top.is_null() {
|
||||||
|
self.buf.top == self.buf.base
|
||||||
|
} else {
|
||||||
|
self.buf.top as usize == self.buf.base as usize + mem::align_of::<Addr>()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -73,11 +73,10 @@ pub struct TermStream<'a, R: Read> {
|
|||||||
stack: Vec<Term>,
|
stack: Vec<Term>,
|
||||||
pub(crate) wam: &'a mut Machine,
|
pub(crate) wam: &'a mut Machine,
|
||||||
parser: Parser<'a, R>,
|
parser: Parser<'a, R>,
|
||||||
in_module: bool,
|
|
||||||
pub(crate) flags: MachineFlags,
|
pub(crate) flags: MachineFlags,
|
||||||
term_expansion_lens: (usize, usize),
|
term_expansion_lens: (usize, usize),
|
||||||
goal_expansion_lens: (usize, usize),
|
goal_expansion_lens: (usize, usize),
|
||||||
top_level_terms: Vec<(Term, usize, usize)> // term, line_num, col_num.
|
top_level_terms: Vec<(Term, usize, usize)>, // term, line_num, col_num.
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExpansionAdditionResult {
|
pub struct ExpansionAdditionResult {
|
||||||
@@ -104,6 +103,8 @@ impl ExpansionAdditionResult {
|
|||||||
impl<'a, R: Read> Drop for TermStream<'a, R> {
|
impl<'a, R: Read> Drop for TermStream<'a, R> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.wam.indices.in_situ_code_dir.clear();
|
self.wam.indices.in_situ_code_dir.clear();
|
||||||
|
self.wam.indices.in_situ_module_dir.clear();
|
||||||
|
|
||||||
self.wam.code_repo.in_situ_code.clear();
|
self.wam.code_repo.in_situ_code.clear();
|
||||||
discard_result!(self.rollback_expansion_code());
|
discard_result!(self.rollback_expansion_code());
|
||||||
}
|
}
|
||||||
@@ -126,9 +127,8 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
|
.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
|
||||||
wam,
|
wam,
|
||||||
parser: Parser::new(src, atom_tbl, flags),
|
parser: Parser::new(src, atom_tbl, flags),
|
||||||
in_module: false,
|
|
||||||
flags,
|
flags,
|
||||||
top_level_terms: vec![]
|
top_level_terms: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
pub fn col_num(&self) -> usize {
|
pub fn col_num(&self) -> usize {
|
||||||
self.parser.col_num()
|
self.parser.col_num()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn update_expansion_lens(&mut self) {
|
pub fn update_expansion_lens(&mut self) {
|
||||||
let te_key = (clause_name!("term_expansion"), 2);
|
let te_key = (clause_name!("term_expansion"), 2);
|
||||||
@@ -209,10 +209,10 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
|
|
||||||
self.wam
|
self.wam
|
||||||
.code_repo
|
.code_repo
|
||||||
.compile_hook(CompileTimeHook::TermExpansion, self.flags)?;
|
.compile_hook(CompileTimeHook::TermExpansion)?;
|
||||||
self.wam
|
self.wam
|
||||||
.code_repo
|
.code_repo
|
||||||
.compile_hook(CompileTimeHook::GoalExpansion, self.flags)?;
|
.compile_hook(CompileTimeHook::GoalExpansion)?;
|
||||||
|
|
||||||
Ok(ExpansionAdditionResult {
|
Ok(ExpansionAdditionResult {
|
||||||
term_expansion_additions,
|
term_expansion_additions,
|
||||||
@@ -226,8 +226,12 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
let iter = extract_from_list(head, tail)?;
|
let iter = extract_from_list(head, tail)?;
|
||||||
Ok(self.stack.extend(iter))
|
Ok(self.stack.extend(iter))
|
||||||
}
|
}
|
||||||
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Ok(self.stack.push(term)),
|
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => {
|
||||||
_ => Err(ParserError::ExpectedTopLevelTerm),
|
Ok(self.stack.push(term))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(ParserError::ExpectedTopLevelTerm)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,36 +244,45 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags);
|
let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags);
|
||||||
|
|
||||||
parser.read_term(composite_op!(
|
parser.read_term(composite_op!(
|
||||||
self.in_module,
|
false,
|
||||||
&self.wam.indices.op_dir,
|
&self.wam.indices.op_dir,
|
||||||
op_dir
|
op_dir
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_term(&mut self, op_dir: &OpDir) -> Result<Term, ParserError> {
|
pub fn expand_term(&mut self, term: Term, op_dir: &OpDir) -> Result<Term, ParserError> {
|
||||||
let mut machine_st = MachineState::new();
|
let mut machine_st = MachineState::new();
|
||||||
|
|
||||||
|
self.stack.push(term);
|
||||||
|
|
||||||
|
while let Some(term) = self.stack.pop() {
|
||||||
|
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::TermExpansion) {
|
||||||
|
Some(term_string) => {
|
||||||
|
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
|
||||||
|
self.enqueue_term(term)?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Ok(term);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_term(&mut self, op_dir: &OpDir) -> Result<Term, ParserError> {
|
||||||
loop {
|
loop {
|
||||||
while let Some(term) = self.stack.pop() {
|
if let Some(term) = self.stack.pop() {
|
||||||
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::TermExpansion) {
|
return Ok(self.expand_term(term, op_dir)?);
|
||||||
Some(term_string) => {
|
|
||||||
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
|
|
||||||
self.enqueue_term(term)?
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let term = self.run_goal_expanders(&mut machine_st, op_dir, term)?;
|
|
||||||
return Ok(term);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.parser.reset();
|
self.parser.reset();
|
||||||
|
|
||||||
let line_num = self.line_num();
|
let line_num = self.line_num();
|
||||||
let col_num = self.col_num();
|
let col_num = self.col_num();
|
||||||
|
|
||||||
let term = self.parser.read_term(composite_op!(
|
let term = self.parser.read_term(composite_op!(
|
||||||
self.in_module,
|
false,
|
||||||
&self.wam.indices.op_dir,
|
&self.wam.indices.op_dir,
|
||||||
op_dir
|
op_dir
|
||||||
))?;
|
))?;
|
||||||
@@ -281,40 +294,6 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn run_goal_expanders(
|
|
||||||
&mut self,
|
|
||||||
machine_st: &mut MachineState,
|
|
||||||
op_dir: &OpDir,
|
|
||||||
term: Term,
|
|
||||||
) -> Result<Term, ParserError> {
|
|
||||||
match term {
|
|
||||||
Term::Clause(cell, name, mut terms, arity) => {
|
|
||||||
let mut new_terms = {
|
|
||||||
let old_terms = match (name.as_str(), terms.len()) {
|
|
||||||
(":-", 2) => {
|
|
||||||
let comma_term = *terms.pop().unwrap();
|
|
||||||
unfold_by_str(comma_term, ",")
|
|
||||||
}
|
|
||||||
("?-", 1) => unfold_by_str(*terms.pop().unwrap(), ","),
|
|
||||||
_ => return Ok(Term::Clause(cell, name, terms, arity)),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.expand_goals(machine_st, op_dir, VecDeque::from(old_terms))?
|
|
||||||
};
|
|
||||||
|
|
||||||
let initial_term = new_terms.pop().unwrap();
|
|
||||||
terms.push(Box::new(fold_by_str(
|
|
||||||
new_terms.into_iter(),
|
|
||||||
initial_term,
|
|
||||||
clause_name!(","),
|
|
||||||
)));
|
|
||||||
|
|
||||||
Ok(Term::Clause(cell, name, terms, arity))
|
|
||||||
}
|
|
||||||
_ => Ok(term),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super)
|
pub(super)
|
||||||
fn expand_goals(
|
fn expand_goals(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -324,7 +303,7 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
) -> Result<Vec<Term>, ParserError> {
|
) -> Result<Vec<Term>, ParserError> {
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
|
|
||||||
while let Some(term) = terms.pop_front() {
|
while let Some(term) = terms.pop_front() {
|
||||||
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::GoalExpansion) {
|
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::GoalExpansion) {
|
||||||
Some(term_string) => {
|
Some(term_string) => {
|
||||||
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
|
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
|
||||||
@@ -374,6 +353,15 @@ impl MachineState {
|
|||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset the machine, but keep the heap contents as they were.
|
||||||
|
// this prevents clashes between underscored variable names
|
||||||
|
// in the same query.
|
||||||
|
fn reset_with_heap_preservation(&mut self) {
|
||||||
|
let heap = self.heap.take();
|
||||||
|
self.reset();
|
||||||
|
self.heap = heap;
|
||||||
|
}
|
||||||
|
|
||||||
fn try_expand_term(
|
fn try_expand_term(
|
||||||
&mut self,
|
&mut self,
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
@@ -381,15 +369,18 @@ impl MachineState {
|
|||||||
hook: CompileTimeHook,
|
hook: CompileTimeHook,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let term_write_result = write_term_to_heap(term, self);
|
let term_write_result = write_term_to_heap(term, self);
|
||||||
let h = self.heap.h;
|
let h = self.heap.h();
|
||||||
|
|
||||||
self[temp_v!(1)] = Addr::HeapCell(term_write_result.heap_loc);
|
self[temp_v!(1)] = Addr::HeapCell(term_write_result.heap_loc);
|
||||||
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
|
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
|
||||||
self[temp_v!(2)] = Addr::HeapCell(h);
|
self[temp_v!(2)] = Addr::HeapCell(h);
|
||||||
|
|
||||||
let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
|
let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
|
||||||
wam.code_repo.cached_query = code;
|
wam.code_repo.cached_query = code;
|
||||||
|
|
||||||
|
self.cp = LocalCodePtr::TopLevel(0, 0);
|
||||||
|
self.at_end_of_expansion = false;
|
||||||
|
|
||||||
self.query_stepper(
|
self.query_stepper(
|
||||||
&mut wam.indices,
|
&mut wam.indices,
|
||||||
&mut wam.policies,
|
&mut wam.policies,
|
||||||
@@ -397,8 +388,8 @@ impl MachineState {
|
|||||||
&mut readline::input_stream(),
|
&mut readline::input_stream(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.fail {
|
if self.fail || self.at_end_of_expansion {
|
||||||
self.reset();
|
self.reset_with_heap_preservation();
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let TermWriteResult { var_dict, .. } = term_write_result;
|
let TermWriteResult { var_dict, .. } = term_write_result;
|
||||||
@@ -406,7 +397,7 @@ impl MachineState {
|
|||||||
self.heap_locs = var_dict;
|
self.heap_locs = var_dict;
|
||||||
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
|
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
|
||||||
|
|
||||||
self.reset();
|
self.reset_with_heap_preservation();
|
||||||
Some(output.result())
|
Some(output.result())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use std::cell::Cell;
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::ops::DerefMut;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
enum IndexSource<'a, T> {
|
enum IndexSource<'a, T> {
|
||||||
@@ -81,11 +82,11 @@ impl<'a, 'b, 'c, R: Read> CompositeIndices<'a, 'b, 'c, R> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(idx) = idx_opt {
|
if let Some(idx) = idx_opt {
|
||||||
self.local_code_dir().insert((name, arity), idx.clone());
|
self.local_code_dir().insert((name.clone(), arity), idx.clone());
|
||||||
idx
|
idx
|
||||||
} else {
|
} else {
|
||||||
let idx = CodeIndex::default();
|
let idx = CodeIndex::default();
|
||||||
self.local_code_dir().insert((name, arity), idx.clone());
|
self.local_code_dir().insert((name.clone(), arity), idx.clone());
|
||||||
idx
|
idx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,6 +109,31 @@ impl<'a, 'b, 'c, R: Read> CompositeIndices<'a, 'b, 'c, R> {
|
|||||||
ct => ct,
|
ct => ct,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_in_situ_module_info(&mut self, module_name: ClauseName, term: &mut Term)
|
||||||
|
{
|
||||||
|
let atom_tbl =
|
||||||
|
match self.term_stream.wam.indices.in_situ_module_dir.get(&module_name) {
|
||||||
|
Some(ref module_stub) => module_stub.atom_tbl.clone(),
|
||||||
|
None => {
|
||||||
|
let atom_tbl = match self.term_stream.wam.indices.modules.get(&module_name) {
|
||||||
|
Some(ref module) => module.atom_tbl.clone(),
|
||||||
|
None => TabledData::new(module_name.to_rc()),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.term_stream.wam.indices.in_situ_module_dir.insert(
|
||||||
|
module_name.clone(),
|
||||||
|
ModuleStub::new(atom_tbl.clone()),
|
||||||
|
);
|
||||||
|
|
||||||
|
atom_tbl
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(name) = term.name() {
|
||||||
|
term.set_name(name.with_table(atom_tbl));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_compile_time_hook(
|
fn as_compile_time_hook(
|
||||||
@@ -196,13 +222,14 @@ fn setup_op_decl(
|
|||||||
to_op_decl(prec, spec.as_str(), name)
|
to_op_decl(prec, spec.as_str(), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_predicate_indicator(mut term: Term) -> Result<PredicateKey, ParserError> {
|
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserError>
|
||||||
|
{
|
||||||
match term {
|
match term {
|
||||||
Term::Clause(_, ref name, ref mut terms, Some(_))
|
Term::Clause(_, ref name, ref mut terms, Some(_))
|
||||||
if name.as_str() == "/" && terms.len() == 2 =>
|
if name.as_str() == "/" && terms.len() == 2 =>
|
||||||
{
|
{
|
||||||
let arity = *terms.pop().unwrap();
|
let arity = *terms.pop().unwrap();
|
||||||
let name = *terms.pop().unwrap();
|
let name = *terms.pop().unwrap();
|
||||||
|
|
||||||
let arity = arity
|
let arity = arity
|
||||||
.to_constant()
|
.to_constant()
|
||||||
@@ -210,7 +237,7 @@ fn setup_predicate_indicator(mut term: Term) -> Result<PredicateKey, ParserError
|
|||||||
.and_then(|n| n.to_usize())
|
.and_then(|n| n.to_usize())
|
||||||
.ok_or(ParserError::InvalidModuleExport)?;
|
.ok_or(ParserError::InvalidModuleExport)?;
|
||||||
|
|
||||||
let name = name
|
let name = name
|
||||||
.to_constant()
|
.to_constant()
|
||||||
.and_then(|c| c.to_atom())
|
.and_then(|c| c.to_atom())
|
||||||
.ok_or(ParserError::InvalidModuleExport)?;
|
.ok_or(ParserError::InvalidModuleExport)?;
|
||||||
@@ -221,7 +248,54 @@ fn setup_predicate_indicator(mut term: Term) -> Result<PredicateKey, ParserError
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleDecl, ParserError> {
|
fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKey, ParserError>
|
||||||
|
{
|
||||||
|
match term {
|
||||||
|
Term::Clause(_, ref name, ref mut terms, Some(_))
|
||||||
|
if name.as_str() == ":" && terms.len() == 2 =>
|
||||||
|
{
|
||||||
|
let mut predicate_indicator = *terms.pop().unwrap();
|
||||||
|
let module_name = *terms.pop().unwrap();
|
||||||
|
|
||||||
|
let module_name = module_name
|
||||||
|
.to_constant()
|
||||||
|
.and_then(|c| c.to_atom())
|
||||||
|
.ok_or(ParserError::InvalidModuleExport)?;
|
||||||
|
|
||||||
|
let key = setup_predicate_indicator(&mut predicate_indicator)?;
|
||||||
|
|
||||||
|
Ok((module_name, key))
|
||||||
|
}
|
||||||
|
_ => Err(ParserError::InvalidModuleExport),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_module_export(
|
||||||
|
mut term: Term,
|
||||||
|
atom_tbl: TabledData<Atom>,
|
||||||
|
) -> Result<ModuleExport, ParserError> {
|
||||||
|
setup_predicate_indicator(&mut term)
|
||||||
|
.map(ModuleExport::PredicateKey)
|
||||||
|
.or_else(|_| {
|
||||||
|
if let Term::Clause(_, name, terms, _) = term {
|
||||||
|
if terms.len() == 3 && name.as_str() == "op" {
|
||||||
|
Ok(ModuleExport::OpDecl(setup_op_decl(
|
||||||
|
terms,
|
||||||
|
atom_tbl
|
||||||
|
)?))
|
||||||
|
} else {
|
||||||
|
Err(ParserError::InvalidModuleDecl)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(ParserError::InvalidModuleDecl)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_module_decl(
|
||||||
|
mut terms: Vec<Box<Term>>,
|
||||||
|
atom_tbl: TabledData<Atom>,
|
||||||
|
) -> Result<ModuleDecl, ParserError> {
|
||||||
let mut export_list = *terms.pop().unwrap();
|
let mut export_list = *terms.pop().unwrap();
|
||||||
let name = terms
|
let name = terms
|
||||||
.pop()
|
.pop()
|
||||||
@@ -230,10 +304,12 @@ fn setup_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleDecl, ParserErro
|
|||||||
.and_then(|c| c.to_atom())
|
.and_then(|c| c.to_atom())
|
||||||
.ok_or(ParserError::InvalidModuleDecl)?;
|
.ok_or(ParserError::InvalidModuleDecl)?;
|
||||||
|
|
||||||
let mut exports = Vec::new();
|
let mut exports = vec![];
|
||||||
|
|
||||||
while let Term::Cons(_, t1, t2) = export_list {
|
while let Term::Cons(_, t1, t2) = export_list {
|
||||||
exports.push(setup_predicate_indicator(*t1)?);
|
let module_export = setup_module_export(*t1, atom_tbl.clone())?;
|
||||||
|
|
||||||
|
exports.push(module_export);
|
||||||
export_list = *t2;
|
export_list = *t2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,14 +333,18 @@ fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, Pars
|
|||||||
.map(|c| ModuleSource::Library(c))
|
.map(|c| ModuleSource::Library(c))
|
||||||
.ok_or(ParserError::InvalidUseModuleDecl)
|
.ok_or(ParserError::InvalidUseModuleDecl)
|
||||||
}
|
}
|
||||||
Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
|
Term::Constant(_, Constant::Atom(ref name, _)) =>
|
||||||
|
Ok(ModuleSource::File(name.clone())),
|
||||||
_ => Err(ParserError::InvalidUseModuleDecl),
|
_ => Err(ParserError::InvalidUseModuleDecl),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type UseModuleExport = (ModuleSource, Vec<PredicateKey>);
|
type UseModuleExport = (ModuleSource, Vec<ModuleExport>);
|
||||||
|
|
||||||
fn setup_qualified_import(mut terms: Vec<Box<Term>>) -> Result<UseModuleExport, ParserError> {
|
fn setup_qualified_import(
|
||||||
|
mut terms: Vec<Box<Term>>,
|
||||||
|
atom_tbl: TabledData<Atom>,
|
||||||
|
) -> Result<UseModuleExport, ParserError> {
|
||||||
let mut export_list = *terms.pop().unwrap();
|
let mut export_list = *terms.pop().unwrap();
|
||||||
let module_src = match *terms.pop().unwrap() {
|
let module_src = match *terms.pop().unwrap() {
|
||||||
Term::Clause(_, ref name, ref mut terms, None)
|
Term::Clause(_, ref name, ref mut terms, None)
|
||||||
@@ -282,10 +362,10 @@ fn setup_qualified_import(mut terms: Vec<Box<Term>>) -> Result<UseModuleExport,
|
|||||||
_ => Err(ParserError::InvalidUseModuleDecl),
|
_ => Err(ParserError::InvalidUseModuleDecl),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
let mut exports = Vec::new();
|
let mut exports = vec![];
|
||||||
|
|
||||||
while let Term::Cons(_, t1, t2) = export_list {
|
while let Term::Cons(_, t1, t2) = export_list {
|
||||||
exports.push(setup_predicate_indicator(*t1)?);
|
exports.push(setup_module_export(*t1, atom_tbl.clone())?);
|
||||||
export_list = *t2;
|
export_list = *t2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,14 +376,8 @@ fn setup_qualified_import(mut terms: Vec<Box<Term>>) -> Result<UseModuleExport,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_consistent(tl: &TopLevel, clauses: &Vec<PredicateClause>) -> bool {
|
fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError>
|
||||||
match clauses.first() {
|
{
|
||||||
Some(ref cl) => tl.name() == cl.name() && tl.arity() == cl.arity(),
|
|
||||||
None => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError> {
|
|
||||||
let mut clauses: Vec<PredicateClause> = vec![];
|
let mut clauses: Vec<PredicateClause> = vec![];
|
||||||
|
|
||||||
while let Some(tl) = tls.pop_front() {
|
while let Some(tl) = tls.pop_front() {
|
||||||
@@ -311,20 +385,21 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError>
|
|||||||
TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => return Ok(tl),
|
TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => return Ok(tl),
|
||||||
TopLevel::Declaration(_) if clauses.is_empty() => return Ok(tl),
|
TopLevel::Declaration(_) if clauses.is_empty() => return Ok(tl),
|
||||||
TopLevel::Query(_) => return Err(ParserError::InconsistentEntry),
|
TopLevel::Query(_) => return Err(ParserError::InconsistentEntry),
|
||||||
TopLevel::Fact(..) if is_consistent(&tl, &clauses) =>
|
TopLevel::Fact(..) => {
|
||||||
if let TopLevel::Fact(fact, line_num, col_num) = tl {
|
if let TopLevel::Fact(fact, line_num, col_num) = tl {
|
||||||
let clause = PredicateClause::Fact(fact, line_num, col_num);
|
let clause = PredicateClause::Fact(fact, line_num, col_num);
|
||||||
clauses.push(clause);
|
clauses.push(clause);
|
||||||
},
|
}
|
||||||
TopLevel::Rule(..) if is_consistent(&tl, &clauses) => {
|
}
|
||||||
|
TopLevel::Rule(..) => {
|
||||||
if let TopLevel::Rule(rule, line_num, col_num) = tl {
|
if let TopLevel::Rule(rule, line_num, col_num) = tl {
|
||||||
let clause = PredicateClause::Rule(rule, line_num, col_num);
|
let clause = PredicateClause::Rule(rule, line_num, col_num);
|
||||||
clauses.push(clause);
|
clauses.push(clause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TopLevel::Predicate(_) if is_consistent(&tl, &clauses) => {
|
TopLevel::Predicate(..) => {
|
||||||
if let TopLevel::Predicate(pred) = tl {
|
if let TopLevel::Predicate(predicate) = tl {
|
||||||
clauses.extend(pred.clauses().into_iter())
|
clauses.extend(predicate.clauses().into_iter())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -341,10 +416,6 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_preds(preds: &mut Vec<PredicateClause>) -> Predicate {
|
|
||||||
Predicate(mem::replace(preds, vec![]))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
|
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
|
||||||
for term in terms.iter_mut() {
|
for term in terms.iter_mut() {
|
||||||
match term {
|
match term {
|
||||||
@@ -410,6 +481,7 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tail_term = conq_terms.pop_back().unwrap();
|
let tail_term = conq_terms.pop_back().unwrap();
|
||||||
|
|
||||||
terms.push(fold_by_str(
|
terms.push(fold_by_str(
|
||||||
conq_terms.into_iter(),
|
conq_terms.into_iter(),
|
||||||
tail_term,
|
tail_term,
|
||||||
@@ -445,6 +517,78 @@ fn flatten_hook(mut term: Term) -> Term {
|
|||||||
term
|
term
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_from_term_dir_impl(
|
||||||
|
term_dir: &TermDir,
|
||||||
|
term_dirs: &mut TermDirQuantum,
|
||||||
|
key: &PredicateKey,
|
||||||
|
preds: &mut Vec<PredicateClause>,
|
||||||
|
queue: &mut VecDeque<TopLevel>
|
||||||
|
) {
|
||||||
|
if let Some(entry) = term_dirs.get_mut(key) {
|
||||||
|
if entry.is_fresh {
|
||||||
|
entry.is_fresh = false;
|
||||||
|
|
||||||
|
(entry.new_terms.0).0.extend(preds.drain(0 ..));
|
||||||
|
entry.new_terms.1.extend(queue.drain(0 ..));
|
||||||
|
|
||||||
|
*preds = (entry.old_terms.0).0
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.chain((entry.new_terms.0).0.iter().cloned())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
*queue = entry.old_terms.1
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.chain(entry.new_terms.1.iter().cloned())
|
||||||
|
.collect();
|
||||||
|
} else {
|
||||||
|
*entry = TermDirQuantumEntry::new();
|
||||||
|
}
|
||||||
|
} else if term_dir.contains_key(key) {
|
||||||
|
let entry = TermDirQuantumEntry::from(&Predicate::new(), &VecDeque::new());
|
||||||
|
term_dirs.insert(key.clone(), entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_from_term_dir<R: Read>(
|
||||||
|
indices: &CompositeIndices<R>,
|
||||||
|
intra_module_term_dirs: &mut IndexMap<ClauseName, TermDirQuantum>,
|
||||||
|
top_level_term_dirs: &mut TermDirQuantum,
|
||||||
|
key: &PredicateKey,
|
||||||
|
preds: &mut Vec<PredicateClause>,
|
||||||
|
queue: &mut VecDeque<TopLevel>,
|
||||||
|
) {
|
||||||
|
let module = key.0.owning_module();
|
||||||
|
|
||||||
|
// aaarghhh..
|
||||||
|
match indices.term_stream.wam.indices.in_situ_module_dir.get(&module) {
|
||||||
|
// modify module_stub to do this right.
|
||||||
|
Some(ref module_stub) if key.0.has_table(&module_stub.atom_tbl) => {
|
||||||
|
if let Some(ref mut term_dirs) = intra_module_term_dirs.get_mut(&module) {
|
||||||
|
if let Some(ref module) = indices.term_stream.wam.indices.modules.get(&module) {
|
||||||
|
return draw_from_term_dir_impl(
|
||||||
|
&module.term_dir,
|
||||||
|
term_dirs,
|
||||||
|
key,
|
||||||
|
preds,
|
||||||
|
queue,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_from_term_dir_impl(
|
||||||
|
&indices.term_stream.wam.code_repo.term_dir,
|
||||||
|
top_level_term_dirs,
|
||||||
|
key,
|
||||||
|
preds,
|
||||||
|
queue,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn setup_declaration<'a, 'b, 'c, R: Read>(
|
fn setup_declaration<'a, 'b, 'c, R: Read>(
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||||
flags: MachineFlags,
|
flags: MachineFlags,
|
||||||
@@ -457,22 +601,8 @@ fn setup_declaration<'a, 'b, 'c, R: Read>(
|
|||||||
match term {
|
match term {
|
||||||
Term::Clause(_, name, mut terms, _) =>
|
Term::Clause(_, name, mut terms, _) =>
|
||||||
match (name.as_str(), terms.len()) {
|
match (name.as_str(), terms.len()) {
|
||||||
("op", 3) =>
|
|
||||||
Ok(Declaration::Op(setup_op_decl(terms, indices.atom_tbl())?)),
|
|
||||||
("module", 2) =>
|
|
||||||
Ok(Declaration::Module(setup_module_decl(terms)?)),
|
|
||||||
("use_module", 1) =>
|
|
||||||
Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
|
|
||||||
("use_module", 2) => {
|
|
||||||
let (name, exports) = setup_qualified_import(terms)?;
|
|
||||||
Ok(Declaration::UseQualifiedModule(name, exports))
|
|
||||||
}
|
|
||||||
("non_counted_backtracking", 1) => {
|
|
||||||
let (name, arity) = setup_predicate_indicator(*terms.pop().unwrap())?;
|
|
||||||
Ok(Declaration::NonCountedBacktracking(name, arity))
|
|
||||||
}
|
|
||||||
("dynamic", 1) => {
|
("dynamic", 1) => {
|
||||||
let (name, arity) = setup_predicate_indicator(*terms.pop().unwrap())?;
|
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
|
||||||
Ok(Declaration::Dynamic(name, arity))
|
Ok(Declaration::Dynamic(name, arity))
|
||||||
}
|
}
|
||||||
("initialization", 1) => {
|
("initialization", 1) => {
|
||||||
@@ -482,10 +612,39 @@ fn setup_declaration<'a, 'b, 'c, R: Read>(
|
|||||||
|
|
||||||
Ok(Declaration::ModuleInitialization(query_terms, queue))
|
Ok(Declaration::ModuleInitialization(query_terms, queue))
|
||||||
}
|
}
|
||||||
_ =>
|
("module", 2) =>
|
||||||
|
Ok(Declaration::Module(setup_module_decl(terms, indices.atom_tbl())?)),
|
||||||
|
("op", 3) =>
|
||||||
|
Ok(Declaration::Op(setup_op_decl(terms, indices.atom_tbl())?)),
|
||||||
|
("non_counted_backtracking", 1) => {
|
||||||
|
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
|
||||||
|
Ok(Declaration::NonCountedBacktracking(name, arity))
|
||||||
|
}
|
||||||
|
("multifile", 1) => {
|
||||||
|
let mut term = *terms.pop().unwrap();
|
||||||
|
|
||||||
|
match setup_predicate_indicator(&mut term) {
|
||||||
|
Ok((name, arity)) =>
|
||||||
|
Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity))),
|
||||||
|
_ =>
|
||||||
|
setup_scoped_predicate_indicator(&mut term)
|
||||||
|
.map(|key| {
|
||||||
|
Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
("use_module", 1) => {
|
||||||
|
Ok(Declaration::UseModule(setup_use_module_decl(terms)?))
|
||||||
|
}
|
||||||
|
("use_module", 2) => {
|
||||||
|
let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?;
|
||||||
|
Ok(Declaration::UseQualifiedModule(name, exports))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
Err(ParserError::InconsistentEntry)
|
Err(ParserError::InconsistentEntry)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => return Err(ParserError::InconsistentEntry),
|
_ => Err(ParserError::InconsistentEntry),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,7 +722,7 @@ impl RelationWorker {
|
|||||||
|
|
||||||
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
||||||
let vars = self.compute_head(&body_term);
|
let vars = self.compute_head(&body_term);
|
||||||
let clauses: Vec<_> = unfold_by_str(body_term, ";")
|
let results = unfold_by_str(body_term, ";")
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|term| {
|
.map(|term| {
|
||||||
let mut subterms = unfold_by_str(term, ",");
|
let mut subterms = unfold_by_str(term, ",");
|
||||||
@@ -572,13 +731,10 @@ impl RelationWorker {
|
|||||||
check_for_internal_if_then(&mut subterms);
|
check_for_internal_if_then(&mut subterms);
|
||||||
|
|
||||||
let term = subterms.pop().unwrap();
|
let term = subterms.pop().unwrap();
|
||||||
fold_by_str(subterms.into_iter(), term, clause_name!(","))
|
let clause = fold_by_str(subterms.into_iter(), term, clause_name!(","));
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let results = clauses
|
self.fabricate_rule_body(&vars, clause)
|
||||||
.into_iter()
|
})
|
||||||
.map(|clause| self.fabricate_rule_body(&vars, clause))
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
(vars, results)
|
(vars, results)
|
||||||
@@ -645,6 +801,26 @@ impl RelationWorker {
|
|||||||
self.queue.push_back(clauses);
|
self.queue.push_back(clauses);
|
||||||
Ok(QueryTerm::Jump(stub))
|
Ok(QueryTerm::Jump(stub))
|
||||||
}
|
}
|
||||||
|
("\\+", 1) => {
|
||||||
|
terms.push(Box::new(Term::Constant(
|
||||||
|
Cell::default(),
|
||||||
|
Constant::Atom(clause_name!("$fail"), None)
|
||||||
|
)));
|
||||||
|
|
||||||
|
let conq = Term::Constant(
|
||||||
|
Cell::default(),
|
||||||
|
Constant::Atom(clause_name!("true"), None)
|
||||||
|
);
|
||||||
|
|
||||||
|
let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None);
|
||||||
|
let terms = vec![Box::new(prec), Box::new(conq)];
|
||||||
|
|
||||||
|
let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
|
||||||
|
let (stub, clauses) = self.fabricate_disjunct(term);
|
||||||
|
|
||||||
|
self.queue.push_back(clauses);
|
||||||
|
Ok(QueryTerm::Jump(stub))
|
||||||
|
}
|
||||||
("$get_level", 1) => {
|
("$get_level", 1) => {
|
||||||
if let Term::Var(_, ref var) = *terms[0] {
|
if let Term::Var(_, ref var) = *terms[0] {
|
||||||
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
|
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
|
||||||
@@ -652,15 +828,11 @@ impl RelationWorker {
|
|||||||
Err(ParserError::InadmissibleQueryTerm)
|
Err(ParserError::InadmissibleQueryTerm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("partial_string", 2) => {
|
|
||||||
let ct = ClauseType::BuiltIn(BuiltInClauseType::PartialString);
|
|
||||||
return Ok(QueryTerm::Clause(Cell::default(), ct, terms, false));
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
let ct = indices.get_clause_type(name, terms.len(), fixity);
|
let ct = indices.get_clause_type(name, terms.len(), fixity);
|
||||||
Ok(QueryTerm::Clause(Cell::default(), ct, terms, false))
|
Ok(QueryTerm::Clause(Cell::default(), ct, terms, false))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Term::Var(..) => Ok(QueryTerm::Clause(
|
Term::Var(..) => Ok(QueryTerm::Clause(
|
||||||
Cell::default(),
|
Cell::default(),
|
||||||
ClauseType::CallN,
|
ClauseType::CallN,
|
||||||
@@ -723,11 +895,11 @@ impl RelationWorker {
|
|||||||
if name.as_str() == "," {
|
if name.as_str() == "," {
|
||||||
let term = Term::Clause(cell, name, terms, op_spec);
|
let term = Term::Clause(cell, name, terms, op_spec);
|
||||||
let mut subterms = unfold_by_str(term, ",");
|
let mut subterms = unfold_by_str(term, ",");
|
||||||
|
|
||||||
while let Some(subterm) = subterms.pop() {
|
while let Some(subterm) = subterms.pop() {
|
||||||
work_queue.push_front(Box::new(subterm));
|
work_queue.push_front(Box::new(subterm));
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
term = Term::Clause(cell, name, terms, op_spec);
|
term = Term::Clause(cell, name, terms, op_spec);
|
||||||
@@ -741,7 +913,7 @@ impl RelationWorker {
|
|||||||
query_terms.push(self.pre_query_term(indices, term)?);
|
query_terms.push(self.pre_query_term(indices, term)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(query_terms)
|
Ok(query_terms)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -815,6 +987,34 @@ impl RelationWorker {
|
|||||||
)?))
|
)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compact_module_scoped_head<'a, 'b, 'c, R: Read>(
|
||||||
|
&self,
|
||||||
|
term: &mut Term,
|
||||||
|
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||||
|
) {
|
||||||
|
let inner_term = match term {
|
||||||
|
Term::Clause(_, ref name, ref mut inner_terms, _)
|
||||||
|
if name.as_str() == ":" && inner_terms.len() == 2 => {
|
||||||
|
let module_name = match inner_terms[0].as_ref() {
|
||||||
|
&Term::Constant(_, Constant::Atom(ref module, _)) => {
|
||||||
|
module.clone()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
indices.add_in_situ_module_info(module_name, inner_terms[1].deref_mut());
|
||||||
|
*inner_terms.pop().unwrap()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
*term = inner_term;
|
||||||
|
}
|
||||||
|
|
||||||
fn try_term_to_tl<'a, 'b, 'c, R: Read>(
|
fn try_term_to_tl<'a, 'b, 'c, R: Read>(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
||||||
@@ -822,7 +1022,7 @@ impl RelationWorker {
|
|||||||
blocks_cuts: bool,
|
blocks_cuts: bool,
|
||||||
) -> Result<TopLevel, ParserError> {
|
) -> Result<TopLevel, ParserError> {
|
||||||
match term {
|
match term {
|
||||||
Term::Clause(r, name, terms, fixity) => {
|
Term::Clause(r, name, mut terms, fixity) => {
|
||||||
if let Some(hook) = is_compile_time_hook(&name, &terms) {
|
if let Some(hook) = is_compile_time_hook(&name, &terms) {
|
||||||
let term = Term::Clause(r, name, terms, fixity);
|
let term = Term::Clause(r, name, terms, fixity);
|
||||||
let (hook, clause, queue) = self.setup_hook(hook, indices, term)?;
|
let (hook, clause, queue) = self.setup_hook(hook, indices, term)?;
|
||||||
@@ -833,6 +1033,8 @@ impl RelationWorker {
|
|||||||
} else if name.as_str() == "?-" {
|
} else if name.as_str() == "?-" {
|
||||||
self.try_term_to_query(indices, terms, blocks_cuts)
|
self.try_term_to_query(indices, terms, blocks_cuts)
|
||||||
} else if name.as_str() == ":-" && terms.len() == 2 {
|
} else if name.as_str() == ":-" && terms.len() == 2 {
|
||||||
|
self.compact_module_scoped_head(&mut terms[0], indices);
|
||||||
|
|
||||||
Ok(TopLevel::Rule(self.setup_rule(
|
Ok(TopLevel::Rule(self.setup_rule(
|
||||||
indices,
|
indices,
|
||||||
terms,
|
terms,
|
||||||
@@ -843,11 +1045,14 @@ impl RelationWorker {
|
|||||||
Ok(TopLevel::Declaration(setup_declaration(indices, self.flags, terms,
|
Ok(TopLevel::Declaration(setup_declaration(indices, self.flags, terms,
|
||||||
self.line_num, self.col_num)?))
|
self.line_num, self.col_num)?))
|
||||||
} else {
|
} else {
|
||||||
let term = Term::Clause(r, name, terms, fixity);
|
let mut term = Term::Clause(r, name, terms, fixity);
|
||||||
|
self.compact_module_scoped_head(&mut term, indices);
|
||||||
|
|
||||||
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
|
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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -890,7 +1095,9 @@ impl RelationWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type DynamicClauseMap = IndexMap<(ClauseName, usize), Vec<(Term, Term)>>;
|
pub type DynamicClause = Vec<(Term, Term)>;
|
||||||
|
|
||||||
|
pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>;
|
||||||
|
|
||||||
pub struct TopLevelBatchWorker<'a, R: Read> {
|
pub struct TopLevelBatchWorker<'a, R: Read> {
|
||||||
pub(crate) term_stream: TermStream<'a, R>,
|
pub(crate) term_stream: TermStream<'a, R>,
|
||||||
@@ -898,6 +1105,9 @@ pub struct TopLevelBatchWorker<'a, R: Read> {
|
|||||||
pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>,
|
pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>,
|
||||||
pub(crate) dynamic_clause_map: DynamicClauseMap,
|
pub(crate) dynamic_clause_map: DynamicClauseMap,
|
||||||
pub(crate) in_module: bool,
|
pub(crate) in_module: bool,
|
||||||
|
pub(crate) term_dirs: TermDirQuantum,
|
||||||
|
pub(crate) intra_module_term_dirs: IndexMap<ClauseName, TermDirQuantum>,
|
||||||
|
pub(crate) non_counted_bt_preds: IndexSet<PredicateKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
||||||
@@ -918,6 +1128,9 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
|||||||
results: vec![],
|
results: vec![],
|
||||||
dynamic_clause_map: IndexMap::new(),
|
dynamic_clause_map: IndexMap::new(),
|
||||||
in_module: false,
|
in_module: false,
|
||||||
|
term_dirs: TermDirQuantum::new(),
|
||||||
|
intra_module_term_dirs: IndexMap::new(),
|
||||||
|
non_counted_bt_preds: IndexSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,18 +1163,30 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
|||||||
let mut indices = CompositeIndices::new(
|
let mut indices = CompositeIndices::new(
|
||||||
&mut self.term_stream,
|
&mut self.term_stream,
|
||||||
IndexSource::Local(indices),
|
IndexSource::Local(indices),
|
||||||
if self.in_module { None } else { Some(IndexSource::TermStream) }
|
if self.in_module { None } else { Some(IndexSource::TermStream) },
|
||||||
);
|
);
|
||||||
|
|
||||||
let queue = self.rel_worker.parse_queue(&mut indices)?;
|
let key = (preds[0].name().unwrap(), preds[0].arity());
|
||||||
let result = (append_preds(preds), queue);
|
|
||||||
|
|
||||||
let in_situ_code_dir = &mut indices.term_stream.wam.indices.in_situ_code_dir;
|
let mut preds = mem::replace(preds, vec![]);
|
||||||
|
let mut queue = self.rel_worker.parse_queue(&mut indices)?;
|
||||||
|
|
||||||
|
draw_from_term_dir(
|
||||||
|
&indices,
|
||||||
|
&mut self.intra_module_term_dirs,
|
||||||
|
&mut self.term_dirs,
|
||||||
|
&key,
|
||||||
|
&mut preds,
|
||||||
|
&mut queue,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = (Predicate(preds), queue);
|
||||||
|
|
||||||
indices.term_stream.wam.code_repo.add_in_situ_result(
|
indices.term_stream.wam.code_repo.add_in_situ_result(
|
||||||
&result,
|
&result,
|
||||||
in_situ_code_dir,
|
&mut indices.term_stream.wam.indices.in_situ_code_dir,
|
||||||
indices.term_stream.flags,
|
&mut indices.term_stream.wam.indices.in_situ_module_dir,
|
||||||
|
&self.non_counted_bt_preds,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(self.results.push(result))
|
Ok(self.results.push(result))
|
||||||
@@ -992,18 +1217,25 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
|||||||
|
|
||||||
while !self.term_stream.eof()? {
|
while !self.term_stream.eof()? {
|
||||||
let term = self.term_stream.read_term(&indices.op_dir)?;
|
let term = self.term_stream.read_term(&indices.op_dir)?;
|
||||||
|
|
||||||
|
// if is_consistent is false, preds is non-empty.
|
||||||
|
let term = if !term.is_consistent(&preds) {
|
||||||
|
self.process_result(indices, &mut preds)?;
|
||||||
|
self.take_dynamic_clauses();
|
||||||
|
|
||||||
|
// expand the term after the addition of the previous
|
||||||
|
// predicate.
|
||||||
|
self.term_stream.expand_term(term, &indices.op_dir)?
|
||||||
|
} else {
|
||||||
|
term
|
||||||
|
};
|
||||||
|
|
||||||
let (mut tl, new_rel_worker) = self.try_term_to_tl(indices, term)?;
|
let (mut tl, new_rel_worker) = self.try_term_to_tl(indices, term)?;
|
||||||
|
|
||||||
if tl.is_end_of_file_atom() {
|
if tl.is_end_of_file_atom() {
|
||||||
tl = TopLevel::Declaration(Declaration::EndOfFile);
|
tl = TopLevel::Declaration(Declaration::EndOfFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if is_consistent is false, preds is non-empty.
|
|
||||||
if !is_consistent(&tl, &preds) {
|
|
||||||
self.process_result(indices, &mut preds)?;
|
|
||||||
self.take_dynamic_clauses();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.rel_worker.absorb(new_rel_worker);
|
self.rel_worker.absorb(new_rel_worker);
|
||||||
|
|
||||||
match tl {
|
match tl {
|
||||||
|
|||||||
@@ -106,16 +106,6 @@ macro_rules! is_var {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! is_partial_string {
|
|
||||||
($r:expr) => {
|
|
||||||
call_clause!(
|
|
||||||
ClauseType::Inlined(InlinedClauseType::IsPartialString($r)),
|
|
||||||
1,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! call_clause {
|
macro_rules! call_clause {
|
||||||
($ct:expr, $arity:expr, $pvs:expr) => {
|
($ct:expr, $arity:expr, $pvs:expr) => {
|
||||||
Line::Control(ControlInstruction::CallClause(
|
Line::Control(ControlInstruction::CallClause(
|
||||||
@@ -217,7 +207,7 @@ macro_rules! return_from_clause {
|
|||||||
|
|
||||||
macro_rules! dir_entry {
|
macro_rules! dir_entry {
|
||||||
($idx:expr) => {
|
($idx:expr) => {
|
||||||
CodePtr::Local(LocalCodePtr::DirEntry($idx))
|
LocalCodePtr::DirEntry($idx)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,11 +231,13 @@ macro_rules! index_store {
|
|||||||
IndexStore {
|
IndexStore {
|
||||||
atom_tbl: $atom_tbl,
|
atom_tbl: $atom_tbl,
|
||||||
code_dir: $code_dir,
|
code_dir: $code_dir,
|
||||||
|
module_dir: ModuleDir::new(),
|
||||||
dynamic_code_dir: DynamicCodeDir::new(),
|
dynamic_code_dir: DynamicCodeDir::new(),
|
||||||
global_variables: GlobalVarDir::new(),
|
global_variables: GlobalVarDir::new(),
|
||||||
in_situ_code_dir: InSituCodeDir::new(),
|
in_situ_code_dir: InSituCodeDir::new(),
|
||||||
|
in_situ_module_dir: ModuleStubDir::new(),
|
||||||
op_dir: $op_dir,
|
op_dir: $op_dir,
|
||||||
modules: $modules,
|
modules: $modules,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
extern crate dirs;
|
extern crate dirs;
|
||||||
extern crate ordered_float;
|
extern crate ordered_float;
|
||||||
extern crate prolog_parser;
|
extern crate prolog_parser;
|
||||||
|
#[cfg(feature = "rug")]
|
||||||
extern crate rug;
|
extern crate rug;
|
||||||
extern crate rustyline;
|
#[cfg(feature = "num-rug-adapter")]
|
||||||
|
extern crate num_rug_adapter as rug;
|
||||||
|
extern crate rustyline;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ pub mod readline {
|
|||||||
use prolog_parser::ast::*;
|
use prolog_parser::ast::*;
|
||||||
use crate::prolog::rustyline::error::ReadlineError;
|
use crate::prolog::rustyline::error::ReadlineError;
|
||||||
use crate::prolog::rustyline::{Cmd, Editor, KeyPress};
|
use crate::prolog::rustyline::{Cmd, Editor, KeyPress};
|
||||||
use std::io::Read;
|
use std::io::{Cursor, Read};
|
||||||
|
|
||||||
static mut PROMPT: bool = false;
|
static mut PROMPT: bool = false;
|
||||||
|
|
||||||
@@ -48,68 +48,52 @@ pub mod readline {
|
|||||||
|
|
||||||
pub struct ReadlineStream {
|
pub struct ReadlineStream {
|
||||||
rl: Editor<()>,
|
rl: Editor<()>,
|
||||||
pending_input: String,
|
pending_input: Cursor<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadlineStream {
|
impl ReadlineStream {
|
||||||
fn input_stream(pending_input: String) -> Self {
|
fn input_stream(pending_input: String) -> Self {
|
||||||
let mut rl = Editor::<()>::new();
|
let mut rl = Editor::<()>::new();
|
||||||
rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string()));
|
rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string()));
|
||||||
ReadlineStream { rl, pending_input }
|
ReadlineStream { rl, pending_input: Cursor::new(pending_input) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
match self.rl.readline(get_prompt()) {
|
match self.rl.readline(get_prompt()) {
|
||||||
Ok(text) => {
|
Ok(text) => {
|
||||||
self.pending_input += &text;
|
*self.pending_input.get_mut() = text;
|
||||||
|
self.pending_input.set_position(0);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if PROMPT {
|
if PROMPT {
|
||||||
self.rl.history_mut().add(&self.pending_input);
|
self.rl.history_mut().add(self.pending_input.get_ref());
|
||||||
PROMPT = false;
|
PROMPT = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pending_input += "\n";
|
*self.pending_input.get_mut() += "\n";
|
||||||
Ok(self.write_to_buf(buf))
|
self.pending_input.read(buf)
|
||||||
}
|
}
|
||||||
Err(ReadlineError::Eof) =>
|
Err(ReadlineError::Eof) => {
|
||||||
Ok(self.write_to_buf(buf)),
|
Ok(0)
|
||||||
Err(e) =>
|
}
|
||||||
|
Err(e) => {
|
||||||
Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, e))
|
Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, e))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_pending(&mut self, buf: &mut [u8], split_idx: usize) -> usize {
|
|
||||||
let (outgoing, _) = self.pending_input.split_at(split_idx);
|
|
||||||
|
|
||||||
for (idx, b) in outgoing.bytes().enumerate() {
|
|
||||||
buf[idx] = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
outgoing.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_to_buf(&mut self, buf: &mut [u8]) -> usize {
|
|
||||||
let split_idx = std::cmp::min(self.pending_input.len(), buf.len());
|
|
||||||
let output_len = self.split_pending(buf, split_idx);
|
|
||||||
|
|
||||||
if split_idx < self.pending_input.len() {
|
|
||||||
self.pending_input = self.pending_input[split_idx..].to_string();
|
|
||||||
} else {
|
|
||||||
self.pending_input.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
output_len
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Read for ReadlineStream {
|
impl Read for ReadlineStream {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
if self.pending_input.is_empty() {
|
match self.pending_input.read(buf) {
|
||||||
self.call_readline(buf)
|
Ok(0) => {
|
||||||
} else {
|
self.call_readline(buf)
|
||||||
Ok(self.write_to_buf(buf))
|
}
|
||||||
|
result => {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +120,7 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn push_stub_addr(machine_st: &mut MachineState) {
|
fn push_stub_addr(machine_st: &mut MachineState) {
|
||||||
let h = machine_st.heap.h;
|
let h = machine_st.heap.h();
|
||||||
machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
|
machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,13 +145,13 @@ pub struct TermWriteResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
|
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
|
||||||
let heap_loc = machine_st.heap.h;
|
let heap_loc = machine_st.heap.h();
|
||||||
|
|
||||||
let mut queue = SubtermDeque::new();
|
let mut queue = SubtermDeque::new();
|
||||||
let mut var_dict = HeapVarDict::new();
|
let mut var_dict = HeapVarDict::new();
|
||||||
|
|
||||||
for term in breadth_first_iter(term, true) {
|
for term in breadth_first_iter(term, true) {
|
||||||
let h = machine_st.heap.h;
|
let h = machine_st.heap.h();
|
||||||
|
|
||||||
match &term {
|
match &term {
|
||||||
&TermRef::Cons(lvl, ..) => {
|
&TermRef::Cons(lvl, ..) => {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
:- module('$toplevel', ['$repl'/1, consult/1, use_module/1, use_module/2]).
|
|
||||||
|
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
:- use_module(library(si)).
|
:- use_module(library(si)).
|
||||||
|
|
||||||
|
:- module('$toplevel', ['$repl'/1, consult/1, use_module/1, use_module/2]).
|
||||||
|
|
||||||
'$repl'(ListOfModules) :-
|
'$repl'(ListOfModules) :-
|
||||||
maplist('$use_list_of_modules', ListOfModules),
|
maplist('$use_list_of_modules', ListOfModules),
|
||||||
false.
|
false.
|
||||||
@@ -14,7 +14,8 @@
|
|||||||
'$repl' :-
|
'$repl' :-
|
||||||
catch('$read_and_match', E, '$print_exception'(E)),
|
catch('$read_and_match', E, '$print_exception'(E)),
|
||||||
false. %% this is for GC, until we get actual GC.
|
false. %% this is for GC, until we get actual GC.
|
||||||
'$repl' :- '$repl'.
|
'$repl' :-
|
||||||
|
'$repl'.
|
||||||
|
|
||||||
'$read_and_match' :-
|
'$read_and_match' :-
|
||||||
'$read_query_term'(Term, VarList),
|
'$read_query_term'(Term, VarList),
|
||||||
@@ -29,7 +30,9 @@
|
|||||||
catch('$$compile_batch', E, '$print_exception_with_check'(E))
|
catch('$$compile_batch', E, '$print_exception_with_check'(E))
|
||||||
; consult(Item)
|
; consult(Item)
|
||||||
)
|
)
|
||||||
; catch(throw(error(type_error(atom, Item), repl/0)),
|
; !,
|
||||||
|
catch(throw(error(type_error(atom, Item), repl/0)),
|
||||||
|
E,
|
||||||
'$print_exception_with_check'(E))
|
'$print_exception_with_check'(E))
|
||||||
).
|
).
|
||||||
'$instruction_match'(Term, VarList) :-
|
'$instruction_match'(Term, VarList) :-
|
||||||
@@ -38,17 +41,55 @@
|
|||||||
|
|
||||||
'$submit_query_and_print_results'(Term0, VarList) :-
|
'$submit_query_and_print_results'(Term0, VarList) :-
|
||||||
( expand_goals(Term0, Term) -> true
|
( expand_goals(Term0, Term) -> true
|
||||||
; Term = Term0
|
; Term0 = Term
|
||||||
),
|
),
|
||||||
( '$get_b_value'(B), call(Term), '$write_eqs_and_read_input'(B, VarList), !
|
( '$get_b_value'(B), call(Term), '$write_eqs_and_read_input'(B, VarList),
|
||||||
; write('false.'), nl
|
!
|
||||||
|
% clear attribute goal lists, which may be populated by
|
||||||
|
% copy_term/3 prior to failure.
|
||||||
|
; '$clear_attribute_goals', write('false.'), nl
|
||||||
|
).
|
||||||
|
|
||||||
|
'$needs_bracketing'(Value, Op) :-
|
||||||
|
catch((functor(Value, F, _),
|
||||||
|
current_op(EqPrec, EqSpec, Op),
|
||||||
|
current_op(FPrec, _, F)),
|
||||||
|
_,
|
||||||
|
false),
|
||||||
|
( EqPrec < FPrec -> true
|
||||||
|
; EqPrec == FPrec,
|
||||||
|
memberchk(EqSpec, [fx,xfx,yfx])
|
||||||
).
|
).
|
||||||
|
|
||||||
'$write_goal'(G, VarList) :-
|
'$write_goal'(G, VarList) :-
|
||||||
( G = (Var = Value) ->
|
( G = (Var = Value) ->
|
||||||
write(Var),
|
write(Var),
|
||||||
write(' = '),
|
write(' = '),
|
||||||
write_term(Value, [quoted(true), variable_names(VarList)])
|
( '$needs_bracketing'(Value, (=)) ->
|
||||||
|
write('('),
|
||||||
|
write_term(Value, [quoted(true), variable_names(VarList)]),
|
||||||
|
write(')')
|
||||||
|
; write_term(Value, [quoted(true), variable_names(VarList)])
|
||||||
|
)
|
||||||
|
; G == [] ->
|
||||||
|
write('true')
|
||||||
|
; write_term(G, [quoted(true), variable_names(VarList)])
|
||||||
|
).
|
||||||
|
|
||||||
|
'$write_last_goal'(G, VarList) :-
|
||||||
|
( G = (Var = Value) ->
|
||||||
|
write(Var),
|
||||||
|
write(' = '),
|
||||||
|
( '$needs_bracketing'(Value, (=)) ->
|
||||||
|
write('('),
|
||||||
|
write_term(Value, [quoted(true), variable_names(VarList)]),
|
||||||
|
write(')')
|
||||||
|
; write_term(Value, [quoted(true), variable_names(VarList)]),
|
||||||
|
( '$trailing_period_is_ambiguous'(Value) ->
|
||||||
|
write(' ')
|
||||||
|
; true
|
||||||
|
)
|
||||||
|
)
|
||||||
; G == [] ->
|
; G == [] ->
|
||||||
write('true')
|
write('true')
|
||||||
; write_term(G, [quoted(true), variable_names(VarList)])
|
; write_term(G, [quoted(true), variable_names(VarList)])
|
||||||
@@ -60,7 +101,21 @@
|
|||||||
write(', '),
|
write(', '),
|
||||||
'$write_eq'(G2, VarList).
|
'$write_eq'(G2, VarList).
|
||||||
'$write_eq'(G, VarList) :-
|
'$write_eq'(G, VarList) :-
|
||||||
'$write_goal'(G, VarList).
|
'$write_last_goal'(G, VarList).
|
||||||
|
|
||||||
|
'$graphic_token_char'(C) :-
|
||||||
|
memberchk(C, ['#', '$', '&', '*', '+', '-', '.', ('/'), ':',
|
||||||
|
'<', '=', '>', '?', '@', '^', '~', ('\\')]).
|
||||||
|
|
||||||
|
'$list_last_item'([C], C) :- !.
|
||||||
|
'$list_last_item'([_|Cs], D) :-
|
||||||
|
'$list_last_item'(Cs, D).
|
||||||
|
|
||||||
|
'$trailing_period_is_ambiguous'(Value) :-
|
||||||
|
atom(Value),
|
||||||
|
atom_chars(Value, ValueChars),
|
||||||
|
'$list_last_item'(ValueChars, Char),
|
||||||
|
'$graphic_token_char'(Char).
|
||||||
|
|
||||||
'$write_eqs_and_read_input'(B, VarList) :-
|
'$write_eqs_and_read_input'(B, VarList) :-
|
||||||
sort(VarList, SortedVarList),
|
sort(VarList, SortedVarList),
|
||||||
@@ -71,11 +126,10 @@
|
|||||||
write('true.'), nl
|
write('true.'), nl
|
||||||
; thread_goals(Goals, ThreadedGoals, (',')),
|
; thread_goals(Goals, ThreadedGoals, (',')),
|
||||||
'$write_eq'(ThreadedGoals, VarList),
|
'$write_eq'(ThreadedGoals, VarList),
|
||||||
write(' .'),
|
write('.'),
|
||||||
nl
|
nl
|
||||||
)
|
)
|
||||||
; repeat,
|
; thread_goals(Goals, ThreadedGoals, (',')),
|
||||||
thread_goals(Goals, ThreadedGoals, (',')),
|
|
||||||
'$write_eq'(ThreadedGoals, VarList),
|
'$write_eq'(ThreadedGoals, VarList),
|
||||||
'$raw_input_read_char'(C),
|
'$raw_input_read_char'(C),
|
||||||
( C == (';'), !,
|
( C == (';'), !,
|
||||||
@@ -93,13 +147,20 @@
|
|||||||
).
|
).
|
||||||
'$gather_query_vars'([], []).
|
'$gather_query_vars'([], []).
|
||||||
|
|
||||||
|
'$is_a_different_variable'([_ = Binding | Pairs], Value) :-
|
||||||
|
( Value == Binding, !
|
||||||
|
; '$is_a_different_variable'(Pairs, Value)
|
||||||
|
).
|
||||||
|
|
||||||
'$gather_goals'([], VarList, Goals) :-
|
'$gather_goals'([], VarList, Goals) :-
|
||||||
'$get_attr_var_queue_beyond'(0, AttrVars),
|
'$get_attr_var_queue_beyond'(0, AttrVars),
|
||||||
'$gather_query_vars'(VarList, QueryVars),
|
'$gather_query_vars'(VarList, QueryVars),
|
||||||
'$call_attribute_goals'(QueryVars, AttrVars),
|
'$call_attribute_goals'(QueryVars, AttrVars),
|
||||||
'$fetch_attribute_goals'(Goals).
|
'$fetch_attribute_goals'(Goals).
|
||||||
'$gather_goals'([Var = Value | Pairs], VarList, Goals) :-
|
'$gather_goals'([Var = Value | Pairs], VarList, Goals) :-
|
||||||
( nonvar(Value) ->
|
( ( nonvar(Value)
|
||||||
|
; '$is_a_different_variable'(Pairs, Value)
|
||||||
|
) ->
|
||||||
Goals = [Var = Value | Goals0],
|
Goals = [Var = Value | Goals0],
|
||||||
'$gather_goals'(Pairs, VarList, Goals0)
|
'$gather_goals'(Pairs, VarList, Goals0)
|
||||||
; '$gather_goals'(Pairs, VarList, Goals)
|
; '$gather_goals'(Pairs, VarList, Goals)
|
||||||
@@ -117,7 +178,7 @@
|
|||||||
; '$print_exception'(E)
|
; '$print_exception'(E)
|
||||||
).
|
).
|
||||||
|
|
||||||
'$predicate_indicator'(Source, PI) :-
|
'$module_export'(Source, PI) :-
|
||||||
( nonvar(PI) ->
|
( nonvar(PI) ->
|
||||||
( PI = Name / Arity ->
|
( PI = Name / Arity ->
|
||||||
( var(Name) -> throw(error(instantiation_error, Source))
|
( var(Name) -> throw(error(instantiation_error, Source))
|
||||||
@@ -128,7 +189,20 @@
|
|||||||
)
|
)
|
||||||
; throw(error(type_error(integer, Arity), Source))
|
; throw(error(type_error(integer, Arity), Source))
|
||||||
)
|
)
|
||||||
; throw(error(type_error(predicate_indicator, PI), Source))
|
; PI = op(Prec, Spec, Name) ->
|
||||||
|
( integer(Prec) ->
|
||||||
|
( \+ atom(Name) ->
|
||||||
|
throw(error(type_error(atom, Name), Source))
|
||||||
|
; Prec < 0 ->
|
||||||
|
throw(error(domain_error(not_less_than_zero, Prec), Source))
|
||||||
|
; Prec > 1200 ->
|
||||||
|
throw(error(domain_error(operator_precision, Prec), Source))
|
||||||
|
; memberchk(Spec, [xfy, yfx, xfx, fx, fy, yf, xf])
|
||||||
|
; throw(error(domain_error(operator_specification, Spec), Source))
|
||||||
|
)
|
||||||
|
; throw(error(type_error(integer, Prec), Source))
|
||||||
|
)
|
||||||
|
; throw(error(type_error(module_export, PI), Source))
|
||||||
)
|
)
|
||||||
; throw(error(instantiation_error, Source))
|
; throw(error(instantiation_error, Source))
|
||||||
).
|
).
|
||||||
@@ -150,9 +224,11 @@ use_module(Module) :-
|
|||||||
use_module(Module, QualifiedExports) :-
|
use_module(Module, QualifiedExports) :-
|
||||||
( nonvar(Module) ->
|
( nonvar(Module) ->
|
||||||
( list_si(QualifiedExports) ->
|
( list_si(QualifiedExports) ->
|
||||||
maplist('$predicate_indicator'(use_module/2), QualifiedExports), !,
|
maplist('$module_export'(use_module/2), QualifiedExports) ->
|
||||||
( Module = library(Filename) -> '$use_qualified_module'(Filename, QualifiedExports)
|
( Module = library(Filename) ->
|
||||||
; atom(Module) -> '$use_qualified_module_from_file'(Module, QualifiedExports)
|
'$use_qualified_module'(Filename, QualifiedExports)
|
||||||
|
; atom(Module) ->
|
||||||
|
'$use_qualified_module_from_file'(Module, QualifiedExports)
|
||||||
; throw(error(invalid_module_specifier, use_module/2))
|
; throw(error(invalid_module_specifier, use_module/2))
|
||||||
)
|
)
|
||||||
; throw(error(type_error(list, QualifiedExports), use_module/2))
|
; throw(error(type_error(list, QualifiedExports), use_module/2))
|
||||||
@@ -160,6 +236,7 @@ use_module(Module, QualifiedExports) :-
|
|||||||
; throw(error(instantiation_error, use_module/2))
|
; throw(error(instantiation_error, use_module/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
% expand goals in initialization directives.
|
% expand goals in initialization directives.
|
||||||
user:term_expansion(Term0, (:- initialization(ExpandedGoals))) :-
|
user:term_expansion(Term0, (:- initialization(ExpandedGoals))) :-
|
||||||
nonvar(Term0),
|
nonvar(Term0),
|
||||||
@@ -167,15 +244,24 @@ user:term_expansion(Term0, (:- initialization(ExpandedGoals))) :-
|
|||||||
expand_goals(Goals, ExpandedGoals),
|
expand_goals(Goals, ExpandedGoals),
|
||||||
Goals \== ExpandedGoals.
|
Goals \== ExpandedGoals.
|
||||||
|
|
||||||
|
'$module_expand_goal'(UnexpandedGoals, ExpandedGoals) :-
|
||||||
|
( '$module_of'(Module, UnexpandedGoals),
|
||||||
|
'$module_exists'(Module),
|
||||||
|
Module:goal_expansion(UnexpandedGoals, ExpandedGoals),
|
||||||
|
UnexpandedGoals \== ExpandedGoals ->
|
||||||
|
true
|
||||||
|
; user:goal_expansion(UnexpandedGoals, ExpandedGoals)
|
||||||
|
).
|
||||||
|
|
||||||
expand_goals(UnexpandedGoals, ExpandedGoals) :-
|
expand_goals(UnexpandedGoals, ExpandedGoals) :-
|
||||||
nonvar(UnexpandedGoals),
|
nonvar(UnexpandedGoals),
|
||||||
var(ExpandedGoals),
|
var(ExpandedGoals),
|
||||||
( expand_goal(UnexpandedGoals, Goals) -> true
|
( '$module_expand_goal'(UnexpandedGoals, Goals) ->
|
||||||
|
true
|
||||||
; Goals = UnexpandedGoals
|
; Goals = UnexpandedGoals
|
||||||
),
|
),
|
||||||
( Goals = (Goal0, Goals0) ->
|
( Goals = (Goal0, Goals0) ->
|
||||||
( expand_goal(Goal0, Goal1) ->
|
( expand_goals(Goal0, Goal1) ->
|
||||||
Expanded = true,
|
|
||||||
expand_goals(Goals0, Goals1),
|
expand_goals(Goals0, Goals1),
|
||||||
thread_goals(Goal1, ExpandedGoals, Goals1, (','))
|
thread_goals(Goal1, ExpandedGoals, Goals1, (','))
|
||||||
; expand_goals(Goals0, Goals1),
|
; expand_goals(Goals0, Goals1),
|
||||||
@@ -189,6 +275,9 @@ expand_goals(UnexpandedGoals, ExpandedGoals) :-
|
|||||||
expand_goals(Goals0, ExpandedGoals0),
|
expand_goals(Goals0, ExpandedGoals0),
|
||||||
expand_goals(Goals1, ExpandedGoals1),
|
expand_goals(Goals1, ExpandedGoals1),
|
||||||
ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1)
|
ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1)
|
||||||
|
; Goals = (\+ Goals0) ->
|
||||||
|
expand_goals(Goals0, Goals1),
|
||||||
|
ExpandedGoals = (\+ Goals1)
|
||||||
; thread_goals(Goals, ExpandedGoals, (','))
|
; thread_goals(Goals, ExpandedGoals, (','))
|
||||||
; Goals = ExpandedGoals
|
; Goals = ExpandedGoals
|
||||||
).
|
).
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ impl fmt::Display for IndexPtr {
|
|||||||
&IndexPtr::DynamicUndefined => write!(f, "undefined"),
|
&IndexPtr::DynamicUndefined => write!(f, "undefined"),
|
||||||
&IndexPtr::Undefined => write!(f, "undefined"),
|
&IndexPtr::Undefined => write!(f, "undefined"),
|
||||||
&IndexPtr::Index(i) => write!(f, "{}", i),
|
&IndexPtr::Index(i) => write!(f, "{}", i),
|
||||||
|
&IndexPtr::InSituDirEntry(i) => write!(f, "in_situ({})", i),
|
||||||
|
&IndexPtr::UserTermExpansion => write!(f, "user:term_expansion"),
|
||||||
|
&IndexPtr::UserGoalExpansion => write!(f, "user:goal_expansion"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,6 +154,9 @@ impl fmt::Display for HeapCellValue {
|
|||||||
&HeapCellValue::NamedStr(arity, ref name, None) => {
|
&HeapCellValue::NamedStr(arity, ref name, None) => {
|
||||||
write!(f, "{}/{}", name.as_str(), arity)
|
write!(f, "{}/{}", name.as_str(), arity)
|
||||||
}
|
}
|
||||||
|
&HeapCellValue::PartialString(ref pstr) => {
|
||||||
|
write!(f, "pstr ( buf: {}, tail: {} )", pstr.block_as_str(), pstr.tail_addr())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,6 +182,8 @@ impl fmt::Display for Addr {
|
|||||||
&Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
|
&Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
|
||||||
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
|
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
|
||||||
&Addr::Str(s) => write!(f, "Addr::Str({})", s),
|
&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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,8 +267,14 @@ impl fmt::Display for SessionError {
|
|||||||
write!(f, "filename {} is invalid", filename)
|
write!(f, "filename {} is invalid", filename)
|
||||||
}
|
}
|
||||||
&SessionError::ModuleNotFound => write!(f, "module not found."),
|
&SessionError::ModuleNotFound => write!(f, "module not found."),
|
||||||
&SessionError::ModuleDoesNotContainExport => {
|
&SessionError::ModuleDoesNotContainExport(ref module, ref key) => {
|
||||||
write!(f, "module does not contain claimed export.")
|
write!(
|
||||||
|
f,
|
||||||
|
"module {} does not contain claimed export {}/{}",
|
||||||
|
module,
|
||||||
|
key.0,
|
||||||
|
key.1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&SessionError::OpIsInfixAndPostFix(_) => {
|
&SessionError::OpIsInfixAndPostFix(_) => {
|
||||||
write!(f, "cannot define an op to be both postfix and infix.")
|
write!(f, "cannot define an op to be both postfix and infix.")
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
:- module(tests_on_builtins, []).
|
||||||
|
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(non_iso)).
|
||||||
|
|
||||||
test_queries_on_builtins :-
|
test_queries_on_builtins :-
|
||||||
\+ atom(_),
|
\+ atom(_),
|
||||||
@@ -20,7 +22,7 @@ test_queries_on_builtins :-
|
|||||||
atomic(0.0),
|
atomic(0.0),
|
||||||
\+ atomic([a,b,c]),
|
\+ atomic([a,b,c]),
|
||||||
\+ atomic(atop(the_trees)),
|
\+ atomic(atop(the_trees)),
|
||||||
( var(X), X = 3, atomic(X) ),
|
\+ \+ findall(X, ( var(X), X = 3, atomic(X) ), [3]),
|
||||||
\+ ( var(X), X = 3, var(X) ),
|
\+ ( var(X), X = 3, var(X) ),
|
||||||
arg(1, f(a,b,c,d), a),
|
arg(1, f(a,b,c,d), a),
|
||||||
arg(2, f(a,b,c,d), b),
|
arg(2, f(a,b,c,d), b),
|
||||||
@@ -34,9 +36,8 @@ test_queries_on_builtins :-
|
|||||||
catch(functor(_,"sdf",3),error(type_error(atom,[s,d,f]),_),true),
|
catch(functor(_,"sdf",3),error(type_error(atom,[s,d,f]),_),true),
|
||||||
f(1,2,3) =.. [f,1,2,3],
|
f(1,2,3) =.. [f,1,2,3],
|
||||||
length([a,b,c], 3),
|
length([a,b,c], 3),
|
||||||
copy_term([[[[X,Y],Y],X]],[[[[Z,V],V],Z]]),
|
\+ \+ copy_term([[[[X,Y],Y],X]],[[[[Z,V],V],Z]]),
|
||||||
\+ ( X = g(X,Y), Y = f(X), copy_term(Y,g(Z)) ),
|
\+ ( X = g(X,Y), Y = f(X), copy_term(Y,g(Z)) ),
|
||||||
(X = g(X,Y), Y = f(X), copy_term(Y,f(Z))),
|
|
||||||
float(3.14159269),
|
float(3.14159269),
|
||||||
\+ float(3),
|
\+ float(3),
|
||||||
\+ float("sdfsa"),
|
\+ float("sdfsa"),
|
||||||
@@ -44,7 +45,7 @@ test_queries_on_builtins :-
|
|||||||
\+ float([1,2,3]),
|
\+ float([1,2,3]),
|
||||||
\+ float([1,2,_]),
|
\+ float([1,2,_]),
|
||||||
\+ (X is 3 rdiv 4, float(X)),
|
\+ (X is 3 rdiv 4, float(X)),
|
||||||
( X is 3 rdiv 4, rational(X) ),
|
\+ \+ (X is 3 rdiv 4, rational(X)),
|
||||||
\+ rational(3),
|
\+ rational(3),
|
||||||
\+ rational(f(_)),
|
\+ rational(f(_)),
|
||||||
\+ rational("sdfa"),
|
\+ rational("sdfa"),
|
||||||
@@ -59,6 +60,71 @@ test_queries_on_builtins :-
|
|||||||
\+ compound(3.14159269),
|
\+ compound(3.14159269),
|
||||||
\+ compound(3),
|
\+ compound(3),
|
||||||
\+ compound("sdfsa"),
|
\+ compound("sdfsa"),
|
||||||
\+ compound(atom).
|
\+ compound(atom),
|
||||||
|
\+ string(functor(string)),
|
||||||
|
\+ string(3.14159269),
|
||||||
|
\+ string(3),
|
||||||
|
\+ string(f(X)),
|
||||||
|
string("sdfsa"),
|
||||||
|
\+ string(atom),
|
||||||
|
\+ string([1,2,3]),
|
||||||
|
\+ string([1,2,X]),
|
||||||
|
\+ \+ ( X = nonvar, nonvar(X) ),
|
||||||
|
\+ nonvar(X),
|
||||||
|
\+ \+ nonvar(f(X)),
|
||||||
|
nonvar(functor(nonvar)),
|
||||||
|
nonvar(3.14159269),
|
||||||
|
nonvar(3),
|
||||||
|
nonvar("sdfsa"),
|
||||||
|
nonvar(atom),
|
||||||
|
nonvar([1,2,3]),
|
||||||
|
\+ \+ nonvar([1,2,X]),
|
||||||
|
\+ \+ (A = f(A), ground(f(f(A))),ground(f(A)),ground(A)),
|
||||||
|
\+ (B = f(A),ground(B)),
|
||||||
|
\+ (B = f(A),ground(A)),
|
||||||
|
\+ \+ ( ground(x),ground(f(x)),X = f(x),ground(g(f(X),[a,b])) ),
|
||||||
|
\+ \+ (A = f(A),g(A,B) == g(f(A),B)),
|
||||||
|
\+ (A = f(A),g(A,B) == g(f(A),b)),
|
||||||
|
\+ (A == B),
|
||||||
|
\+ (A == 12.1),
|
||||||
|
\+ \+ (X = x,f(X,x) == f(x,X)),
|
||||||
|
\+ (A = f(A),g(A,B) \== g(f(A),B)),
|
||||||
|
\+ \+ (A = f(A),g(A,B) \== g(f(A),b)),
|
||||||
|
\+ \+ (A \== B),
|
||||||
|
\+ \+ (A \== 12.1),
|
||||||
|
\+ (X = x,f(X,x) \== f(x,X)),
|
||||||
|
\+ \+ (X @=< Y),
|
||||||
|
\+ (X @>= Y),
|
||||||
|
\+ (X @> Y),
|
||||||
|
\+ \+ (X @>= X),
|
||||||
|
\+ (atom @=< "string"),
|
||||||
|
\+ \+ (atom @=< atom),
|
||||||
|
\+ (atom @=< aaa),
|
||||||
|
\+ \+ (atom @>= "string"),
|
||||||
|
\+ \+ (X is 3 + 3,X @>= Y),
|
||||||
|
\+ \+ (f(X) @>= f(X)),
|
||||||
|
\+ \+ (f(X) @>= a),
|
||||||
|
\+ (f(X) @=< a),
|
||||||
|
[1,2] @=< [1,2],
|
||||||
|
\+ ([1,2,3] @=< [1,2]),
|
||||||
|
\+ \+ ([] @=< [1,2]),
|
||||||
|
\+ ([] @< 1),
|
||||||
|
\+ ([] @< "string"),
|
||||||
|
\+ ([] @< atom),
|
||||||
|
atom @< [],
|
||||||
|
1.1 @< 1,
|
||||||
|
1.0 @=< 1,
|
||||||
|
1 @=< 1.0,
|
||||||
|
\+ \+ (variant(X, Y)),
|
||||||
|
\+ (variant(f(X), f(x))),
|
||||||
|
\+ \+ (variant(X, X)),
|
||||||
|
\+ \+ (variant(f(x), f(x))),
|
||||||
|
\+ (variant([X,Y,Z], [V,W,V])),
|
||||||
|
\+ \+ (variant([X,Y,Z], [V,W,Z])),
|
||||||
|
\+ \+ (variant([X,Y,X], [V,W,V])),
|
||||||
|
\+ \+ (g(B) = B, g(A) = A, variant(A, B)),
|
||||||
|
keysort([1-1,1-1],[1-1,1-1]),
|
||||||
|
\+ \+ findall(Sorted, keysort([2-99,1-a,3-f(_),1-z,1-a,2-44],Sorted), [[1-a,1-z,1-a,2-99,2-44,3-f(_)]]),
|
||||||
|
\+ \+ findall(X, keysort([X-1,1-1],[2-1,1-1]), [2]).
|
||||||
|
|
||||||
:- initialization(test_queries_on_builtins).
|
:- initialization(test_queries_on_builtins).
|
||||||
|
|||||||
54
src/tests/call_with_inference_limit.pl
Normal file
54
src/tests/call_with_inference_limit.pl
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
:- module(tests_on_call_with_inference_limit, []).
|
||||||
|
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(non_iso)).
|
||||||
|
|
||||||
|
:- dynamic(f/1).
|
||||||
|
:- dynamic(g/1).
|
||||||
|
|
||||||
|
test_queries_on_call_with_inference_limit :-
|
||||||
|
catch(call_with_inference_limit(throw(error), 0, inference_limit_exceeded),
|
||||||
|
error,
|
||||||
|
true),
|
||||||
|
catch(call_with_inference_limit(throw(error), 1, inference_limit_exceeded),
|
||||||
|
error,
|
||||||
|
true),
|
||||||
|
\+ call_with_inference_limit(g(X), 5, R),
|
||||||
|
maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]),
|
||||||
|
findall([R,X],
|
||||||
|
call_with_inference_limit(g(X), 10, R),
|
||||||
|
[[true, 1],
|
||||||
|
[true, 2],
|
||||||
|
[true, 3],
|
||||||
|
[true, 4],
|
||||||
|
[!, 5]]),
|
||||||
|
findall([R,X],
|
||||||
|
(call_with_inference_limit(g(X), 10, R), call(true)),
|
||||||
|
[[true, 1],
|
||||||
|
[true, 2],
|
||||||
|
[true, 3],
|
||||||
|
[true, 4],
|
||||||
|
[!, 5]]),
|
||||||
|
findall([R,X],
|
||||||
|
(call_with_inference_limit(g(X), 4, R), call(true)),
|
||||||
|
[[true, 1],
|
||||||
|
[true, 2],
|
||||||
|
[inference_limit_exceeded, _]]),
|
||||||
|
findall([X,R1,R2],
|
||||||
|
(call_with_inference_limit(g(X), 4, R1),
|
||||||
|
call_with_inference_limit(g(X), 5, R2)),
|
||||||
|
[[1,true,!],
|
||||||
|
[2,true,!],
|
||||||
|
[3,true,!],
|
||||||
|
[4,true,!],
|
||||||
|
[5,!,!]]),
|
||||||
|
\+ \+ assertz((f(X) :- call_with_inference_limit(g(X), 8, _))),
|
||||||
|
findall([R,X],
|
||||||
|
call_with_inference_limit(f(X), 12, R),
|
||||||
|
[[true,1],
|
||||||
|
[true,2],
|
||||||
|
[true,3],
|
||||||
|
[true,4],
|
||||||
|
[!,5]]).
|
||||||
|
|
||||||
|
:- initialization(test_queries_on_call_with_inference_limit).
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
:- module(tests_on_facts, []).
|
||||||
|
|
||||||
:- dynamic(p/2).
|
:- dynamic(p/2).
|
||||||
:- dynamic(p/3).
|
:- dynamic(p/3).
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
:- module(test_on_predicates, []).
|
||||||
|
|
||||||
:- dynamic(p/2).
|
:- dynamic(p/2).
|
||||||
:- dynamic(p/3).
|
:- dynamic(p/3).
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
:- module(tests_on_rules, []).
|
||||||
|
|
||||||
:- dynamic(p/3).
|
:- dynamic(p/3).
|
||||||
:- dynamic(p/2).
|
:- dynamic(p/2).
|
||||||
:- dynamic(q/2).
|
:- dynamic(q/2).
|
||||||
@@ -10,46 +12,54 @@ q(q, s).
|
|||||||
r(s, t).
|
r(s, t).
|
||||||
|
|
||||||
test_queries_on_rules :-
|
test_queries_on_rules :-
|
||||||
findall([X,Y], p(X, Y), [[q, t]]),
|
\+ \+ findall([X,Y], p(X, Y), [[q, t]]),
|
||||||
p(q, t),
|
p(q, t),
|
||||||
\+ p(t, q),
|
\+ p(t, q),
|
||||||
findall(T, p(q, T), [t]),
|
\+ \+ findall(T, p(q, T), [t]),
|
||||||
\+ p(t, t),
|
\+ p(t, t),
|
||||||
retract((p(X,Y) :- q(X,Z), r(Z, Y))),
|
\+ \+ retract((p(X,Y) :- q(X,Z), r(Z, Y))),
|
||||||
retract(q(_,_)),
|
retract(q(_,_)),
|
||||||
assertz((p(X,_) :- q(f(f(X)), _), r(_, _))),
|
\+ \+ assertz((p(X,_) :- q(f(f(X)), _), r(_, _))),
|
||||||
assertz(q(f(f(X)), r)),
|
\+ \+ assertz(q(f(f(X)), r)),
|
||||||
p(_,_),
|
p(_,_),
|
||||||
retract(q(_,_)),
|
retract(q(_,_)),
|
||||||
assertz(q(f(f(x)), r)),
|
assertz(q(f(f(x)), r)),
|
||||||
findall(X, p(X,_), [x]),
|
\+ \+ findall(X, p(X,_), [x]),
|
||||||
retract((p(X,_) :- q(f(f(X)), _), r(_, _))),
|
\+ \+ retract((p(X,_) :- q(f(f(X)), _), r(_, _))),
|
||||||
retract(q(_,_)),
|
retract(q(_,_)),
|
||||||
assertz((p(X, Y) :- q(X, Y), r(X, Y))),
|
\+ \+ assertz((p(X, Y) :- q(X, Y), r(X, Y))),
|
||||||
assertz(q(s, t)),
|
assertz(q(s, t)),
|
||||||
retract(r(_,_)),
|
retract(r(_,_)),
|
||||||
assertz((r(X, Y) :- r(a))),
|
\+ \+ assertz((r(X, Y) :- r(a))),
|
||||||
assertz(r(a)),
|
assertz(r(a)),
|
||||||
findall([X,Y], p(X, Y), [[s,t]]),
|
\+ \+ findall([X,Y], p(X, Y), [[s,t]]),
|
||||||
\+ p(t, _),
|
\+ p(t, _),
|
||||||
findall(T, p(s, T), [t]),
|
\+ \+ findall(T, p(s, T), [t]),
|
||||||
findall(S, p(S, t), [s]),
|
\+ \+ findall(S, p(S, t), [s]),
|
||||||
assertz((p(f(f(a), g(b), X), g(b), h) :- q(X, Y))),
|
\+ \+ assertz((p(f(f(a), g(b), X), g(b), h) :- q(X, _))),
|
||||||
retract(q(_,_)),
|
retract(q(_,_)),
|
||||||
assertz(q(_,_)),
|
assertz(q(_,_)),
|
||||||
findall([X,Y,Z], p(f(X, Y, Z), g(b), h), [[f(a), g(b), _]]),
|
\+ \+ findall([X,Y,Z], p(f(X, Y, Z), g(b), h), [[f(a), g(b), _]]),
|
||||||
\+ p(f(X, g(_), Z), g(Z), X),
|
\+ p(f(X, g(_), Z), g(Z), X),
|
||||||
findall([X,Y,Z], p(f(X, g(Y), Z), g(Z), h), [[f(a), b, b]]),
|
\+ \+ findall([X,Y,Z], p(f(X, g(Y), Z), g(Z), h), [[f(a), b, b]]),
|
||||||
findall([X,Y,Z], p(Z, Y, X), [[h, g(b), f(f(a),g(b),_)]]),
|
\+ \+ findall([X,Y,Z], p(Z, Y, X), [[h, g(b), f(f(a),g(b),_)]]),
|
||||||
findall([X,Y,Z], p(f(X, Y, Z), Y, h), [[f(a), g(b), _]]),
|
\+ \+ findall([X,Y,Z], p(f(X, Y, Z), Y, h), [[f(a), g(b), _]]),
|
||||||
retract((p(X, Y) :- q(X, Y), r(X, Y))),
|
\+ \+ retract((p(X, Y) :- q(X, Y), r(X, Y))),
|
||||||
retract((p(f(f(a), g(b), X), g(b), h) :- q(X, _))),
|
\+ \+ retract((p(f(f(a), g(b), X), g(b), h) :- q(X, _))),
|
||||||
assertz((p(_, f(_, Y, _)) :- h(Y))),
|
\+ \+ assertz((p(_, f(_, Y, _)) :- h(Y))),
|
||||||
assertz(h(y)),
|
assertz(h(y)),
|
||||||
findall(Y, p(_, f(_, Y, _)), [y]).
|
\+ \+ findall(Y, p(_, f(_, Y, _)), [y]).
|
||||||
p(_, f(_, y, _)),
|
p(_, f(_, y, _)),
|
||||||
\+ p(_, f(_, z, _)),
|
\+ p(_, f(_, z, _)),
|
||||||
retract((p(_, f(_, Y, _)) :- h(Y))).
|
\+ \+ retract((p(_, f(_, Y, _)) :- h(Y))),
|
||||||
|
cleanup.
|
||||||
|
|
||||||
|
cleanup :- abolish(p/3),
|
||||||
|
abolish(p/2),
|
||||||
|
abolish(q/2),
|
||||||
|
abolish(r/2),
|
||||||
|
abolish(r/1),
|
||||||
|
abolish(h/1).
|
||||||
|
|
||||||
:- initialization(test_queries_on_rules).
|
:- initialization(test_queries_on_rules).
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user