Compare commits
238 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb9d865635 | ||
|
|
694c87cb61 | ||
|
|
c41aba6b90 | ||
|
|
28ea672e36 | ||
|
|
9366a48d6d | ||
|
|
c7e1f5d568 | ||
|
|
d91ee5b77c | ||
|
|
fd97b84916 | ||
|
|
23f59970cb | ||
|
|
8781e03863 | ||
|
|
f2940ddfcf | ||
|
|
140149f051 | ||
|
|
9055370326 | ||
|
|
1af62c8d11 | ||
|
|
ec5430826e | ||
|
|
b2cccab768 | ||
|
|
579aa8acd4 | ||
|
|
9c2cb144b5 | ||
|
|
3d04689660 | ||
|
|
a891cc4edf | ||
|
|
706ab2ae5b | ||
|
|
9c1de8e00b | ||
|
|
1109e05e06 | ||
|
|
ce313b8a6b | ||
|
|
7c96b91663 | ||
|
|
87e966e185 | ||
|
|
1e018681de | ||
|
|
5b324680ba | ||
|
|
abca5fc405 | ||
|
|
6a455d2866 | ||
|
|
70da818101 | ||
|
|
5ec837acb4 | ||
|
|
76e33d051c | ||
|
|
7c5318b784 | ||
|
|
47892bf24a | ||
|
|
8a9cd7779c | ||
|
|
d4c0277065 | ||
|
|
069e132c0e | ||
|
|
4e6c138099 | ||
|
|
0ab355eada | ||
|
|
44825826df | ||
|
|
612f09893c | ||
|
|
e9f507b868 | ||
|
|
78278c804f | ||
|
|
b51460a59a | ||
|
|
181be5be3f | ||
|
|
91d4e91f53 | ||
|
|
ad3ae7991b | ||
|
|
c7caf6b7a9 | ||
|
|
4422ffe39f | ||
|
|
1ff52f70aa | ||
|
|
fce45167a5 | ||
|
|
b8f384045c | ||
|
|
ea95a7900c | ||
|
|
edea1273c8 | ||
|
|
ec9c763211 | ||
|
|
5a08117e75 | ||
|
|
0aec980aa8 | ||
|
|
6b05ee5130 | ||
|
|
1ffbf63d20 | ||
|
|
b905d2758d | ||
|
|
311d985145 | ||
|
|
a9a06b5297 | ||
|
|
6b8e620495 | ||
|
|
577f85099d | ||
|
|
607c84a79b | ||
|
|
2eec6499ff | ||
|
|
cd1150c11d | ||
|
|
987bbdecf5 | ||
|
|
a68394b6f2 | ||
|
|
3d6fbabc86 | ||
|
|
1479b5d38c | ||
|
|
336311ecc8 | ||
|
|
e9bb35c895 | ||
|
|
ab4f93dcee | ||
|
|
140a199805 | ||
|
|
232b66cfc3 | ||
|
|
11ba7e47fd | ||
|
|
c36d4a9c9a | ||
|
|
4b5c22864e | ||
|
|
5e1faeb5d2 | ||
|
|
4b7c2ba6c8 | ||
|
|
b9285f8de1 | ||
|
|
084fc84590 | ||
|
|
7a9b71cc03 | ||
|
|
6b49653754 | ||
|
|
d5fa8cc211 | ||
|
|
10a11c293e | ||
|
|
e486862db8 | ||
|
|
1c8aae0839 | ||
|
|
6feb1f8b82 | ||
|
|
bef8eb538c | ||
|
|
4e3b066555 | ||
|
|
4d23542ef3 | ||
|
|
47a6b498e3 | ||
|
|
b6f77f4e6f | ||
|
|
b96cd06129 | ||
|
|
e8eb6765bd | ||
|
|
8df552e952 | ||
|
|
18c52e076f | ||
|
|
1810dabc14 | ||
|
|
609a3a229f | ||
|
|
dff56643f0 | ||
|
|
77f8d52271 | ||
|
|
1e9821ec0c | ||
|
|
66e047083a | ||
|
|
e6438e79d8 | ||
|
|
a5e72679bc | ||
|
|
15cc916333 | ||
|
|
2f3de51e55 | ||
|
|
cea1353fbb | ||
|
|
bfbafd4168 | ||
|
|
27a15a2464 | ||
|
|
c2a87f898e | ||
|
|
aaa75c3ffc | ||
|
|
2dfa108034 | ||
|
|
4895cb7b22 | ||
|
|
2d3eb8483f | ||
|
|
36ef988514 | ||
|
|
d58dd7cc91 | ||
|
|
7e06abebd5 | ||
|
|
8dd7f51ae3 | ||
|
|
6030fae685 | ||
|
|
0f502fff84 | ||
|
|
789f662ec8 | ||
|
|
72536037ca | ||
|
|
e4eefc92f4 | ||
|
|
23c4e935b4 | ||
|
|
68b4951bc9 | ||
|
|
ed89c43e48 | ||
|
|
16137ace0e | ||
|
|
b4ef7556da | ||
|
|
eea83d9474 | ||
|
|
9d5264c5a3 | ||
|
|
66075bf45b | ||
|
|
35b8f69f92 | ||
|
|
2d5fe21b05 | ||
|
|
b448681872 | ||
|
|
05c14d5780 | ||
|
|
bb9de52a53 | ||
|
|
7595ec16e5 | ||
|
|
d8cf0f320d | ||
|
|
d644a3996e | ||
|
|
525050c407 | ||
|
|
468088fd6b | ||
|
|
95c192a988 | ||
|
|
d6287fae06 | ||
|
|
9e98f75495 | ||
|
|
56681af1b6 | ||
|
|
8bf3d4ea71 | ||
|
|
00eab4d415 | ||
|
|
0876d46880 | ||
|
|
ed803d30cd | ||
|
|
b6504bf377 | ||
|
|
85b4f235ef | ||
|
|
064bfa5e0d | ||
|
|
4a6ffb6b9e | ||
|
|
d952b7ace8 | ||
|
|
3b6138eaaa | ||
|
|
f3167f6b5f | ||
|
|
8c99d748e2 | ||
|
|
0ab928063e | ||
|
|
c9a34bde3f | ||
|
|
7f85c682b8 | ||
|
|
181185bad6 | ||
|
|
01a9fd9e25 | ||
|
|
3be00045cf | ||
|
|
86176dce8d | ||
|
|
1fa8a0a969 | ||
|
|
d5fe2e88d1 | ||
|
|
9177dbce7f | ||
|
|
55a896367d | ||
|
|
f2e49c84cc | ||
|
|
afa0bea1b1 | ||
|
|
f7e31fceac | ||
|
|
c490d818fb | ||
|
|
32bdedde6d | ||
|
|
48960f1beb | ||
|
|
cf65cbe2f1 | ||
|
|
45c35eca3e | ||
|
|
bb2a8c9090 | ||
|
|
6798b22b49 | ||
|
|
3acbe2a418 | ||
|
|
c45cdd6ea0 | ||
|
|
f520c38b60 | ||
|
|
046a2175ab | ||
|
|
83def95383 | ||
|
|
012fefa37e | ||
|
|
4878e42e07 | ||
|
|
1a7992e524 | ||
|
|
94d7c6dc5f | ||
|
|
23bfb4da50 | ||
|
|
1f21a5fe62 | ||
|
|
2173a8e3cb | ||
|
|
067e2633af | ||
|
|
d916da9ba8 | ||
|
|
c2fc33afec | ||
|
|
3d4e400ed2 | ||
|
|
75d719d204 | ||
|
|
172e3e9f34 | ||
|
|
8e32bdd8db | ||
|
|
895b02b641 | ||
|
|
d06b5f7ab5 | ||
|
|
e88ec6736c | ||
|
|
922abf21e7 | ||
|
|
c55bfa2c6e | ||
|
|
5463c1d47f | ||
|
|
3513a9c7ba | ||
|
|
45db236ec7 | ||
|
|
5848ff5735 | ||
|
|
64c9ac4071 | ||
|
|
75fc922898 | ||
|
|
59e2c3fd5e | ||
|
|
5bd73741cf | ||
|
|
fcfa3beaa3 | ||
|
|
dfbdaa9dab | ||
|
|
5f1f07e5a1 | ||
|
|
eace0d9b37 | ||
|
|
d83b32a200 | ||
|
|
9cefb33388 | ||
|
|
bd5d6d0686 | ||
|
|
ecebaf8216 | ||
|
|
8762647b55 | ||
|
|
664c0ee77c | ||
|
|
7a9c3d351d | ||
|
|
69e52d1ed8 | ||
|
|
bd594e0c05 | ||
|
|
3bf42860e2 | ||
|
|
0532f51cc2 | ||
|
|
1808597258 | ||
|
|
2744989cf1 | ||
|
|
0d04abb5c7 | ||
|
|
495168e7bb | ||
|
|
475fbf9561 | ||
|
|
c6264cf098 | ||
|
|
bc9123affb | ||
|
|
7fd12972ad | ||
|
|
8ad4f188f2 |
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
*.png binary
|
||||||
|
*.pl text eol=lf
|
||||||
|
*.rs text eol=lf diff=rust
|
||||||
|
*.md text eol=lf diff=markdown
|
||||||
52
.github/workflows/docker-publish.yml
vendored
Normal file
52
.github/workflows/docker-publish.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: Docker Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: [ 'v*.*.*' ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: mjt128/scryer-prolog
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Workaround: https://github.com/docker/build-push-action/issues/461
|
||||||
|
- name: Setup Docker buildx
|
||||||
|
uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf
|
||||||
|
|
||||||
|
# Login against Docker registry
|
||||||
|
# https://github.com/docker/login-action
|
||||||
|
- name: Log into registry
|
||||||
|
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Extract Docker image tag from git tag. E.g. if git tag is "v0.19.1" then use
|
||||||
|
# Docker image tag "0.19.1". Tag "latest" is automatically synced with newest
|
||||||
|
# version.
|
||||||
|
# https://github.com/docker/metadata-action
|
||||||
|
- name: Extract Docker metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
||||||
|
with:
|
||||||
|
images: docker.io/${{ env.IMAGE_NAME }}
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
|
||||||
|
# Build and push Docker image with Buildx
|
||||||
|
# https://github.com/docker/build-push-action
|
||||||
|
- name: Build and push Docker image
|
||||||
|
id: build-and-push
|
||||||
|
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
31
.github/workflows/test.yml
vendored
31
.github/workflows/test.yml
vendored
@@ -38,3 +38,34 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --verbose --all --no-default-features --features num
|
args: --verbose --all --no-default-features --features num
|
||||||
|
msrv:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-20.04, macos-10.15]
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Install cargo-msrv
|
||||||
|
uses: baptiste0928/cargo-install@v1.1.0
|
||||||
|
with:
|
||||||
|
crate: cargo-msrv
|
||||||
|
- name: Verify MSRV
|
||||||
|
run: cargo msrv --verify
|
||||||
|
windows:
|
||||||
|
runs-on: windows-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: msys2 {0}
|
||||||
|
steps:
|
||||||
|
- name: Setup MSYS2
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
update: true
|
||||||
|
install: >-
|
||||||
|
base-devel
|
||||||
|
mingw-w64-x86_64-rust
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Test on Windows
|
||||||
|
run: cargo test --verbose --all
|
||||||
|
|||||||
1607
Cargo.lock
generated
1607
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
51
Cargo.toml
51
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "scryer-prolog"
|
name = "scryer-prolog"
|
||||||
version = "0.9.0"
|
version = "0.9.1"
|
||||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A modern Prolog implementation written mostly in Rust."
|
description = "A modern Prolog implementation written mostly in Rust."
|
||||||
@@ -9,31 +9,26 @@ repository = "https://github.com/mthom/scryer-prolog"
|
|||||||
license = "BSD-3-Clause"
|
license = "BSD-3-Clause"
|
||||||
keywords = ["prolog", "prolog-interpreter", "prolog-system"]
|
keywords = ["prolog", "prolog-interpreter", "prolog-system"]
|
||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
build = "build.rs"
|
build = "build/main.rs"
|
||||||
|
rust-version = "1.61"
|
||||||
[workspace]
|
|
||||||
members = ["crates/num-rug-adapter",
|
|
||||||
"crates/static-string-indexing",
|
|
||||||
"crates/instructions-template",
|
|
||||||
"crates/to-syn-value",
|
|
||||||
"crates/to-syn-value_derive"]
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
num = ["num-rug-adapter"]
|
|
||||||
# no default features to make num tests work
|
|
||||||
# workaround for --no-default-features and --features not working intuitively for workspaces with a root package
|
|
||||||
# see rust-lang/cargo#7160
|
|
||||||
default = ["rug"]
|
default = ["rug"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
indexmap = "1.0.2"
|
indexmap = "1.0.2"
|
||||||
static-string-indexing = { path = "./crates/static-string-indexing" }
|
proc-macro2 = "1.0.36"
|
||||||
instructions-template = { path = "./crates/instructions-template" }
|
quote = "1.0.15"
|
||||||
proc-macro2 = "*"
|
strum = "0.23"
|
||||||
|
strum_macros = "0.23"
|
||||||
|
syn = { version = "1.0.88", features = ['full', 'visit', 'extra-traits'] }
|
||||||
|
to-syn-value = "0.1.0"
|
||||||
|
to-syn-value_derive = "0.1.0"
|
||||||
|
walkdir = "2"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cpu-time = "1.0.0"
|
cpu-time = "1.0.0"
|
||||||
crossterm = "0.16.0"
|
crossterm = "0.20.0"
|
||||||
dirs-next = "2.0.0"
|
dirs-next = "2.0.0"
|
||||||
divrem = "0.1.0"
|
divrem = "0.1.0"
|
||||||
fxhash = "0.2.1"
|
fxhash = "0.2.1"
|
||||||
@@ -43,33 +38,39 @@ indexmap = "1.0.2"
|
|||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
lexical = "5.2.2"
|
lexical = "5.2.2"
|
||||||
libc = "0.2.62"
|
libc = "0.2.62"
|
||||||
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } # modular-bitfield = "0.11.2"
|
modular-bitfield = "0.11.2"
|
||||||
nix = "0.15.0"
|
ctrlc = "3.2.2"
|
||||||
num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" }
|
ordered-float = "2.6.0"
|
||||||
ordered-float = "2.1.1"
|
|
||||||
phf = { version = "0.9", features = ["macros"] }
|
phf = { version = "0.9", features = ["macros"] }
|
||||||
ref_thread_local = "0.0.0"
|
ref_thread_local = "0.0.0"
|
||||||
rug = { version = "1.12.0", optional = true }
|
rug = { version = "1.15.0", optional = true }
|
||||||
rustyline = "9.0.0"
|
rustyline = "9.0.0"
|
||||||
ring = "0.16.13"
|
ring = "0.16.13"
|
||||||
ripemd160 = "0.8.0"
|
ripemd160 = "0.8.0"
|
||||||
sha3 = "0.8.2"
|
sha3 = "0.8.2"
|
||||||
blake2 = "0.8.1"
|
blake2 = "0.8.1"
|
||||||
openssl = { version = "0.10.29", features = ["vendored"] }
|
crrl ="0.2.0"
|
||||||
native-tls = "0.2.4"
|
native-tls = "0.2.4"
|
||||||
chrono = "0.4.11"
|
chrono = "0.4.11"
|
||||||
select = "0.4.3"
|
select = "0.4.3"
|
||||||
roxmltree = "0.11.0"
|
roxmltree = "0.11.0"
|
||||||
base64 = "0.12.3"
|
base64 = "0.12.3"
|
||||||
smallvec = "*"
|
smallvec = "1.8.0"
|
||||||
sodiumoxide = "0.2.6"
|
sodiumoxide = "0.2.6"
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
slice-deque = "0.3.0"
|
ryu = "1.0.9"
|
||||||
|
hyper = { version = "0.14", features = ["full"] }
|
||||||
|
hyper-tls = "0.5.0"
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
futures = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "1.0.3"
|
assert_cmd = "1.0.3"
|
||||||
predicates-core = "1.0.2"
|
predicates-core = "1.0.2"
|
||||||
serial_test = "0.5.1"
|
serial_test = "0.5.1"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = true
|
debug = true
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# See https://github.com/LukeMathWalker/cargo-chef
|
# See https://github.com/LukeMathWalker/cargo-chef
|
||||||
ARG RUST_VERSION=1.52.1-buster
|
ARG RUST_VERSION=1.60-buster
|
||||||
FROM rust:${RUST_VERSION} as planner
|
FROM rust:${RUST_VERSION} as planner
|
||||||
WORKDIR /scryer-prolog
|
WORKDIR /scryer-prolog
|
||||||
RUN cargo install cargo-chef
|
RUN cargo install cargo-chef
|
||||||
|
|||||||
94
README.md
94
README.md
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# Scryer Prolog
|
# Scryer Prolog
|
||||||
|
|
||||||
Scryer Prolog aims to become to ISO Prolog what GHC is to Haskell: an open
|
Scryer Prolog aims to become to ISO Prolog what GHC is to Haskell: an open
|
||||||
@@ -101,7 +102,7 @@ strings.
|
|||||||
|
|
||||||
## Installing Scryer Prolog
|
## Installing Scryer Prolog
|
||||||
|
|
||||||
### Native Install (Unix Only)
|
### Native Install
|
||||||
|
|
||||||
First, install the latest stable version of
|
First, install the latest stable version of
|
||||||
[Rust](https://www.rust-lang.org/en-US/install.html) using your
|
[Rust](https://www.rust-lang.org/en-US/install.html) using your
|
||||||
@@ -112,20 +113,8 @@ Rust updated to the latest stable release; any existing Rust
|
|||||||
distribution should be uninstalled from your system before rustup is
|
distribution should be uninstalled from your system before rustup is
|
||||||
used.
|
used.
|
||||||
|
|
||||||
Scryer Prolog can be installed with cargo, like so:
|
Currently the only way to install the latest version of Scryer is to
|
||||||
|
clone directly from this git repository, which can be done as follows:
|
||||||
```
|
|
||||||
$> cargo install scryer-prolog
|
|
||||||
```
|
|
||||||
|
|
||||||
cargo will download and install the libraries Scryer Prolog uses
|
|
||||||
automatically from crates.io. You can find the `scryer-prolog`
|
|
||||||
executable in `~/.cargo/bin`.
|
|
||||||
|
|
||||||
Publishing Rust crates to crates.io and pushing to git are entirely
|
|
||||||
distinct, independent processes, so to be sure you have the latest
|
|
||||||
commit, it is recommended to clone directly from this git repository,
|
|
||||||
which can be done as follows:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
$> git clone https://github.com/mthom/scryer-prolog
|
$> git clone https://github.com/mthom/scryer-prolog
|
||||||
@@ -136,9 +125,20 @@ $> cargo run [--release]
|
|||||||
The optional `--release` flag will perform various optimizations,
|
The optional `--release` flag will perform various optimizations,
|
||||||
producing a faster executable.
|
producing a faster executable.
|
||||||
|
|
||||||
|
On Windows, Scryer Prolog is easier to build inside a [MSYS2](https://www.msys2.org/)
|
||||||
|
environment as some crates may require native C compilation. However,
|
||||||
|
the resulting binary does not need MSYS2 to run. When executing Scryer in a shell, it is recommended to use a more advanced shell than mintty (the default MSYS2 shell). The [Windows Terminal](https://github.com/microsoft/terminal) works correctly.
|
||||||
|
|
||||||
|
To build a Windows Installer, you'll need first Scryer Prolog compiled in release mode, then, with WiX Toolset installed, execute:
|
||||||
|
```
|
||||||
|
candle.exe scryer-prolog.wxs
|
||||||
|
light.exe scryer-prolog.wixobj
|
||||||
|
```
|
||||||
|
It will generate a very basic MSI file which installs the main executable and a shortcut in the Start Menu. It can be installed with a double-click. To uninstall, go to the Control Panel and uninstall as usual.
|
||||||
|
|
||||||
Scryer Prolog must be built with **Rust 1.57 and up**.
|
Scryer Prolog must be built with **Rust 1.57 and up**.
|
||||||
|
|
||||||
### Docker Install (All Platforms)
|
### Docker Install
|
||||||
|
|
||||||
First, install [Docker](https://docs.docker.com/get-docker/) on Linux,
|
First, install [Docker](https://docs.docker.com/get-docker/) on Linux,
|
||||||
Windows, or Mac.
|
Windows, or Mac.
|
||||||
@@ -213,8 +213,14 @@ predicates it defines. For example, with the program shown above:
|
|||||||
|
|
||||||
Press `SPACE` to show further answers, if any exist. Press `RETURN`
|
Press `SPACE` to show further answers, if any exist. Press `RETURN`
|
||||||
or `.` to abort the search and return to the
|
or `.` to abort the search and return to the
|
||||||
toplevel prompt. Press `f` to see the next 5 answers, and
|
toplevel prompt. Press `f` to see up to the next multiple of
|
||||||
`a` to see all answers. Press `h` to show a help message.
|
5 answers, and `a` to see all answers. Press `h` to show a help
|
||||||
|
message.
|
||||||
|
|
||||||
|
Use `TAB` to complete atoms and predicate names in queries. For
|
||||||
|
instance, after consulting the program above, typing `decl` followed
|
||||||
|
by `TAB` yields `declarative_world`. Press `TAB` repeatedly
|
||||||
|
to cycle through alternative completions.
|
||||||
|
|
||||||
To quit Scryer Prolog, use the standard predicate `halt/0`:
|
To quit Scryer Prolog, use the standard predicate `halt/0`:
|
||||||
|
|
||||||
@@ -267,9 +273,30 @@ in any clause of a predicate's definition.
|
|||||||
|
|
||||||
### Strings and partial strings
|
### Strings and partial strings
|
||||||
|
|
||||||
|
A very compact internal representation of *strings* is one of the key
|
||||||
|
innovations of Scryer Prolog. This means that terms which appear as
|
||||||
|
lists of characters to Prolog programs are stored in packed
|
||||||
|
UTF-8 encoding by the engine.
|
||||||
|
|
||||||
|
Without this innovation, storing a list of characters in memory
|
||||||
|
would use one memory cell per character, one memory cell per
|
||||||
|
list constructor, and one memory cell for each tail that occurs
|
||||||
|
in the list. Since one memory cell takes 8 bytes on 64-bit
|
||||||
|
machines, the packed representation used by Scryer Prolog yields
|
||||||
|
an up to **24-fold reduction** of memory usage, and
|
||||||
|
corresponding reduction of memory accesses when creating and
|
||||||
|
processing strings.
|
||||||
|
|
||||||
|
Scryer Prolog's compact internal string representation makes it
|
||||||
|
ideally suited for the use case Prolog was originally developed for:
|
||||||
|
efficient and convenient text processing, especially with definite
|
||||||
|
clause grammars (DCGs) as provided by
|
||||||
|
[`library(dcgs)`](src/lib/dcgs.pl) and
|
||||||
|
[`library(pio)`](src/lib/pio.pl) to transparently apply DCGs to files.
|
||||||
|
|
||||||
In Scryer Prolog, the default value of the Prolog flag `double_quotes`
|
In Scryer Prolog, the default value of the Prolog flag `double_quotes`
|
||||||
is `chars`, which is also the recommended setting. This means that
|
is `chars`, which is also the recommended setting. This means that
|
||||||
double-quoted strings are interpreted as lists of *characters*, in the
|
lists of characters can be written as double-quoted strings, in the
|
||||||
tradition of Marseille Prolog.
|
tradition of Marseille Prolog.
|
||||||
|
|
||||||
For example, the following query succeeds:
|
For example, the following query succeeds:
|
||||||
@@ -279,15 +306,9 @@ For example, the following query succeeds:
|
|||||||
true.
|
true.
|
||||||
```
|
```
|
||||||
|
|
||||||
Internally, strings are represented very compactly in packed
|
This shows that the string `"abc"`, which is represented as a sequence
|
||||||
UTF-8 encoding. A naive representation of strings as lists of
|
of 3 bytes internally, appears to Prolog programs as a list of
|
||||||
characters would use one memory cell per character, one
|
characters.
|
||||||
memory cell per list constructor, and one memory cell for
|
|
||||||
each tail that occurs in the list. Since one memory cell takes
|
|
||||||
8 bytes on 64-bit machines, the packed representation used by
|
|
||||||
Scryer Prolog yields an up to **24-fold reduction** of
|
|
||||||
memory usage, and corresponding reduction of memory accesses when
|
|
||||||
creating and processing strings.
|
|
||||||
|
|
||||||
Scryer Prolog uses the same efficient encoding for *partial* strings,
|
Scryer Prolog uses the same efficient encoding for *partial* strings,
|
||||||
which appear to Prolog code as partial lists of characters. The
|
which appear to Prolog code as partial lists of characters. The
|
||||||
@@ -310,13 +331,11 @@ the above example, posting <tt>Ls0 = [a,b,c|Ls]</tt> yields
|
|||||||
the exact same internal representation, and has the advantage that
|
the exact same internal representation, and has the advantage that
|
||||||
only the standard predicate `(=)/2` is used.
|
only the standard predicate `(=)/2` is used.
|
||||||
|
|
||||||
Definite clause grammars as provided by
|
The efficient internal representation of strings and partial strings
|
||||||
[`library(dcgs)`](src/lib/dcgs.pl), and the predicates from
|
was first proposed and explained by Ulrich Neumerkel in
|
||||||
[`library(lists)`](src/lib/lists.pl), are ideally suited for reasoning
|
issues [#24](https://github.com/mthom/scryer-prolog/issues/24)
|
||||||
about strings.
|
and [#95](https://github.com/mthom/scryer-prolog/issues/95), and
|
||||||
|
Scryer Prolog is the first Prolog system that implements it.
|
||||||
Partial strings were first proposed by Ulrich Neumerkel in issue
|
|
||||||
[#95](https://github.com/mthom/scryer-prolog/issues/95).
|
|
||||||
|
|
||||||
### Occurs check and cyclic terms
|
### Occurs check and cyclic terms
|
||||||
|
|
||||||
@@ -520,7 +539,7 @@ The modules that ship with Scryer Prolog are also called
|
|||||||
Probabilistic predicates and random number generators.
|
Probabilistic predicates and random number generators.
|
||||||
* [`http/http_open`](src/lib/http/http_open.pl) Open a stream to
|
* [`http/http_open`](src/lib/http/http_open.pl) Open a stream to
|
||||||
read answers from web servers. HTTPS is also supported.
|
read answers from web servers. HTTPS is also supported.
|
||||||
* [`http/http_server`](src/lib/http/http_server.pl) Runs a HTTP/1.0 web server.
|
* [`http/http_server`](src/lib/http/http_server.pl) Runs a HTTP/1.1 and HTTP/2.0 web server. Uses [Hyper](https://hyper.rs) as a backend. Supports some query and form handling.
|
||||||
* [`sgml`](src/lib/sgml.pl)
|
* [`sgml`](src/lib/sgml.pl)
|
||||||
`load_html/3` and `load_xml/3` represent HTML and XML documents
|
`load_html/3` and `load_xml/3` represent HTML and XML documents
|
||||||
as Prolog terms for convenient and efficient reasoning. Use
|
as Prolog terms for convenient and efficient reasoning. Use
|
||||||
@@ -562,6 +581,9 @@ The modules that ship with Scryer Prolog are also called
|
|||||||
* [`tls`](src/lib/tls.pl)
|
* [`tls`](src/lib/tls.pl)
|
||||||
Predicates for negotiating TLS connections explicitly.
|
Predicates for negotiating TLS connections explicitly.
|
||||||
* [`ugraphs`](src/lib/ugraphs.pl) Graph manipulation library
|
* [`ugraphs`](src/lib/ugraphs.pl) Graph manipulation library
|
||||||
|
* [`simplex`](src/lib/simplex.pl) Providing `assignment/2`,
|
||||||
|
`transportation/4` and other predicates for solving linear
|
||||||
|
programming problems.
|
||||||
|
|
||||||
To use predicates provided by the `lists` library, write:
|
To use predicates provided by the `lists` library, write:
|
||||||
|
|
||||||
|
|||||||
@@ -190,9 +190,9 @@ enum REPLCodePtr {
|
|||||||
DynamicProperty,
|
DynamicProperty,
|
||||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
|
#[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
|
||||||
AbolishClause,
|
AbolishClause,
|
||||||
#[strum_discriminants(strum(props(Arity = "5", Name = "$asserta")))]
|
#[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))]
|
||||||
Asserta,
|
Asserta,
|
||||||
#[strum_discriminants(strum(props(Arity = "5", Name = "$assertz")))]
|
#[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))]
|
||||||
Assertz,
|
Assertz,
|
||||||
#[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
|
#[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
|
||||||
Retract,
|
Retract,
|
||||||
@@ -276,6 +276,8 @@ enum SystemClauseType {
|
|||||||
DeleteHeadAttribute,
|
DeleteHeadAttribute,
|
||||||
#[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))]
|
#[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))]
|
||||||
DynamicModuleResolution(usize),
|
DynamicModuleResolution(usize),
|
||||||
|
#[strum_discriminants(strum(props(Arity = "arity", Name = "$prepare_call_clause")))]
|
||||||
|
PrepareCallClause(usize),
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))]
|
||||||
EnqueueAttributedVar,
|
EnqueueAttributedVar,
|
||||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
|
#[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
|
||||||
@@ -402,8 +404,6 @@ enum SystemClauseType {
|
|||||||
InferenceLevel,
|
InferenceLevel,
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$clean_up_block")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$clean_up_block")))]
|
||||||
CleanUpBlock,
|
CleanUpBlock,
|
||||||
#[strum_discriminants(strum(props(Arity = "0", Name = "$erase_ball")))]
|
|
||||||
EraseBall,
|
|
||||||
#[strum_discriminants(strum(props(Arity = "0", Name = "$fail")))]
|
#[strum_discriminants(strum(props(Arity = "0", Name = "$fail")))]
|
||||||
Fail,
|
Fail,
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$get_ball")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$get_ball")))]
|
||||||
@@ -432,6 +432,12 @@ enum SystemClauseType {
|
|||||||
ReturnFromVerifyAttr,
|
ReturnFromVerifyAttr,
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_ball")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_ball")))]
|
||||||
SetBall,
|
SetBall,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "0", Name = "$push_ball_stack")))]
|
||||||
|
PushBallStack,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "0", Name = "$pop_ball_stack")))]
|
||||||
|
PopBallStack,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "0", Name = "$pop_from_ball_stack")))]
|
||||||
|
PopFromBallStack,
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp_by_default")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp_by_default")))]
|
||||||
SetCutPointByDefault(RegType),
|
SetCutPointByDefault(RegType),
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_double_quotes")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_double_quotes")))]
|
||||||
@@ -490,7 +496,7 @@ enum SystemClauseType {
|
|||||||
CryptoDataEncrypt,
|
CryptoDataEncrypt,
|
||||||
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
|
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
|
||||||
CryptoDataDecrypt,
|
CryptoDataDecrypt,
|
||||||
#[strum_discriminants(strum(props(Arity = "5", Name = "$crypto_curve_scalar_mult")))]
|
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_curve_scalar_mult")))]
|
||||||
CryptoCurveScalarMult,
|
CryptoCurveScalarMult,
|
||||||
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
|
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
|
||||||
Ed25519Sign,
|
Ed25519Sign,
|
||||||
@@ -538,6 +544,26 @@ enum SystemClauseType {
|
|||||||
PopCount,
|
PopCount,
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$cpu_now")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$cpu_now")))]
|
||||||
CpuNow,
|
CpuNow,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "2", Name = "$det_length_rundown")))]
|
||||||
|
DeterministicLengthRundown,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "7", Name = "$http_open")))]
|
||||||
|
HttpOpen,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "2", Name = "$http_listen")))]
|
||||||
|
HttpListen,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "7", Name = "$http_accept")))]
|
||||||
|
HttpAccept,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "4", Name = "$http_answer")))]
|
||||||
|
HttpAnswer,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "3", Name = "$predicate_defined")))]
|
||||||
|
PredicateDefined,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))]
|
||||||
|
StripModule,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "4", Name = "$compile_inline_or_expanded_goal")))]
|
||||||
|
CompileInlineOrExpandedGoal,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "arity", Name = "$call_inline")))]
|
||||||
|
InlineCallN(usize),
|
||||||
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$is_expanded_or_inlined")))]
|
||||||
|
IsExpandedOrInlined,
|
||||||
REPL(REPLCodePtr),
|
REPL(REPLCodePtr),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,8 +828,8 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
|
use fxhash::FxBuildHasher;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use slice_deque::SliceDeque;
|
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
@@ -915,8 +941,8 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
IndexingCodePtr,
|
IndexingCodePtr,
|
||||||
IndexingCodePtr,
|
IndexingCodePtr,
|
||||||
),
|
),
|
||||||
SwitchOnConstant(IndexMap<Literal, IndexingCodePtr>),
|
SwitchOnConstant(IndexMap<Literal, IndexingCodePtr, FxBuildHasher>),
|
||||||
SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>),
|
SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@@ -1026,8 +1052,8 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum IndexingLine {
|
pub enum IndexingLine {
|
||||||
Indexing(IndexingInstruction),
|
Indexing(IndexingInstruction),
|
||||||
IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
|
IndexedChoice(VecDeque<IndexedChoiceInstruction>),
|
||||||
DynamicIndexedChoice(SliceDeque<usize>),
|
DynamicIndexedChoice(VecDeque<usize>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IndexingInstruction> for IndexingLine {
|
impl From<IndexingInstruction> for IndexingLine {
|
||||||
@@ -1095,6 +1121,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_head_instr(&self) -> bool {
|
pub fn is_head_instr(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
Instruction::Deallocate |
|
||||||
Instruction::GetConstant(..) |
|
Instruction::GetConstant(..) |
|
||||||
Instruction::GetList(..) |
|
Instruction::GetList(..) |
|
||||||
Instruction::GetPartialString(..) |
|
Instruction::GetPartialString(..) |
|
||||||
@@ -1424,6 +1451,12 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::DefaultExecuteN(arity, _) => {
|
&Instruction::DefaultExecuteN(arity, _) => {
|
||||||
functor!(atom!("execute_default_n"), [fixnum(arity)])
|
functor!(atom!("execute_default_n"), [fixnum(arity)])
|
||||||
}
|
}
|
||||||
|
&Instruction::CallInlineCallN(arity, _) => {
|
||||||
|
functor!(atom!("call_n_inline"), [fixnum(arity)])
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteInlineCallN(arity, _) => {
|
||||||
|
functor!(atom!("call_n_inline"), [fixnum(arity)])
|
||||||
|
}
|
||||||
&Instruction::CallTermGreaterThan(_) |
|
&Instruction::CallTermGreaterThan(_) |
|
||||||
&Instruction::CallTermLessThan(_) |
|
&Instruction::CallTermLessThan(_) |
|
||||||
&Instruction::CallTermGreaterThanOrEqual(_) |
|
&Instruction::CallTermGreaterThanOrEqual(_) |
|
||||||
@@ -1585,6 +1618,9 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::CallDeleteAttribute(_) |
|
&Instruction::CallDeleteAttribute(_) |
|
||||||
&Instruction::CallDeleteHeadAttribute(_) |
|
&Instruction::CallDeleteHeadAttribute(_) |
|
||||||
&Instruction::CallDynamicModuleResolution(..) |
|
&Instruction::CallDynamicModuleResolution(..) |
|
||||||
|
&Instruction::CallPrepareCallClause(..) |
|
||||||
|
&Instruction::CallCompileInlineOrExpandedGoal(..) |
|
||||||
|
&Instruction::CallIsExpandedOrInlined(_) |
|
||||||
&Instruction::CallEnqueueAttributedVar(_) |
|
&Instruction::CallEnqueueAttributedVar(_) |
|
||||||
&Instruction::CallFetchGlobalVar(_) |
|
&Instruction::CallFetchGlobalVar(_) |
|
||||||
&Instruction::CallFirstStream(_) |
|
&Instruction::CallFirstStream(_) |
|
||||||
@@ -1648,7 +1684,6 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::CallSetStreamPosition(_) |
|
&Instruction::CallSetStreamPosition(_) |
|
||||||
&Instruction::CallInferenceLevel(_) |
|
&Instruction::CallInferenceLevel(_) |
|
||||||
&Instruction::CallCleanUpBlock(_) |
|
&Instruction::CallCleanUpBlock(_) |
|
||||||
&Instruction::CallEraseBall(_) |
|
|
||||||
&Instruction::CallFail(_) |
|
&Instruction::CallFail(_) |
|
||||||
&Instruction::CallGetBall(_) |
|
&Instruction::CallGetBall(_) |
|
||||||
&Instruction::CallGetCurrentBlock(_) |
|
&Instruction::CallGetCurrentBlock(_) |
|
||||||
@@ -1658,12 +1693,22 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::CallInstallNewBlock(_) |
|
&Instruction::CallInstallNewBlock(_) |
|
||||||
&Instruction::CallMaybe(_) |
|
&Instruction::CallMaybe(_) |
|
||||||
&Instruction::CallCpuNow(_) |
|
&Instruction::CallCpuNow(_) |
|
||||||
|
&Instruction::CallDeterministicLengthRundown(_) |
|
||||||
|
&Instruction::CallHttpOpen(_) |
|
||||||
|
&Instruction::CallHttpListen(_) |
|
||||||
|
&Instruction::CallHttpAccept(_) |
|
||||||
|
&Instruction::CallHttpAnswer(_) |
|
||||||
|
&Instruction::CallPredicateDefined(_) |
|
||||||
|
&Instruction::CallStripModule(_) |
|
||||||
&Instruction::CallCurrentTime(_) |
|
&Instruction::CallCurrentTime(_) |
|
||||||
&Instruction::CallQuotedToken(_) |
|
&Instruction::CallQuotedToken(_) |
|
||||||
&Instruction::CallReadTermFromChars(_) |
|
&Instruction::CallReadTermFromChars(_) |
|
||||||
&Instruction::CallResetBlock(_) |
|
&Instruction::CallResetBlock(_) |
|
||||||
&Instruction::CallReturnFromVerifyAttr(_) |
|
&Instruction::CallReturnFromVerifyAttr(_) |
|
||||||
&Instruction::CallSetBall(_) |
|
&Instruction::CallSetBall(_) |
|
||||||
|
&Instruction::CallPushBallStack(_) |
|
||||||
|
&Instruction::CallPopBallStack(_) |
|
||||||
|
&Instruction::CallPopFromBallStack(_) |
|
||||||
&Instruction::CallSetCutPointByDefault(..) |
|
&Instruction::CallSetCutPointByDefault(..) |
|
||||||
&Instruction::CallSetDoubleQuotes(_) |
|
&Instruction::CallSetDoubleQuotes(_) |
|
||||||
&Instruction::CallSetSeed(_) |
|
&Instruction::CallSetSeed(_) |
|
||||||
@@ -1786,7 +1831,10 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::ExecuteFileTime(_) |
|
&Instruction::ExecuteFileTime(_) |
|
||||||
&Instruction::ExecuteDeleteAttribute(_) |
|
&Instruction::ExecuteDeleteAttribute(_) |
|
||||||
&Instruction::ExecuteDeleteHeadAttribute(_) |
|
&Instruction::ExecuteDeleteHeadAttribute(_) |
|
||||||
&Instruction::ExecuteDynamicModuleResolution(_, _) |
|
&Instruction::ExecuteDynamicModuleResolution(..) |
|
||||||
|
&Instruction::ExecutePrepareCallClause(..) |
|
||||||
|
&Instruction::ExecuteCompileInlineOrExpandedGoal(..) |
|
||||||
|
&Instruction::ExecuteIsExpandedOrInlined(_) |
|
||||||
&Instruction::ExecuteEnqueueAttributedVar(_) |
|
&Instruction::ExecuteEnqueueAttributedVar(_) |
|
||||||
&Instruction::ExecuteFetchGlobalVar(_) |
|
&Instruction::ExecuteFetchGlobalVar(_) |
|
||||||
&Instruction::ExecuteFirstStream(_) |
|
&Instruction::ExecuteFirstStream(_) |
|
||||||
@@ -1850,7 +1898,6 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::ExecuteSetStreamPosition(_) |
|
&Instruction::ExecuteSetStreamPosition(_) |
|
||||||
&Instruction::ExecuteInferenceLevel(_) |
|
&Instruction::ExecuteInferenceLevel(_) |
|
||||||
&Instruction::ExecuteCleanUpBlock(_) |
|
&Instruction::ExecuteCleanUpBlock(_) |
|
||||||
&Instruction::ExecuteEraseBall(_) |
|
|
||||||
&Instruction::ExecuteFail(_) |
|
&Instruction::ExecuteFail(_) |
|
||||||
&Instruction::ExecuteGetBall(_) |
|
&Instruction::ExecuteGetBall(_) |
|
||||||
&Instruction::ExecuteGetCurrentBlock(_) |
|
&Instruction::ExecuteGetCurrentBlock(_) |
|
||||||
@@ -1860,12 +1907,22 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::ExecuteInstallNewBlock(_) |
|
&Instruction::ExecuteInstallNewBlock(_) |
|
||||||
&Instruction::ExecuteMaybe(_) |
|
&Instruction::ExecuteMaybe(_) |
|
||||||
&Instruction::ExecuteCpuNow(_) |
|
&Instruction::ExecuteCpuNow(_) |
|
||||||
|
&Instruction::ExecuteDeterministicLengthRundown(_) |
|
||||||
|
&Instruction::ExecuteHttpOpen(_) |
|
||||||
|
&Instruction::ExecuteHttpListen(_) |
|
||||||
|
&Instruction::ExecuteHttpAccept(_) |
|
||||||
|
&Instruction::ExecuteHttpAnswer(_) |
|
||||||
|
&Instruction::ExecutePredicateDefined(_) |
|
||||||
|
&Instruction::ExecuteStripModule(_) |
|
||||||
&Instruction::ExecuteCurrentTime(_) |
|
&Instruction::ExecuteCurrentTime(_) |
|
||||||
&Instruction::ExecuteQuotedToken(_) |
|
&Instruction::ExecuteQuotedToken(_) |
|
||||||
&Instruction::ExecuteReadTermFromChars(_) |
|
&Instruction::ExecuteReadTermFromChars(_) |
|
||||||
&Instruction::ExecuteResetBlock(_) |
|
&Instruction::ExecuteResetBlock(_) |
|
||||||
&Instruction::ExecuteReturnFromVerifyAttr(_) |
|
&Instruction::ExecuteReturnFromVerifyAttr(_) |
|
||||||
&Instruction::ExecuteSetBall(_) |
|
&Instruction::ExecuteSetBall(_) |
|
||||||
|
&Instruction::ExecutePushBallStack(_) |
|
||||||
|
&Instruction::ExecutePopBallStack(_) |
|
||||||
|
&Instruction::ExecutePopFromBallStack(_) |
|
||||||
&Instruction::ExecuteSetCutPointByDefault(_, _) |
|
&Instruction::ExecuteSetCutPointByDefault(_, _) |
|
||||||
&Instruction::ExecuteSetDoubleQuotes(_) |
|
&Instruction::ExecuteSetDoubleQuotes(_) |
|
||||||
&Instruction::ExecuteSetSeed(_) |
|
&Instruction::ExecuteSetSeed(_) |
|
||||||
@@ -2158,6 +2215,7 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
let mut clause_type_from_name_and_arity_arms = vec![];
|
let mut clause_type_from_name_and_arity_arms = vec![];
|
||||||
let mut clause_type_to_instr_arms = vec![];
|
let mut clause_type_to_instr_arms = vec![];
|
||||||
let mut clause_type_name_arms = vec![];
|
let mut clause_type_name_arms = vec![];
|
||||||
|
let mut is_inbuilt_arms = vec![];
|
||||||
|
|
||||||
for (name, arity, variant) in instr_data.compare_number_variants {
|
for (name, arity, variant) in instr_data.compare_number_variants {
|
||||||
let ident = variant.ident.clone();
|
let ident = variant.ident.clone();
|
||||||
@@ -2212,6 +2270,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
) => Instruction::#instr_ident(#(#placeholder_ids),*, 0)
|
) => Instruction::#instr_ident(#(#placeholder_ids),*, 0)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
is_inbuilt_arms.push(
|
||||||
|
quote! {
|
||||||
|
(atom!(#name), #arity) => true
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, arity, variant) in instr_data.compare_term_variants {
|
for (name, arity, variant) in instr_data.compare_term_variants {
|
||||||
@@ -2241,6 +2305,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
) => Instruction::#instr_ident(0)
|
) => Instruction::#instr_ident(0)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
is_inbuilt_arms.push(
|
||||||
|
quote! {
|
||||||
|
(atom!(#name), #arity) => true
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, arity, variant) in instr_data.builtin_type_variants {
|
for (name, arity, variant) in instr_data.builtin_type_variants {
|
||||||
@@ -2302,6 +2372,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
) => Instruction::#instr_ident(0)
|
) => Instruction::#instr_ident(0)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
is_inbuilt_arms.push(
|
||||||
|
quote! {
|
||||||
|
(atom!(#name), #arity) => true
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, arity, variant) in instr_data.inlined_type_variants {
|
for (name, arity, variant) in instr_data.inlined_type_variants {
|
||||||
@@ -2361,6 +2437,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
|
) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
is_inbuilt_arms.push(
|
||||||
|
quote! {
|
||||||
|
(atom!(#name), #arity) => true
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, arity, variant) in instr_data.system_clause_type_variants {
|
for (name, arity, variant) in instr_data.system_clause_type_variants {
|
||||||
@@ -2391,6 +2473,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
SystemClauseType::#ident(temp_v!(1))
|
SystemClauseType::#ident(temp_v!(1))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else if ident.to_string() == "InlineCallN" {
|
||||||
|
quote! {
|
||||||
|
(atom!(#name), arity) => ClauseType::System(
|
||||||
|
SystemClauseType::#ident(arity)
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
(atom!(#name), #arity) => ClauseType::System(
|
(atom!(#name), #arity) => ClauseType::System(
|
||||||
@@ -2421,6 +2509,7 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let ident = variant.ident;
|
let ident = variant.ident;
|
||||||
|
|
||||||
let instr_ident = if ident != "CallContinuation" {
|
let instr_ident = if ident != "CallContinuation" {
|
||||||
format_ident!("Call{}", ident)
|
format_ident!("Call{}", ident)
|
||||||
} else {
|
} else {
|
||||||
@@ -2444,6 +2533,18 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
) => Instruction::#instr_ident(0)
|
) => Instruction::#instr_ident(0)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
is_inbuilt_arms.push(
|
||||||
|
if let Arity::Ident("arity") = &arity {
|
||||||
|
quote! {
|
||||||
|
(atom!(#name), _arity) => true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
(atom!(#name), #arity) => true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, arity, variant) in instr_data.repl_code_ptr_variants {
|
for (name, arity, variant) in instr_data.repl_code_ptr_variants {
|
||||||
@@ -2509,6 +2610,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
)) => Instruction::#instr_ident(0)
|
)) => Instruction::#instr_ident(0)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
is_inbuilt_arms.push(
|
||||||
|
quote! {
|
||||||
|
(atom!(#name), #arity) => true
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, arity, variant) in instr_data.clause_type_variants {
|
for (name, arity, variant) in instr_data.clause_type_variants {
|
||||||
@@ -2516,7 +2623,7 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
|
|
||||||
if ident == "Named" {
|
if ident == "Named" {
|
||||||
clause_type_from_name_and_arity_arms.push(quote! {
|
clause_type_from_name_and_arity_arms.push(quote! {
|
||||||
(name, arity) => ClauseType::Named(arity, name, CodeIndex::default())
|
(name, arity) => ClauseType::Named(arity, name, CodeIndex::default(arena))
|
||||||
});
|
});
|
||||||
|
|
||||||
clause_type_to_instr_arms.push(quote! {
|
clause_type_to_instr_arms.push(quote! {
|
||||||
@@ -2578,6 +2685,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
ClauseType::#ident => Instruction::#ident(0)
|
ClauseType::#ident => Instruction::#ident(0)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
is_inbuilt_arms.push(
|
||||||
|
quote! {
|
||||||
|
(atom!(#name), _arity) => true
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let to_execute_arms: Vec<_> = instr_data.instr_variants
|
let to_execute_arms: Vec<_> = instr_data.instr_variants
|
||||||
@@ -2912,7 +3025,7 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClauseType {
|
impl ClauseType {
|
||||||
pub fn from(name: Atom, arity: usize) -> ClauseType {
|
pub fn from(name: Atom, arity: usize, arena: &mut Arena) -> ClauseType {
|
||||||
match (name, arity) {
|
match (name, arity) {
|
||||||
#(
|
#(
|
||||||
#clause_type_from_name_and_arity_arms,
|
#clause_type_from_name_and_arity_arms,
|
||||||
@@ -2928,19 +3041,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_builtin(&self) -> bool {
|
pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
|
||||||
if let ClauseType::BuiltIn(_) = self {
|
match (name, arity) {
|
||||||
true
|
#(
|
||||||
} else {
|
#is_inbuilt_arms,
|
||||||
false
|
)*
|
||||||
}
|
_ => false,
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_inlined(&self) -> bool {
|
|
||||||
if let ClauseType::Inlined(_) = self {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3135,7 +3241,7 @@ enum Arity {
|
|||||||
impl From<&'static str> for Arity {
|
impl From<&'static str> for Arity {
|
||||||
fn from(arity: &'static str) -> Self {
|
fn from(arity: &'static str) -> Self {
|
||||||
usize::from_str_radix(&arity, 10)
|
usize::from_str_radix(&arity, 10)
|
||||||
.map(|n| Arity::Static(n))
|
.map(Arity::Static)
|
||||||
.unwrap_or_else(|_| Arity::Ident(arity))
|
.unwrap_or_else(|_| Arity::Ident(arity))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
use static_string_indexing::index_static_strings;
|
mod instructions_template;
|
||||||
|
mod static_string_indexing;
|
||||||
|
|
||||||
use instructions_template::generate_instructions_rs;
|
use instructions_template::generate_instructions_rs;
|
||||||
|
use static_string_indexing::index_static_strings;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
|
fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
|
||||||
let entries = match current_dir.read_dir() {
|
let entries = match current_dir.read_dir() {
|
||||||
@@ -39,6 +42,16 @@ fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let has_rustfmt = Command::new("rustfmt")
|
||||||
|
.arg("--version")
|
||||||
|
.stdin(Stdio::inherit())
|
||||||
|
.status()
|
||||||
|
.is_ok();
|
||||||
|
|
||||||
|
if !has_rustfmt {
|
||||||
|
println!("Failed to run rustfmt, will skip formatting generated files.")
|
||||||
|
}
|
||||||
|
|
||||||
let out_dir = env::var("OUT_DIR").unwrap();
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
let dest_path = Path::new(&out_dir).join("libraries.rs");
|
let dest_path = Path::new(&out_dir).join("libraries.rs");
|
||||||
|
|
||||||
@@ -65,10 +78,9 @@ fn main() {
|
|||||||
.write_all(quoted_output.to_string().as_bytes())
|
.write_all(quoted_output.to_string().as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Command::new("rustfmt")
|
if has_rustfmt {
|
||||||
.arg(instructions_path.as_os_str())
|
format_generated_file(instructions_path.as_path());
|
||||||
.spawn().unwrap()
|
}
|
||||||
.wait().unwrap();
|
|
||||||
|
|
||||||
let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
|
let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
|
||||||
let mut static_atoms_file = File::create(&static_atoms_path).unwrap();
|
let mut static_atoms_file = File::create(&static_atoms_path).unwrap();
|
||||||
@@ -79,10 +91,24 @@ fn main() {
|
|||||||
.write_all(quoted_output.to_string().as_bytes())
|
.write_all(quoted_output.to_string().as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Command::new("rustfmt")
|
if has_rustfmt {
|
||||||
.arg(static_atoms_path.as_os_str())
|
format_generated_file(static_atoms_path.as_path());
|
||||||
.spawn().unwrap()
|
}
|
||||||
.wait().unwrap();
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=src/");
|
println!("cargo:rerun-if-changed=src/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_generated_file(path: &Path) {
|
||||||
|
Command::new("rustfmt")
|
||||||
|
.arg(path.as_os_str())
|
||||||
|
.spawn()
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
panic!(
|
||||||
|
"{}: rustfmt was detected as available, but failed to format generated file '{}'",
|
||||||
|
err,
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.wait()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
@@ -66,7 +66,7 @@ impl<'ast> Visit<'ast> for StaticStrVisitor {
|
|||||||
if let Some(Lit::Str(string)) = m.parse_body::<Lit>().ok() {
|
if let Some(Lit::Str(string)) = m.parse_body::<Lit>().ok() {
|
||||||
self.static_strs.insert(string.value());
|
self.static_strs.insert(string.value());
|
||||||
}
|
}
|
||||||
} else if path.is_ident("read_heap_cell") {
|
} else if path.is_ident("read_heap_cell") || path.is_ident("match_untyped_arena_ptr") {
|
||||||
if let Some(m) = m.parse_body::<ReadHeapCellExprAndArms>().ok() {
|
if let Some(m) = m.parse_body::<ReadHeapCellExprAndArms>().ok() {
|
||||||
self.visit_expr(&m.expr);
|
self.visit_expr(&m.expr);
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea
|
|||||||
#((#static_strs) => { Atom { index: #indices_iter } };)*
|
#((#static_strs) => { Atom { index: #indices_iter } };)*
|
||||||
}
|
}
|
||||||
|
|
||||||
static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
|
pub static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
|
||||||
#(#static_strs => { Atom { index: #indices } },)*
|
#(#static_strs => { Atom { index: #indices } },)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
129
crates/instructions-template/Cargo.lock
generated
129
crates/instructions-template/Cargo.lock
generated
@@ -1,129 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "heck"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-segmentation",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indexmap"
|
|
||||||
version = "1.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"hashbrown",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "instructions-template"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"indexmap",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"strum",
|
|
||||||
"strum_macros",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.35"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "392a54546fda6b7cc663379d0e6ce8b324cf88aecc5a499838e1be9781bdce2e"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-xid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustversion"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strum"
|
|
||||||
version = "0.23.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strum_macros"
|
|
||||||
version = "0.23.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
|
|
||||||
dependencies = [
|
|
||||||
"heck",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"rustversion",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.84"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-xid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "to-syn-value"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"syn",
|
|
||||||
"to-syn-value_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "to-syn-value_derive"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-segmentation"
|
|
||||||
version = "1.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-xid"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "instructions-template"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
indexmap = "*"
|
|
||||||
proc-macro2 = "*"
|
|
||||||
quote = "*"
|
|
||||||
strum = "0.23"
|
|
||||||
strum_macros = "0.23"
|
|
||||||
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
|
|
||||||
to-syn-value = { path = "../to-syn-value" }
|
|
||||||
to-syn-value_derive = { path = "../to-syn-value_derive" }
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "num-rug-adapter"
|
|
||||||
version = "0.1.5"
|
|
||||||
authors = ["Marco A L Barbosa <malbarbo@gmail.com>"]
|
|
||||||
edition = "2021"
|
|
||||||
description = "An adapter to use num crate where rug is needed."
|
|
||||||
license = "MIT/Apache-2.0"
|
|
||||||
repository = "https://github.com/malbarbo/num-rug-adapter"
|
|
||||||
keywords = ["mathematics", "numerics", "bignum"]
|
|
||||||
categories = ["api-bindings", "science"]
|
|
||||||
readme = "README.md"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
libc = "0.2"
|
|
||||||
num-bigint = "0.2"
|
|
||||||
num-integer = "0.1.41"
|
|
||||||
num-rational = "0.2"
|
|
||||||
num-traits = "0.2"
|
|
||||||
@@ -1,888 +0,0 @@
|
|||||||
use num_bigint::{BigInt, ParseBigIntError};
|
|
||||||
use num_integer::Integer as _;
|
|
||||||
use num_rational::BigRational;
|
|
||||||
use num_traits::{FromPrimitive, Num, Signed, ToPrimitive};
|
|
||||||
use num_traits::identities::One;
|
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::fmt::{self, Display, Formatter};
|
|
||||||
use std::ops::*;
|
|
||||||
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
|
||||||
pub struct Integer(BigInt);
|
|
||||||
|
|
||||||
impl Integer {
|
|
||||||
#[inline]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Integer(BigInt::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseBigIntError> {
|
|
||||||
BigInt::from_str_radix(s, radix).map(Integer)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn to_u8(&self) -> Option<u8> {
|
|
||||||
self.0.to_u8()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn to_u32(&self) -> Option<u32> {
|
|
||||||
self.0.to_u32()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn to_u64(&self) -> Option<u64> {
|
|
||||||
self.0.to_u64()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn to_usize(&self) -> Option<usize> {
|
|
||||||
self.0.to_usize()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn to_i32(&self) -> Option<i32> {
|
|
||||||
self.0.to_i32()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn to_isize(&self) -> Option<isize> {
|
|
||||||
self.0.to_isize()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn to_f64(&self) -> f64 {
|
|
||||||
self.0.to_f64().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn abs(&self) -> Self {
|
|
||||||
Integer(self.0.abs())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn abs_ref(&self) -> Self {
|
|
||||||
Integer(self.0.abs())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn div_rem(&self, other: Self) -> (Self, Self) {
|
|
||||||
let (a, b) = num_integer::Integer::div_rem(&self.0, &other.0);
|
|
||||||
(Integer(a), Integer(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn div_rem_ref(&self, other: &Self) -> (Self, Self) {
|
|
||||||
let (a, b) = num_integer::Integer::div_rem(&self.0, &other.0);
|
|
||||||
(Integer(a), Integer(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn div_rem_floor(&self, other: Self) -> (Self, Self) {
|
|
||||||
let (a, b) = num_integer::Integer::div_mod_floor(&self.0, &other.0);
|
|
||||||
(Integer(a), Integer(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn div_rem_floor_ref(&self, other: &Self) -> (Self, Self) {
|
|
||||||
let (a, b) = num_integer::Integer::div_mod_floor(&self.0, &other.0);
|
|
||||||
(Integer(a), Integer(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn mod_u(&self, modulo: u32) -> u32 {
|
|
||||||
(self.0.abs() % modulo).to_u32().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_odd(&self) -> bool {
|
|
||||||
num_integer::Integer::is_odd(&self.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn from_f64(v: f64) -> Option<Self> {
|
|
||||||
BigInt::from_f64(v).map(Integer)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn gcd_ref(&self, other: &Self) -> Self {
|
|
||||||
Integer(num_integer::Integer::gcd(&self.0, &other.0))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn gcd(&self, other: &Self) -> Self {
|
|
||||||
Integer(num_integer::Integer::gcd(&self.0, &other.0))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn count_ones(&self) -> Option<u32> {
|
|
||||||
Some(self.0.to_u32_digits().1.iter().map(|&d| d.count_ones()).sum())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Integer> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn from(s: &Integer) -> Self {
|
|
||||||
s.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<i32> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn from(s: i32) -> Self {
|
|
||||||
Integer(BigInt::from(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn from(s: isize) -> Self {
|
|
||||||
Integer(BigInt::from(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn from(s: u8) -> Self {
|
|
||||||
Integer(BigInt::from(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u32> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn from(s: u32) -> Self {
|
|
||||||
Integer(BigInt::from(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u64> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn from(s: u64) -> Self {
|
|
||||||
Integer(BigInt::from(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<usize> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn from(s: usize) -> Self {
|
|
||||||
Integer(BigInt::from(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn mul(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(self.0 * other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul<u32> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn mul(self, other: u32) -> Self::Output {
|
|
||||||
Integer(self.0 * other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul<&Integer> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
fn mul(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(self.0 * &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MulAssign<&Integer> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn mul_assign(&mut self, other: &Integer) {
|
|
||||||
self.0 *= &other.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn add(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(self.0 + other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<Integer> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn add(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(&self.0 + other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<&Integer> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn add(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(self.0 + &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<&Integer> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn add(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(&self.0 + &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddAssign<i64> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn add_assign(&mut self, other: i64) {
|
|
||||||
self.0 += other;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddAssign<&Integer> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn add_assign(&mut self, other: &Integer) {
|
|
||||||
self.0 += &other.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Div for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn div(self, other: Integer) -> Integer {
|
|
||||||
Integer(self.0 / other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Div<&Integer> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn div(self, other: &Integer) -> Integer {
|
|
||||||
Integer(self.0 / &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Div<Integer> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn div(self, other: Integer) -> Integer {
|
|
||||||
Integer(&self.0 / &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Shr<u32> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn shr(self, rhs: u32) -> Self::Output {
|
|
||||||
Integer(self.0 >> rhs as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Shr<u32> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn shr(self, rhs: u32) -> Self::Output {
|
|
||||||
Integer(&self.0 >> rhs as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ShrAssign<u32> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn shr_assign(&mut self, rhs: u32) {
|
|
||||||
self.0 >>= rhs as usize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Shl<u32> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn shl(self, rhs: u32) -> Self::Output {
|
|
||||||
Integer(self.0 << rhs as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Shl<u32> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn shl(self, rhs: u32) -> Self::Output {
|
|
||||||
Integer(&self.0 << rhs as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Not for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn not(self) -> Self::Output {
|
|
||||||
Integer(!self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Not for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn not(self) -> Self::Output {
|
|
||||||
Integer(!&self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rem for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rem(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(self.0.mod_floor(&other.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rem<&Integer> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rem(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(self.0.mod_floor(&other.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rem<&Integer> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rem(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(self.0.mod_floor(&other.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rem<Integer> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rem(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(self.0.mod_floor(&other.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitAnd for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitand(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(self.0 & &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitAnd<&Integer> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitand(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(self.0 & &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitAnd<Integer> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitand(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(&self.0 & other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitAnd for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitand(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(&self.0 & &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOr for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitor(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(self.0 | other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOr<&Integer> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitor(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(self.0 | &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOr<Integer> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitor(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(&self.0 | other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitOr for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitor(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(&self.0 | &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitXor for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitxor(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(self.0 ^ other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitXor<&Integer> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitxor(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(self.0 ^ &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitXor<Integer> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitxor(self, other: Integer) -> Self::Output {
|
|
||||||
Integer(&self.0 ^ other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BitXor<&Integer> for &Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn bitxor(self, other: &Integer) -> Self::Output {
|
|
||||||
Integer(&self.0 ^ &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<i32> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &i32) -> bool {
|
|
||||||
self.0 == BigInt::from(*other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<i64> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &i64) -> bool {
|
|
||||||
self.0 == BigInt::from(*other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<isize> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &isize) -> bool {
|
|
||||||
self.0 == BigInt::from(*other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<usize> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &usize) -> bool {
|
|
||||||
self.0 == BigInt::from(*other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<Integer> for isize {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &Integer) -> bool {
|
|
||||||
other.0 == BigInt::from(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd<i32> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
|
|
||||||
self.0.partial_cmp(&BigInt::from(*other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd<i64> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
|
|
||||||
self.0.partial_cmp(&BigInt::from(*other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd<isize> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &isize) -> Option<Ordering> {
|
|
||||||
self.0.partial_cmp(&BigInt::from(*other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd<usize> for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &usize) -> Option<Ordering> {
|
|
||||||
self.0.partial_cmp(&BigInt::from(*other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Integer {
|
|
||||||
type Err = <BigInt as FromStr>::Err;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
Ok(Integer(s.parse()?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Neg for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn neg(self) -> Self {
|
|
||||||
Integer(-self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Integer {
|
|
||||||
#[inline]
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rational
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
|
||||||
pub struct Rational(BigRational);
|
|
||||||
|
|
||||||
impl Rational {
|
|
||||||
#[inline]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Rational(BigRational::from(BigInt::default()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn from_f64(v: f64) -> Option<Self> {
|
|
||||||
BigRational::from_f64(v).map(Rational)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn to_f64(&self) -> f64 {
|
|
||||||
self.0.numer().to_f64().unwrap() / self.0.denom().to_f64().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn numer(&self) -> &Integer {
|
|
||||||
unsafe { ::std::mem::transmute(self.0.numer()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn denom(&self) -> &Integer {
|
|
||||||
unsafe { ::std::mem::transmute(self.0.denom()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn abs(self) -> Self {
|
|
||||||
Rational(self.0.abs())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn abs_ref(&self) -> Self {
|
|
||||||
Rational(self.0.abs())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn fract_floor_ref(&self) -> &Self {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn from(s: isize) -> Self {
|
|
||||||
Rational(BigRational::new_raw(BigInt::from(s), One::one()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Integer> for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn from(s: &Integer) -> Self {
|
|
||||||
Rational::from(s.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Rational> for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn from(s: &Rational) -> Self {
|
|
||||||
s.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Integer> for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn from(i: Integer) -> Self {
|
|
||||||
Rational(BigRational::from(i.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for Rational {
|
|
||||||
type Output = Rational;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn add(self, other: Rational) -> Self::Output {
|
|
||||||
Rational(self.0 + other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<&Rational> for Rational {
|
|
||||||
type Output = Rational;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn add(self, other: &Rational) -> Self::Output {
|
|
||||||
Rational(self.0 + &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<i32> for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &i32) -> bool {
|
|
||||||
self.0 == BigRational::from(BigInt::from(*other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<i64> for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &i64) -> bool {
|
|
||||||
self.0 == BigRational::from(BigInt::from(*other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<isize> for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &isize) -> bool {
|
|
||||||
self == &Rational::from(*other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<Rational> for isize {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &Rational) -> bool {
|
|
||||||
other == &Rational::from(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd<isize> for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &isize) -> Option<Ordering> {
|
|
||||||
self.0.partial_cmp(&BigRational::from(BigInt::from(*other)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd<i64> for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
|
|
||||||
self.0.partial_cmp(&BigRational::from(BigInt::from(*other)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd<i32> for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
|
|
||||||
self.0.partial_cmp(&BigRational::from(BigInt::from(*other)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Neg for Rational {
|
|
||||||
type Output = Rational;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn neg(self) -> Self {
|
|
||||||
Rational(-self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul for Rational {
|
|
||||||
type Output = Rational;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn mul(self, other: Rational) -> Self::Output {
|
|
||||||
Rational(self.0 * other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul<&Rational> for Rational {
|
|
||||||
type Output = Rational;
|
|
||||||
|
|
||||||
fn mul(self, other: &Rational) -> Self::Output {
|
|
||||||
Rational(self.0 * &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Div for Rational {
|
|
||||||
type Output = Rational;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn div(self, other: Rational) -> Self::Output {
|
|
||||||
Rational(self.0 / other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Div<&Rational> for &Rational {
|
|
||||||
type Output = Rational;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn div(self, other: &Rational) -> Self::Output {
|
|
||||||
Rational(&self.0 / &other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Assign<Src = Self> {
|
|
||||||
fn assign(&mut self, src: Src);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Assign<&Rational> for (&mut Rational, &mut Integer) {
|
|
||||||
fn assign(&mut self, _src: &Rational) {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod ops {
|
|
||||||
use super::{Integer, Rational};
|
|
||||||
|
|
||||||
pub trait Pow<Rhs> {
|
|
||||||
type Output;
|
|
||||||
fn pow(self, rhs: Rhs) -> Self::Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pow<u32> for Integer {
|
|
||||||
type Output = Integer;
|
|
||||||
|
|
||||||
fn pow(self, rhs: u32) -> Self::Output {
|
|
||||||
Integer(num_traits::Pow::pow(&self.0, rhs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait PowAssign<Rhs> {
|
|
||||||
fn pow_assign(&mut self, rhs: Rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PowAssign<u32> for Integer {
|
|
||||||
fn pow_assign(&mut self, rhs: u32) {
|
|
||||||
// FIXME: make it efficient
|
|
||||||
self.0 = num_traits::Pow::pow(&self.0, rhs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait NegAssign {
|
|
||||||
fn neg_assign(&mut self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NegAssign for Integer {
|
|
||||||
fn neg_assign(&mut self) {
|
|
||||||
self.0 = -std::mem::replace(self, Integer::new()).0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NegAssign for Rational {
|
|
||||||
#[inline]
|
|
||||||
fn neg_assign(&mut self) {
|
|
||||||
self.0 = -std::mem::replace(self, Rational::new()).0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod rand {
|
|
||||||
use super::Integer;
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
pub struct RandState<'a>{
|
|
||||||
_marker: PhantomData<&'a ()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> RandState<'a> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
unsafe { libc::srand(libc::time(std::ptr::null_mut()) as _) };
|
|
||||||
RandState { _marker: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn borrow_mut(&self) -> &Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bits(&mut self, bits: u32) -> u32 {
|
|
||||||
assert!(bits <= 32);
|
|
||||||
(unsafe { libc::rand() } as u32) & (u32::max_value() >> (32 - bits))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn seed(&mut self, seed: &Integer) {
|
|
||||||
unsafe { libc::srand(seed.to_f64() as _)}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use super::ops::NegAssign;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn bits() {
|
|
||||||
let mut rand = rand::RandState::new();
|
|
||||||
for bits in 1..32 {
|
|
||||||
for _ in 0..100 {
|
|
||||||
let r = rand.bits(bits);
|
|
||||||
let max = 1 << bits;
|
|
||||||
assert!(max > r, "{} > {}", max, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn neg_rational() {
|
|
||||||
let mut x = Rational::from_f64(5.0).unwrap();
|
|
||||||
let x_neg = Rational::from_f64(-5.0).unwrap();
|
|
||||||
x.neg_assign();
|
|
||||||
assert_eq!(x, x_neg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn neg_integer() {
|
|
||||||
let mut x = Integer::from(5);
|
|
||||||
let x_neg = Integer::from(-5);
|
|
||||||
x.neg_assign();
|
|
||||||
assert_eq!(x, x_neg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "static-string-indexing"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
proc-macro2 = "*"
|
|
||||||
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
|
|
||||||
indexmap = "*"
|
|
||||||
walkdir = "2"
|
|
||||||
quote = "*"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "to-syn-value"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
|
|
||||||
to-syn-value_derive = { path = "../to-syn-value_derive" }
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
pub trait ToDeriveInput {
|
|
||||||
fn to_derive_input() -> syn::DeriveInput;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "to-syn-value_derive"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
proc-macro2 = "*"
|
|
||||||
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
|
|
||||||
quote = "*"
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
use syn::*;
|
|
||||||
use quote::*;
|
|
||||||
|
|
||||||
#[proc_macro_derive(ToDeriveInput)]
|
|
||||||
pub fn derive_to_derive_input(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
||||||
let derive_input = parse_macro_input!(input as DeriveInput);
|
|
||||||
let ty_name = derive_input.ident.clone();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
use to_syn_value::*;
|
|
||||||
|
|
||||||
impl ToDeriveInput for #ty_name {
|
|
||||||
fn to_derive_input() -> syn::DeriveInput {
|
|
||||||
syn::parse_quote! {
|
|
||||||
#derive_input
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.into()
|
|
||||||
}
|
|
||||||
31
scryer-prolog.wxs
Normal file
31
scryer-prolog.wxs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||||
|
<Product Name="Scryer Prolog" Manufacturer="Scryer Prolog contributors" Id="*" UpgradeCode="cfb2dee4-5dd5-4d7d-b426-cd7340810559" Language="1033" Codepage="1252" Version="0.9.0">
|
||||||
|
<Package Description="An open source industrial strength production environment for ISO Prolog that is also a testbed for bleeding edge research in logic and constraint programming, which is itself written in a high-level language." Platform="x64" Keywords="prolog" Id="*" Compressed="yes" InstallScope="perMachine" InstallerVersion="300" Languages="1033" SummaryCodepage="1252" Manufacturer="Scryer Prolog contributors"/>
|
||||||
|
<Property Id="APPHELPLINK" Value="https://github.com/mthom/scryer-prolog"/>
|
||||||
|
<Media Id="1" Cabinet="scryer.cab" EmbedCab="yes" />
|
||||||
|
|
||||||
|
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||||
|
<Directory Id="ProgramFilesFolder" Name="PFiles">
|
||||||
|
<Directory Id="INSTALLDIR" Name="Scryer Prolog">
|
||||||
|
<Component Id="MainExecutable" Guid="1b41ceda-ba18-47f9-911b-ee41b4f20921">
|
||||||
|
<File Id="ScryerPrologEXE" Name="scryer-prolog.exe" DiskId="1" Source="target/release/scryer-prolog.exe" KeyPath="yes" Checksum="yes"/>
|
||||||
|
</Component>
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
<Directory Id="ProgramMenuFolder">
|
||||||
|
<Component Id="ApplicationShortcut" Guid="8c9b14a3-e7b1-4d30-a892-61d7371dcae2">
|
||||||
|
<Shortcut Id="ApplicationStarMenuShortcut" Name="Scryer Prolog" Description="Launch Scryer Prolog" Target="[#ScryerPrologEXE]" WorkingDirectory="INSTALLDIR"/>
|
||||||
|
<RemoveFolder Id="ApplicationShortcut" On="uninstall"/>
|
||||||
|
<RegistryValue Root="HKCU" Key="Software\Microsoft\ScryerProlog" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
|
||||||
|
</Component>
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<Feature Id="Complete" Level="1" Display="expand" ConfigurableDirectory="INSTALLDIR">
|
||||||
|
<ComponentRef Id="MainExecutable"/>
|
||||||
|
<ComponentRef Id="ApplicationShortcut"/>
|
||||||
|
</Feature>
|
||||||
|
</Product>
|
||||||
|
</Wix>
|
||||||
|
|
||||||
@@ -59,6 +59,7 @@ pub(crate) trait Allocator {
|
|||||||
fn bindings_mut(&mut self) -> &mut AllocVarDict;
|
fn bindings_mut(&mut self) -> &mut AllocVarDict;
|
||||||
|
|
||||||
fn take_bindings(self) -> AllocVarDict;
|
fn take_bindings(self) -> AllocVarDict;
|
||||||
|
fn max_reg_allocated(&self) -> usize;
|
||||||
|
|
||||||
fn drain_var_data<'a>(
|
fn drain_var_data<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
483
src/arena.rs
483
src/arena.rs
@@ -1,11 +1,12 @@
|
|||||||
|
use crate::http::{HttpListener, HttpResponse};
|
||||||
use crate::machine::loader::LiveLoadState;
|
use crate::machine::loader::LiveLoadState;
|
||||||
use crate::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::machine::streams::*;
|
use crate::machine::streams::*;
|
||||||
|
use crate::raw_block::*;
|
||||||
use crate::read::*;
|
use crate::read::*;
|
||||||
|
|
||||||
use modular_bitfield::prelude::*;
|
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use rug::{Integer, Rational};
|
use crate::parser::rug::{Integer, Rational};
|
||||||
|
|
||||||
use std::alloc;
|
use std::alloc;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -20,14 +21,116 @@ macro_rules! arena_alloc {
|
|||||||
($e:expr, $arena:expr) => {{
|
($e:expr, $arena:expr) => {{
|
||||||
let result = $e;
|
let result = $e;
|
||||||
#[allow(unused_unsafe)]
|
#[allow(unused_unsafe)]
|
||||||
unsafe { $arena.alloc(result) }
|
unsafe { ArenaAllocated::alloc($arena, result) }
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! float_alloc {
|
||||||
|
($e:expr, $arena:expr) => {{
|
||||||
|
let result = $e;
|
||||||
|
#[allow(unused_unsafe)]
|
||||||
|
unsafe { $arena.f64_tbl.build_with(result) }
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
const F64_TABLE_INIT_SIZE: usize = 1 << 16;
|
||||||
|
const F64_TABLE_ALIGN: usize = 8;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
thread_local! {
|
||||||
|
static F64_TABLE_BUF_BASE: RefCell<*const u8> = RefCell::new(ptr::null_mut());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
static mut F64_TABLE_BUF_BASE: *const u8 = ptr::null_mut();
|
||||||
|
|
||||||
|
impl RawBlockTraits for F64Table {
|
||||||
|
#[inline]
|
||||||
|
fn init_size() -> usize {
|
||||||
|
F64_TABLE_INIT_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn align() -> usize {
|
||||||
|
F64_TABLE_ALIGN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct F64Table {
|
||||||
|
block: RawBlock<F64Table>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for F64Table {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.block.deallocate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn set_f64_tbl_buf_base(ptr: *const u8) {
|
||||||
|
F64_TABLE_BUF_BASE.with(|f64_table_buf_base| {
|
||||||
|
*f64_table_buf_base.borrow_mut() = ptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) fn get_f64_tbl_buf_base() -> *const u8 {
|
||||||
|
F64_TABLE_BUF_BASE.with(|f64_table_buf_base| *f64_table_buf_base.borrow())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
fn set_f64_tbl_buf_base(ptr: *const u8) {
|
||||||
|
unsafe {
|
||||||
|
F64_TABLE_BUF_BASE = ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
pub(crate) fn get_f64_tbl_buf_base() -> *const u8 {
|
||||||
|
unsafe { F64_TABLE_BUF_BASE }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn lookup_float(offset: usize) -> *mut OrderedFloat<f64> {
|
||||||
|
let base = get_f64_tbl_buf_base() as usize;
|
||||||
|
(base + offset) as *mut _
|
||||||
|
}
|
||||||
|
|
||||||
|
impl F64Table {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let table = Self { block: RawBlock::new() };
|
||||||
|
set_f64_tbl_buf_base(table.block.base);
|
||||||
|
table
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn build_with(&mut self, value: f64) -> F64Ptr {
|
||||||
|
let mut ptr;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
ptr = self.block.alloc(mem::size_of::<f64>());
|
||||||
|
|
||||||
|
if ptr.is_null() {
|
||||||
|
self.block.grow();
|
||||||
|
set_f64_tbl_buf_base(self.block.base);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr::write(ptr as *mut OrderedFloat<f64>, OrderedFloat(value));
|
||||||
|
F64Ptr(ptr::NonNull::new_unchecked(ptr as *mut _))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
|
||||||
#[bits = 7]
|
#[bits = 7]
|
||||||
pub enum ArenaHeaderTag {
|
pub enum ArenaHeaderTag {
|
||||||
F64 = 0b01,
|
|
||||||
Integer = 0b10,
|
Integer = 0b10,
|
||||||
Rational = 0b11,
|
Rational = 0b11,
|
||||||
OssifiedOpDir = 0b0000100,
|
OssifiedOpDir = 0b0000100,
|
||||||
@@ -37,6 +140,8 @@ pub enum ArenaHeaderTag {
|
|||||||
OutputFileStream = 0b10100,
|
OutputFileStream = 0b10100,
|
||||||
NamedTcpStream = 0b011100,
|
NamedTcpStream = 0b011100,
|
||||||
NamedTlsStream = 0b100000,
|
NamedTlsStream = 0b100000,
|
||||||
|
HttpReadStream = 0b100001,
|
||||||
|
HttpWriteStream = 0b100010,
|
||||||
ReadlineStream = 0b110000,
|
ReadlineStream = 0b110000,
|
||||||
StaticStringStream = 0b110100,
|
StaticStringStream = 0b110100,
|
||||||
ByteStream = 0b111000,
|
ByteStream = 0b111000,
|
||||||
@@ -44,7 +149,13 @@ pub enum ArenaHeaderTag {
|
|||||||
StandardErrorStream = 0b11000,
|
StandardErrorStream = 0b11000,
|
||||||
NullStream = 0b111100,
|
NullStream = 0b111100,
|
||||||
TcpListener = 0b1000000,
|
TcpListener = 0b1000000,
|
||||||
|
HttpListener = 0b1000001,
|
||||||
|
HttpResponse = 0b1000010,
|
||||||
Dropped = 0b1000100,
|
Dropped = 0b1000100,
|
||||||
|
IndexPtrDynamicUndefined = 0b1000101,
|
||||||
|
IndexPtrDynamicIndex = 0b1000110,
|
||||||
|
IndexPtrIndex = 0b1000111,
|
||||||
|
IndexPtrUndefined = 0b1001000,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bitfield]
|
#[bitfield]
|
||||||
@@ -72,9 +183,15 @@ impl ArenaHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialOrd, Ord)]
|
#[derive(Debug)]
|
||||||
pub struct TypedArenaPtr<T: ?Sized>(ptr::NonNull<T>);
|
pub struct TypedArenaPtr<T: ?Sized>(ptr::NonNull<T>);
|
||||||
|
|
||||||
|
impl<T: ?Sized + PartialOrd> PartialOrd for TypedArenaPtr<T> {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
(**self).partial_cmp(&**other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ?Sized + PartialEq> PartialEq for TypedArenaPtr<T> {
|
impl<T: ?Sized + PartialEq> PartialEq for TypedArenaPtr<T> {
|
||||||
fn eq(&self, other: &TypedArenaPtr<T>) -> bool {
|
fn eq(&self, other: &TypedArenaPtr<T>) -> bool {
|
||||||
self.0 == other.0 || &**self == &**other
|
self.0 == other.0 || &**self == &**other
|
||||||
@@ -83,6 +200,12 @@ impl<T: ?Sized + PartialEq> PartialEq for TypedArenaPtr<T> {
|
|||||||
|
|
||||||
impl<T: ?Sized + PartialEq> Eq for TypedArenaPtr<T> {}
|
impl<T: ?Sized + PartialEq> Eq for TypedArenaPtr<T> {}
|
||||||
|
|
||||||
|
impl<T: ?Sized + Ord> Ord for TypedArenaPtr<T> {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
(**self).cmp(&**other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ?Sized + Hash> Hash for TypedArenaPtr<T> {
|
impl<T: ?Sized + Hash> Hash for TypedArenaPtr<T> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||||
@@ -118,7 +241,7 @@ impl<T: fmt::Display> fmt::Display for TypedArenaPtr<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> TypedArenaPtr<T> {
|
impl<T: ?Sized + ArenaAllocated> TypedArenaPtr<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn new(data: *mut T) -> Self {
|
pub const fn new(data: *mut T) -> Self {
|
||||||
unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) }
|
unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) }
|
||||||
@@ -132,14 +255,14 @@ impl<T: ?Sized> TypedArenaPtr<T> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn header_ptr(&self) -> *const ArenaHeader {
|
pub fn header_ptr(&self) -> *const ArenaHeader {
|
||||||
let mut ptr = self.as_ptr() as *const u8 as usize;
|
let mut ptr = self.as_ptr() as *const u8 as usize;
|
||||||
ptr -= mem::size_of::<*const ArenaHeader>();
|
ptr -= T::header_offset_from_payload(); // mem::size_of::<*const ArenaHeader>();
|
||||||
ptr as *const ArenaHeader
|
ptr as *const ArenaHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
|
fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
|
||||||
let mut ptr = self.as_ptr() as *const u8 as usize;
|
let mut ptr = self.as_ptr() as *const u8 as usize;
|
||||||
ptr -= mem::size_of::<*const ArenaHeader>();
|
ptr -= T::header_offset_from_payload(); // mem::size_of::<*const ArenaHeader>();
|
||||||
ptr as *mut ArenaHeader
|
ptr as *mut ArenaHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,18 +296,66 @@ impl<T: ?Sized> TypedArenaPtr<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ArenaAllocated {
|
pub trait ArenaAllocated: Sized {
|
||||||
type PtrToAllocated;
|
type PtrToAllocated;
|
||||||
|
|
||||||
fn tag() -> ArenaHeaderTag;
|
fn tag() -> ArenaHeaderTag;
|
||||||
fn size(&self) -> usize;
|
fn size(&self) -> usize;
|
||||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated
|
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated;
|
||||||
where
|
|
||||||
Self: Sized;
|
fn header_offset_from_payload() -> usize {
|
||||||
|
mem::size_of::<*const ArenaHeader>()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated {
|
||||||
|
let size = value.size() + mem::size_of::<AllocSlab>();
|
||||||
|
|
||||||
|
let align = mem::align_of::<AllocSlab>();
|
||||||
|
let layout = alloc::Layout::from_size_align_unchecked(size, align);
|
||||||
|
|
||||||
|
let slab = alloc::alloc(layout) as *mut AllocSlab;
|
||||||
|
|
||||||
|
(*slab).next = arena.base;
|
||||||
|
(*slab).header = ArenaHeader::build_with(value.size() as u64, Self::tag());
|
||||||
|
|
||||||
|
let offset = (*slab).payload_offset();
|
||||||
|
let result = value.copy_to_arena(offset as *mut Self);
|
||||||
|
|
||||||
|
arena.base = slab;
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct F64Ptr(pub TypedArenaPtr<OrderedFloat<f64>>);
|
pub struct F64Ptr(pub ptr::NonNull<OrderedFloat<f64>>);
|
||||||
|
|
||||||
|
impl PartialEq for F64Ptr {
|
||||||
|
fn eq(&self, other: &F64Ptr) -> bool {
|
||||||
|
self.0 == other.0 || &**self == &**other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for F64Ptr {}
|
||||||
|
|
||||||
|
impl PartialOrd for F64Ptr {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
(**self).partial_cmp(&**other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for F64Ptr {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
(**self).cmp(&**other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for F64Ptr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||||
|
(&*self as &OrderedFloat<f64>).hash(hasher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for F64Ptr {
|
impl fmt::Display for F64Ptr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
@@ -193,41 +364,94 @@ impl fmt::Display for F64Ptr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for F64Ptr {
|
impl Deref for F64Ptr {
|
||||||
type Target = TypedArenaPtr<OrderedFloat<f64>>;
|
type Target = OrderedFloat<f64>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
unsafe { &*self.0.as_ptr() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for F64Ptr {
|
impl DerefMut for F64Ptr {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.0
|
unsafe { &mut *self.0.as_ptr() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArenaAllocated for OrderedFloat<f64> {
|
impl F64Ptr {
|
||||||
type PtrToAllocated = F64Ptr;
|
#[inline(always)]
|
||||||
|
pub fn from_offset(offset: usize) -> Self {
|
||||||
#[inline]
|
|
||||||
fn tag() -> ArenaHeaderTag {
|
|
||||||
ArenaHeaderTag::F64
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn size(&self) -> usize {
|
|
||||||
mem::size_of::<Self>()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::write(dst, self);
|
F64Ptr(ptr::NonNull::new_unchecked(lookup_float(offset)))
|
||||||
F64Ptr(TypedArenaPtr::new(dst as *mut Self))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn as_offset(&self) -> F64Offset {
|
||||||
|
F64Offset(self.0.as_ptr() as usize - get_f64_tbl_buf_base() as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct F64Offset(usize);
|
||||||
|
|
||||||
|
impl F64Offset {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new(offset: usize) -> Self {
|
||||||
|
Self(offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn from_ptr(ptr: F64Ptr) -> Self {
|
||||||
|
ptr.as_offset()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn as_ptr(self) -> F64Ptr {
|
||||||
|
F64Ptr::from_offset(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn to_u64(self) -> u64 {
|
||||||
|
self.0 as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for F64Offset {
|
||||||
|
#[inline(always)]
|
||||||
|
fn eq(&self, other: &F64Offset) -> bool {
|
||||||
|
self.as_ptr() == other.as_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for F64Offset {}
|
||||||
|
|
||||||
|
impl PartialOrd for F64Offset {
|
||||||
|
#[inline(always)]
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
self.as_ptr().partial_cmp(&other.as_ptr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for F64Offset {
|
||||||
|
#[inline(always)]
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.as_ptr().cmp(&other.as_ptr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for F64Offset {
|
||||||
|
#[inline(always)]
|
||||||
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||||
|
self.as_ptr().hash(hasher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for F64Offset {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "F64Offset({})", self.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArenaAllocated for Integer {
|
impl ArenaAllocated for Integer {
|
||||||
@@ -340,6 +564,93 @@ impl ArenaAllocated for TcpListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ArenaAllocated for HttpListener {
|
||||||
|
type PtrToAllocated = TypedArenaPtr<HttpListener>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn tag() -> ArenaHeaderTag {
|
||||||
|
ArenaHeaderTag::HttpListener
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
mem::size_of::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||||
|
unsafe {
|
||||||
|
ptr::write(dst, self);
|
||||||
|
TypedArenaPtr::new(dst as *mut Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArenaAllocated for HttpResponse {
|
||||||
|
type PtrToAllocated = TypedArenaPtr<HttpResponse>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn tag() -> ArenaHeaderTag {
|
||||||
|
ArenaHeaderTag::HttpResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
mem::size_of::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||||
|
unsafe {
|
||||||
|
ptr::write(dst, self);
|
||||||
|
TypedArenaPtr::new(dst as *mut Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArenaAllocated for IndexPtr {
|
||||||
|
type PtrToAllocated = TypedArenaPtr<IndexPtr>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn tag() -> ArenaHeaderTag {
|
||||||
|
ArenaHeaderTag::IndexPtrUndefined
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
mem::size_of::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||||
|
unsafe {
|
||||||
|
ptr::write(dst, self);
|
||||||
|
TypedArenaPtr::new(dst as *mut Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn header_offset_from_payload() -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated {
|
||||||
|
let size = mem::size_of::<AllocSlab>();
|
||||||
|
|
||||||
|
let align = mem::align_of::<AllocSlab>();
|
||||||
|
let layout = alloc::Layout::from_size_align_unchecked(size, align);
|
||||||
|
|
||||||
|
let slab = alloc::alloc(layout) as *mut AllocSlab;
|
||||||
|
|
||||||
|
(*slab).next = arena.base;
|
||||||
|
|
||||||
|
let result = value.copy_to_arena(mem::transmute::<_, *mut IndexPtr>(&(*slab).header));
|
||||||
|
arena.base = slab;
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct AllocSlab {
|
struct AllocSlab {
|
||||||
next: *mut AllocSlab,
|
next: *mut AllocSlab,
|
||||||
@@ -347,7 +658,10 @@ struct AllocSlab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Arena(*mut AllocSlab);
|
pub struct Arena {
|
||||||
|
base: *mut AllocSlab,
|
||||||
|
pub f64_tbl: F64Table,
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl Send for Arena {}
|
unsafe impl Send for Arena {}
|
||||||
unsafe impl Sync for Arena {}
|
unsafe impl Sync for Arena {}
|
||||||
@@ -355,26 +669,7 @@ unsafe impl Sync for Arena {}
|
|||||||
impl Arena {
|
impl Arena {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Arena(ptr::null_mut())
|
Arena { base: ptr::null_mut(), f64_tbl: F64Table::new() }
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn alloc<T: ArenaAllocated>(&mut self, value: T) -> T::PtrToAllocated {
|
|
||||||
let size = value.size() + mem::size_of::<AllocSlab>();
|
|
||||||
|
|
||||||
let align = mem::align_of::<AllocSlab>();
|
|
||||||
let layout = alloc::Layout::from_size_align_unchecked(size, align);
|
|
||||||
|
|
||||||
let slab = alloc::alloc(layout) as *mut AllocSlab;
|
|
||||||
|
|
||||||
(*slab).next = self.0;
|
|
||||||
(*slab).header = ArenaHeader::build_with(value.size() as u64, T::tag());
|
|
||||||
|
|
||||||
let offset = (*slab).payload_offset();
|
|
||||||
let result = value.copy_to_arena(offset as *mut T);
|
|
||||||
|
|
||||||
self.0 = slab;
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,6 +695,12 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
|
|||||||
ArenaHeaderTag::NamedTlsStream => {
|
ArenaHeaderTag::NamedTlsStream => {
|
||||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>());
|
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>());
|
||||||
}
|
}
|
||||||
|
ArenaHeaderTag::HttpReadStream => {
|
||||||
|
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpReadStream>>>());
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::HttpWriteStream => {
|
||||||
|
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpWriteStream>>>());
|
||||||
|
}
|
||||||
ArenaHeaderTag::ReadlineStream => {
|
ArenaHeaderTag::ReadlineStream => {
|
||||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>());
|
ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>());
|
||||||
}
|
}
|
||||||
@@ -420,20 +721,28 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
|
|||||||
ArenaHeaderTag::TcpListener => {
|
ArenaHeaderTag::TcpListener => {
|
||||||
ptr::drop_in_place(value.payload_offset::<TcpListener>());
|
ptr::drop_in_place(value.payload_offset::<TcpListener>());
|
||||||
}
|
}
|
||||||
|
ArenaHeaderTag::HttpListener => {
|
||||||
|
ptr::drop_in_place(value.payload_offset::<HttpListener>());
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::HttpResponse => {
|
||||||
|
ptr::drop_in_place(value.payload_offset::<HttpResponse>());
|
||||||
|
}
|
||||||
ArenaHeaderTag::StandardOutputStream => {
|
ArenaHeaderTag::StandardOutputStream => {
|
||||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>());
|
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>());
|
||||||
}
|
}
|
||||||
ArenaHeaderTag::StandardErrorStream => {
|
ArenaHeaderTag::StandardErrorStream => {
|
||||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardErrorStream>>());
|
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardErrorStream>>());
|
||||||
}
|
}
|
||||||
ArenaHeaderTag::F64 | ArenaHeaderTag::NullStream => {
|
ArenaHeaderTag::NullStream | ArenaHeaderTag::IndexPtrUndefined |
|
||||||
|
ArenaHeaderTag::IndexPtrDynamicUndefined | ArenaHeaderTag::IndexPtrDynamicIndex |
|
||||||
|
ArenaHeaderTag::IndexPtrIndex => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Arena {
|
impl Drop for Arena {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let mut ptr = self.0;
|
let mut ptr = self.base;
|
||||||
|
|
||||||
while !ptr.is_null() {
|
while !ptr.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -452,7 +761,7 @@ impl Drop for Arena {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.0 = ptr::null_mut();
|
self.base = ptr::null_mut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,27 +788,27 @@ mod tests {
|
|||||||
use crate::machine::partial_string::*;
|
use crate::machine::partial_string::*;
|
||||||
|
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use rug::{Integer, Rational};
|
use crate::parser::rug::{Integer, Rational};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn float_ptr_cast() {
|
fn float_ptr_cast() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
let f = OrderedFloat(0f64);
|
let f = 0f64;
|
||||||
let mut fp = arena_alloc!(f, &mut wam.machine_st.arena);
|
let fp = float_alloc!(f, wam.machine_st.arena);
|
||||||
let cell = HeapCellValue::from(fp);
|
let mut cell = HeapCellValue::from(fp);
|
||||||
|
|
||||||
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
|
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
|
||||||
assert_eq!(fp.get_mark_bit(), false);
|
assert_eq!(cell.get_mark_bit(), false);
|
||||||
assert_eq!(**fp, f);
|
assert_eq!(*fp, OrderedFloat(f));
|
||||||
|
|
||||||
fp.mark();
|
cell.set_mark_bit(true);
|
||||||
|
|
||||||
assert_eq!(fp.get_mark_bit(), true);
|
assert_eq!(cell.get_mark_bit(), true);
|
||||||
|
|
||||||
read_heap_cell!(cell,
|
read_heap_cell!(cell,
|
||||||
(HeapCellValueTag::F64, ptr) => {
|
(HeapCellValueTag::F64, ptr) => {
|
||||||
assert_eq!(**ptr, f)
|
assert_eq!(OrderedFloat(*ptr), OrderedFloat(f))
|
||||||
}
|
}
|
||||||
_ => { unreachable!() }
|
_ => { unreachable!() }
|
||||||
);
|
);
|
||||||
@@ -542,8 +851,9 @@ mod tests {
|
|||||||
|
|
||||||
// integer
|
// integer
|
||||||
|
|
||||||
let big_int = 2 * Integer::from(1u64 << 63);
|
let big_int: Integer = 2 * Integer::from(1u64 << 63);
|
||||||
let big_int_ptr: TypedArenaPtr<Integer> = arena_alloc!(big_int, &mut wam.machine_st.arena);
|
let big_int_ptr: TypedArenaPtr<Integer> =
|
||||||
|
arena_alloc!(big_int, &mut wam.machine_st.arena);
|
||||||
|
|
||||||
assert!(!big_int_ptr.as_ptr().is_null());
|
assert!(!big_int_ptr.as_ptr().is_null());
|
||||||
|
|
||||||
@@ -696,16 +1006,16 @@ mod tests {
|
|||||||
_ => { unreachable!() }
|
_ => { unreachable!() }
|
||||||
);
|
);
|
||||||
|
|
||||||
let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 55));
|
let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 54));
|
||||||
|
|
||||||
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
|
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
|
||||||
|
|
||||||
match fixnum_b_cell.to_fixnum() {
|
match fixnum_b_cell.to_fixnum() {
|
||||||
Some(n) => assert_eq!(n.get_num(), 1 << 55),
|
Some(n) => assert_eq!(n.get_num(), 1 << 54),
|
||||||
None => assert!(false),
|
None => assert!(false),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Fixnum::build_with_checked(1 << 57) {
|
match Fixnum::build_with_checked(1 << 56) {
|
||||||
Ok(_) => assert!(false),
|
Ok(_) => assert!(false),
|
||||||
_ => assert!(true),
|
_ => assert!(true),
|
||||||
}
|
}
|
||||||
@@ -725,17 +1035,17 @@ mod tests {
|
|||||||
_ => assert!(false),
|
_ => assert!(false),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Fixnum::build_with_checked((1 << 56) - 1) {
|
match Fixnum::build_with_checked((1 << 55) - 1) {
|
||||||
Ok(n) => assert_eq!(n.get_num(), (1 << 56) - 1),
|
Ok(n) => assert_eq!(n.get_num(), (1 << 55) - 1),
|
||||||
_ => assert!(false),
|
_ => assert!(false),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Fixnum::build_with_checked(-(1 << 56)) {
|
match Fixnum::build_with_checked(-(1 << 55)) {
|
||||||
Ok(n) => assert_eq!(n.get_num(), -(1 << 56)),
|
Ok(n) => assert_eq!(n.get_num(), -(1 << 55)),
|
||||||
_ => assert!(false),
|
_ => assert!(false),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Fixnum::build_with_checked(-(1 << 56) - 1) {
|
match Fixnum::build_with_checked(-(1 << 55) - 1) {
|
||||||
Ok(_n) => assert!(false),
|
Ok(_n) => assert!(false),
|
||||||
_ => assert!(true),
|
_ => assert!(true),
|
||||||
}
|
}
|
||||||
@@ -747,22 +1057,11 @@ mod tests {
|
|||||||
|
|
||||||
// float
|
// float
|
||||||
|
|
||||||
let float = OrderedFloat(3.1415926f64);
|
let float = 3.1415926f64;
|
||||||
let float_ptr = arena_alloc!(float, &mut wam.machine_st.arena);
|
let float_ptr = float_alloc!(float, wam.machine_st.arena);
|
||||||
|
let cell = HeapCellValue::from(float_ptr);
|
||||||
|
|
||||||
assert!(!float_ptr.as_ptr().is_null());
|
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
|
||||||
|
|
||||||
let float_cell = typed_arena_ptr_as_cell!(float_ptr);
|
|
||||||
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
|
|
||||||
|
|
||||||
match float_cell.to_untyped_arena_ptr() {
|
|
||||||
Some(untyped_arena_ptr) => {
|
|
||||||
assert_eq!(Some(float_ptr.header_ptr()), Some(untyped_arena_ptr.into()),);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
assert!(false); // we fail.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// char
|
// char
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use crate::allocator::*;
|
use crate::allocator::*;
|
||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::fixtures::*;
|
use crate::debray_allocator::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::iterators::*;
|
use crate::iterators::*;
|
||||||
|
use crate::targets::QueryInstruction;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
@@ -12,7 +13,6 @@ use crate::parser::rug::ops::PowAssign;
|
|||||||
use crate::parser::rug::{Assign, Integer, Rational};
|
use crate::parser::rug::{Assign, Integer, Rational};
|
||||||
|
|
||||||
use crate::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::machine::machine_indices::*;
|
|
||||||
|
|
||||||
use ordered_float::*;
|
use ordered_float::*;
|
||||||
|
|
||||||
@@ -64,21 +64,24 @@ impl<'a> ArithInstructionIterator<'a> {
|
|||||||
fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
|
fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
|
||||||
let state = match term {
|
let state = match term {
|
||||||
Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
|
Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
|
||||||
Term::Clause(cell, name, terms) => match ClauseType::from(*name, terms.len()) {
|
Term::Clause(cell, name, terms) => {
|
||||||
|
TermIterState::Clause(Level::Shallow, 0, cell, *name, terms)
|
||||||
|
}
|
||||||
|
/* match ClauseType::from(*name, terms.len()) {
|
||||||
ct @ ClauseType::Named(..) => {
|
ct @ ClauseType::Named(..) => {
|
||||||
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
||||||
}
|
}
|
||||||
ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
|
ct @ ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
|
||||||
let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
|
// let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
|
||||||
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
||||||
}
|
}
|
||||||
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||||
Literal::Atom(*name),
|
Literal::Atom(*name),
|
||||||
terms.len(),
|
terms.len(),
|
||||||
)),
|
)),
|
||||||
}?,
|
}?,*/
|
||||||
Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
|
Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
|
||||||
Term::Cons(..) | Term::PartialString(..) => {
|
Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => {
|
||||||
return Err(ArithmeticError::NonEvaluableFunctor(
|
return Err(ArithmeticError::NonEvaluableFunctor(
|
||||||
Literal::Atom(atom!(".")),
|
Literal::Atom(atom!(".")),
|
||||||
2,
|
2,
|
||||||
@@ -107,29 +110,26 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
|||||||
while let Some(iter_state) = self.state_stack.pop() {
|
while let Some(iter_state) = self.state_stack.pop() {
|
||||||
match iter_state {
|
match iter_state {
|
||||||
TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)),
|
TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)),
|
||||||
TermIterState::Clause(lvl, child_num, cell, ct, subterms) => {
|
TermIterState::Clause(lvl, child_num, cell, name, subterms) => {
|
||||||
let arity = subterms.len();
|
let arity = subterms.len();
|
||||||
|
|
||||||
if child_num == arity {
|
if child_num == arity {
|
||||||
return Some(Ok(ArithTermRef::Op(ct.name(), arity)));
|
return Some(Ok(ArithTermRef::Op(name, arity)));
|
||||||
} else {
|
} else {
|
||||||
self.state_stack.push(TermIterState::Clause(
|
self.state_stack.push(TermIterState::Clause(
|
||||||
lvl,
|
lvl,
|
||||||
child_num + 1,
|
child_num + 1,
|
||||||
cell,
|
cell,
|
||||||
ct,
|
name,
|
||||||
subterms,
|
subterms,
|
||||||
));
|
));
|
||||||
|
|
||||||
self.push_subterm(lvl, &subterms[child_num]);
|
self.push_subterm(lvl.child_level(), &subterms[child_num]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
|
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
|
||||||
TermIterState::Var(lvl, cell, var) => {
|
TermIterState::Var(lvl, cell, var) => {
|
||||||
// the expression is the second argument of an
|
return Some(Ok(ArithTermRef::Var(lvl, cell, var.clone())));
|
||||||
// is/2 but the iterator can't see that, so the
|
|
||||||
// level needs to be demoted manually.
|
|
||||||
return Some(Ok(ArithTermRef::Var(lvl.child_level(), cell, var.clone())));
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Some(Err(ArithmeticError::NonEvaluableFunctor(
|
return Some(Err(ArithmeticError::NonEvaluableFunctor(
|
||||||
@@ -145,8 +145,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct ArithmeticEvaluator<'a, TermMarker> {
|
pub(crate) struct ArithmeticEvaluator<'a> {
|
||||||
marker: &'a mut TermMarker,
|
marker: &'a mut DebrayAllocator,
|
||||||
interm: Vec<ArithmeticTerm>,
|
interm: Vec<ArithmeticTerm>,
|
||||||
interm_c: usize,
|
interm_c: usize,
|
||||||
}
|
}
|
||||||
@@ -169,16 +169,16 @@ fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), Ari
|
|||||||
match c {
|
match c {
|
||||||
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
|
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
|
||||||
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
|
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
|
||||||
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(***n))),
|
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))),
|
||||||
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
|
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
|
||||||
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
|
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
|
||||||
Number::Float(OrderedFloat(f64::consts::E)),
|
Number::Float(OrderedFloat(std::f64::consts::E))
|
||||||
)),
|
)),
|
||||||
Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
|
Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
|
||||||
Number::Float(OrderedFloat(f64::consts::PI)),
|
Number::Float(OrderedFloat(std::f64::consts::PI))
|
||||||
)),
|
)),
|
||||||
Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
|
Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
|
||||||
Number::Float(OrderedFloat(f64::EPSILON)),
|
Number::Float(OrderedFloat(std::f64::EPSILON))
|
||||||
)),
|
)),
|
||||||
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
|
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
|
||||||
}
|
}
|
||||||
@@ -186,8 +186,8 @@ fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), Ari
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
|
impl<'a> ArithmeticEvaluator<'a> {
|
||||||
pub(crate) fn new(marker: &'a mut TermMarker, target_int: usize) -> Self {
|
pub(crate) fn new(marker: &'a mut DebrayAllocator, target_int: usize) -> Self {
|
||||||
ArithmeticEvaluator {
|
ArithmeticEvaluator {
|
||||||
marker,
|
marker,
|
||||||
interm: Vec::new(),
|
interm: Vec::new(),
|
||||||
@@ -315,10 +315,11 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eval(
|
pub(crate) fn compile_is(
|
||||||
&mut self,
|
&mut self,
|
||||||
src: &'a Term,
|
src: &'a Term,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
|
arg: usize,
|
||||||
) -> Result<ArithCont, ArithmeticError>
|
) -> Result<ArithCont, ArithmeticError>
|
||||||
{
|
{
|
||||||
let mut code = vec![];
|
let mut code = vec![];
|
||||||
@@ -328,17 +329,15 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
|
|||||||
match term_ref? {
|
match term_ref? {
|
||||||
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
|
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
|
||||||
ArithTermRef::Var(lvl, cell, name) => {
|
ArithTermRef::Var(lvl, cell, name) => {
|
||||||
let r = if cell.get().norm().reg_num() == 0 {
|
let r = if lvl == Level::Shallow {
|
||||||
let mut getter = || {
|
self.marker.mark_non_callable(
|
||||||
use crate::targets::QueryInstruction;
|
name.clone(),
|
||||||
|
arg,
|
||||||
loop {
|
term_loc,
|
||||||
match self.marker.bindings().get(&name) {
|
cell,
|
||||||
Some(&VarData::Temp(_, t, _)) if t != 0 =>
|
&mut code,
|
||||||
return RegType::Temp(t),
|
)
|
||||||
Some(&VarData::Perm(p)) if p != 0 =>
|
} else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
|
||||||
return RegType::Perm(p),
|
|
||||||
_ => {
|
|
||||||
self.marker.mark_var::<QueryInstruction>(
|
self.marker.mark_var::<QueryInstruction>(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
lvl,
|
lvl,
|
||||||
@@ -346,15 +345,8 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
|
|||||||
term_loc,
|
term_loc,
|
||||||
&mut code,
|
&mut code,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
getter()
|
self.marker.get_binding(&name).unwrap()
|
||||||
/*
|
|
||||||
_ => return Err(ArithmeticError::UninstantiatedVar),
|
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
cell.get().norm()
|
cell.get().norm()
|
||||||
};
|
};
|
||||||
@@ -374,16 +366,38 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
|
|||||||
// integer division rounding function -- 9.1.3.1.
|
// integer division rounding function -- 9.1.3.1.
|
||||||
pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number {
|
pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number {
|
||||||
match n {
|
match n {
|
||||||
&Number::Integer(_) | &Number::Fixnum(_) => *n,
|
&Number::Integer(i) => {
|
||||||
&Number::Float(OrderedFloat(f)) => fixnum!(Number, f.floor() as i64, arena),
|
if let Some(n) = i.to_i64() {
|
||||||
|
fixnum!(Number, n, arena)
|
||||||
|
} else {
|
||||||
|
*n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&Number::Fixnum(_) => *n,
|
||||||
|
&Number::Float(f) => {
|
||||||
|
let f = f.floor();
|
||||||
|
|
||||||
|
const I64_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MIN as f64);
|
||||||
|
const I64_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MAX as f64);
|
||||||
|
|
||||||
|
if I64_MIN_TO_F <= f && f <= I64_MAX_TO_F {
|
||||||
|
fixnum!(Number, f.into_inner() as i64, arena)
|
||||||
|
} else {
|
||||||
|
Number::Integer(arena_alloc!(Integer::from_f64(f.into_inner()).unwrap(), arena))
|
||||||
|
}
|
||||||
|
}
|
||||||
&Number::Rational(ref r) => {
|
&Number::Rational(ref r) => {
|
||||||
let r_ref = r.fract_floor_ref();
|
let r_ref = r.fract_floor_ref();
|
||||||
let (mut fract, mut floor) = (Rational::new(), Integer::new());
|
let (mut fract, mut floor) = (Rational::new(), Integer::new());
|
||||||
(&mut fract, &mut floor).assign(r_ref);
|
(&mut fract, &mut floor).assign(r_ref);
|
||||||
|
|
||||||
|
if let Some(floor) = floor.to_i64() {
|
||||||
|
fixnum!(Number, floor, arena)
|
||||||
|
} else {
|
||||||
Number::Integer(arena_alloc!(floor, arena))
|
Number::Integer(arena_alloc!(floor, arena))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Fixnum> for Integer {
|
impl From<Fixnum> for Integer {
|
||||||
@@ -404,23 +418,14 @@ pub(crate) fn rnd_f(n: &Number) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// floating point result function -- 9.1.4.2.
|
// floating point result function -- 9.1.4.2.
|
||||||
pub(crate) fn result_f<Round>(n: &Number, round: Round) -> Result<f64, EvalError>
|
pub(crate) fn result_f(n: &Number) -> Result<f64, EvalError> {
|
||||||
where
|
classify_float(rnd_f(n))
|
||||||
Round: Fn(&Number) -> f64,
|
|
||||||
{
|
|
||||||
let f = rnd_f(n);
|
|
||||||
classify_float(f, round)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classify_float<Round>(f: f64, round: Round) -> Result<f64, EvalError>
|
fn classify_float(f: f64) -> Result<f64, EvalError> {
|
||||||
where
|
|
||||||
Round: Fn(&Number) -> f64,
|
|
||||||
{
|
|
||||||
match f.classify() {
|
match f.classify() {
|
||||||
FpCategory::Normal | FpCategory::Zero => Ok(round(&Number::Float(OrderedFloat(f)))),
|
FpCategory::Normal | FpCategory::Zero => Ok(f),
|
||||||
FpCategory::Infinite => {
|
FpCategory::Infinite => {
|
||||||
let f = round(&Number::Float(OrderedFloat(f)));
|
|
||||||
|
|
||||||
if OrderedFloat(f) == OrderedFloat(f64::MAX) {
|
if OrderedFloat(f) == OrderedFloat(f64::MAX) {
|
||||||
Ok(f)
|
Ok(f)
|
||||||
} else {
|
} else {
|
||||||
@@ -428,33 +433,33 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
FpCategory::Nan => Err(EvalError::Undefined),
|
FpCategory::Nan => Err(EvalError::Undefined),
|
||||||
_ => Ok(round(&Number::Float(OrderedFloat(f)))),
|
_ => Ok(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn float_fn_to_f(n: i64) -> Result<f64, EvalError> {
|
pub(crate) fn float_fn_to_f(n: i64) -> Result<f64, EvalError> {
|
||||||
classify_float(n as f64, rnd_f)
|
classify_float(n as f64)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
|
pub(crate) fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
|
||||||
classify_float(n.to_f64(), rnd_f)
|
classify_float(n.to_f64())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
|
pub(crate) fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
|
||||||
classify_float(r.to_f64(), rnd_f)
|
classify_float(r.to_f64())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
pub(crate) fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||||
Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?))
|
Ok(OrderedFloat(classify_float(f1 + f2)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
pub(crate) fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||||
Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?))
|
Ok(OrderedFloat(classify_float(f1 * f2)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -462,7 +467,7 @@ fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
|||||||
if FpCategory::Zero == f2.classify() {
|
if FpCategory::Zero == f2.classify() {
|
||||||
Err(EvalError::ZeroDivisor)
|
Err(EvalError::ZeroDivisor)
|
||||||
} else {
|
} else {
|
||||||
Ok(OrderedFloat(classify_float(f1 / f2, rnd_f)?))
|
Ok(OrderedFloat(classify_float(f1 / f2)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,9 +677,6 @@ impl TryFrom<HeapCellValue> for Number {
|
|||||||
read_heap_cell!(value,
|
read_heap_cell!(value,
|
||||||
(HeapCellValueTag::Cons, c) => {
|
(HeapCellValueTag::Cons, c) => {
|
||||||
match_untyped_arena_ptr!(c,
|
match_untyped_arena_ptr!(c,
|
||||||
(ArenaHeaderTag::F64, n) => {
|
|
||||||
Ok(Number::Float(*n))
|
|
||||||
}
|
|
||||||
(ArenaHeaderTag::Integer, n) => {
|
(ArenaHeaderTag::Integer, n) => {
|
||||||
Ok(Number::Integer(n))
|
Ok(Number::Integer(n))
|
||||||
}
|
}
|
||||||
@@ -687,7 +689,7 @@ impl TryFrom<HeapCellValue> for Number {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::F64, n) => {
|
(HeapCellValueTag::F64, n) => {
|
||||||
Ok(Number::Float(**n))
|
Ok(Number::Float(*n))
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Fixnum, n) => {
|
(HeapCellValueTag::Fixnum, n) => {
|
||||||
Ok(Number::Fixnum(n))
|
Ok(Number::Fixnum(n))
|
||||||
|
|||||||
@@ -1,20 +1,11 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
use nix::sys::signal;
|
use std::sync::atomic::Ordering;
|
||||||
use scryer_prolog::*;
|
use scryer_prolog::*;
|
||||||
|
|
||||||
let handler = signal::SigHandler::Handler(handle_sigint);
|
ctrlc::set_handler(move || {
|
||||||
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
|
scryer_prolog::machine::INTERRUPT.store(true, Ordering::Relaxed);
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
let mut wam = machine::Machine::new();
|
let mut wam = machine::Machine::new();
|
||||||
|
|
||||||
wam.run_top_level();
|
wam.run_top_level();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn handle_sigint(signal: libc::c_int) {
|
|
||||||
use nix::sys::signal;
|
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
let signal = signal::Signal::from_c_int(signal).unwrap();
|
|
||||||
if signal == signal::Signal::SIGINT {
|
|
||||||
scryer_prolog::machine::INTERRUPT.store(true, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
363
src/codegen.rs
363
src/codegen.rs
@@ -4,6 +4,7 @@ use crate::{perm_v, temp_v};
|
|||||||
|
|
||||||
use crate::allocator::*;
|
use crate::allocator::*;
|
||||||
use crate::arithmetic::*;
|
use crate::arithmetic::*;
|
||||||
|
use crate::debray_allocator::*;
|
||||||
use crate::fixtures::*;
|
use crate::fixtures::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::indexing::*;
|
use crate::indexing::*;
|
||||||
@@ -195,12 +196,22 @@ impl CodeGenSettings {
|
|||||||
Instruction::TrustMe(0)
|
Instruction::TrustMe(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn default_call_policy(&self) -> CallPolicy {
|
||||||
|
// calls are inference counted by default if and only if
|
||||||
|
// backtracking is counted too.
|
||||||
|
if self.non_counted_bt {
|
||||||
|
CallPolicy::Default
|
||||||
|
} else {
|
||||||
|
CallPolicy::Counted
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct CodeGenerator<'a, TermMarker> {
|
pub(crate) struct CodeGenerator<'a> {
|
||||||
pub(crate) atom_tbl: &'a mut AtomTable,
|
pub(crate) atom_tbl: &'a mut AtomTable,
|
||||||
marker: TermMarker,
|
marker: DebrayAllocator,
|
||||||
pub(crate) var_count: IndexMap<Rc<String>, usize>,
|
pub(crate) var_count: IndexMap<Rc<String>, usize>,
|
||||||
settings: CodeGenSettings,
|
settings: CodeGenSettings,
|
||||||
pub(crate) skeleton: PredicateSkeleton,
|
pub(crate) skeleton: PredicateSkeleton,
|
||||||
@@ -208,11 +219,76 @@ pub(crate) struct CodeGenerator<'a, TermMarker> {
|
|||||||
global_jmp_by_locs_offset: usize,
|
global_jmp_by_locs_offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
impl DebrayAllocator {
|
||||||
|
fn mark_var_in_non_callable(
|
||||||
|
&mut self,
|
||||||
|
name: Rc<String>,
|
||||||
|
term_loc: GenContext,
|
||||||
|
vr: &Cell<VarReg>,
|
||||||
|
code: &mut Code,
|
||||||
|
) -> RegType {
|
||||||
|
self.mark_var::<QueryInstruction>(name, Level::Shallow, vr, term_loc, code);
|
||||||
|
vr.get().norm()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn get_binding(&self, name: &String) -> Option<RegType> {
|
||||||
|
match self.bindings().get(name) {
|
||||||
|
Some(&VarData::Temp(_, t, _)) if t != 0 => Some(RegType::Temp(t)),
|
||||||
|
Some(&VarData::Perm(p)) if p != 0 => Some(RegType::Perm(p)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mark_non_callable(
|
||||||
|
&mut self,
|
||||||
|
name: Rc<String>,
|
||||||
|
arg: usize,
|
||||||
|
term_loc: GenContext,
|
||||||
|
vr: &Cell<VarReg>,
|
||||||
|
code: &mut Code,
|
||||||
|
) -> RegType {
|
||||||
|
match self.get_binding(&name) {
|
||||||
|
Some(RegType::Temp(t)) => RegType::Temp(t),
|
||||||
|
Some(RegType::Perm(p)) => {
|
||||||
|
if let GenContext::Last(_) = term_loc {
|
||||||
|
self.mark_var_in_non_callable(name.clone(), term_loc, vr, code);
|
||||||
|
temp_v!(arg)
|
||||||
|
} else {
|
||||||
|
RegType::Perm(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => self.mark_var_in_non_callable(name, term_loc, vr, code),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the final argument of the structure is a Literal::Index,
|
||||||
|
// decrement the arity of the PutStructure instruction by 1.
|
||||||
|
fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) {
|
||||||
|
match instr {
|
||||||
|
Instruction::PutStructure(_, ref mut arity, _) |
|
||||||
|
Instruction::GetStructure(_, ref mut arity, _) => {
|
||||||
|
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
|
||||||
|
// it is acceptable if arity == 0 is the result of
|
||||||
|
// this decrement. call/N will have to read the index
|
||||||
|
// constant for '$call_inline' to succeed. to find it,
|
||||||
|
// it must know the heap location of the index.
|
||||||
|
// self.store must stop before reading the atom into a
|
||||||
|
// register.
|
||||||
|
|
||||||
|
*arity -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> CodeGenerator<'b> {
|
||||||
pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self {
|
pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self {
|
||||||
CodeGenerator {
|
CodeGenerator {
|
||||||
atom_tbl,
|
atom_tbl,
|
||||||
marker: Allocator::new(),
|
marker: DebrayAllocator::new(),
|
||||||
var_count: IndexMap::new(),
|
var_count: IndexMap::new(),
|
||||||
settings,
|
settings,
|
||||||
skeleton: PredicateSkeleton::new(),
|
skeleton: PredicateSkeleton::new(),
|
||||||
@@ -234,45 +310,6 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
*self.var_count.get(var).unwrap()
|
*self.var_count.get(var).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_var_in_non_callable(
|
|
||||||
&mut self,
|
|
||||||
name: Rc<String>,
|
|
||||||
term_loc: GenContext,
|
|
||||||
vr: &Cell<VarReg>,
|
|
||||||
code: &mut Code,
|
|
||||||
) -> RegType {
|
|
||||||
let mut target = Code::new();
|
|
||||||
self.marker.mark_var::<QueryInstruction>(name, Level::Shallow, vr, term_loc, &mut target);
|
|
||||||
|
|
||||||
if !target.is_empty() {
|
|
||||||
code.extend(target.into_iter());
|
|
||||||
}
|
|
||||||
|
|
||||||
vr.get().norm()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_non_callable(
|
|
||||||
&mut self,
|
|
||||||
name: Rc<String>,
|
|
||||||
arg: usize,
|
|
||||||
term_loc: GenContext,
|
|
||||||
vr: &Cell<VarReg>,
|
|
||||||
code: &mut Code,
|
|
||||||
) -> RegType {
|
|
||||||
match self.marker.bindings().get(&name) {
|
|
||||||
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
|
|
||||||
Some(&VarData::Perm(p)) if p != 0 => {
|
|
||||||
if let GenContext::Last(_) = term_loc {
|
|
||||||
self.mark_var_in_non_callable(name.clone(), term_loc, vr, code);
|
|
||||||
temp_v!(arg)
|
|
||||||
} else {
|
|
||||||
RegType::Perm(p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => self.mark_var_in_non_callable(name, term_loc, vr, code),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_or_increment_void_instr<'a, Target>(target: &mut Code)
|
fn add_or_increment_void_instr<'a, Target>(target: &mut Code)
|
||||||
where
|
where
|
||||||
Target: crate::targets::CompilationTarget<'a>,
|
Target: crate::targets::CompilationTarget<'a>,
|
||||||
@@ -316,9 +353,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
&Term::AnonVar => {
|
&Term::AnonVar => {
|
||||||
Self::add_or_increment_void_instr::<Target>(target);
|
Self::add_or_increment_void_instr::<Target>(target);
|
||||||
}
|
}
|
||||||
&Term::Cons(ref cell, ..)
|
&Term::Cons(ref cell, ..) |
|
||||||
| &Term::Clause(ref cell, ..)
|
&Term::Clause(ref cell, ..) |
|
||||||
| Term::PartialString(ref cell, ..) => {
|
Term::PartialString(ref cell, ..) |
|
||||||
|
Term::CompleteString(ref cell, ..) => {
|
||||||
self.marker.mark_non_var::<Target>(Level::Deep, term_loc, cell, target);
|
self.marker.mark_non_var::<Target>(Level::Deep, term_loc, cell, target);
|
||||||
target.push(Target::clause_arg_to_instr(cell.get()));
|
target.push(Target::clause_arg_to_instr(cell.get()));
|
||||||
}
|
}
|
||||||
@@ -352,9 +390,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
self.marker.mark_anon_var::<Target>(lvl, term_loc, &mut target);
|
self.marker.mark_anon_var::<Target>(lvl, term_loc, &mut target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermRef::Clause(lvl, cell, ct, terms) => {
|
TermRef::Clause(lvl, cell, name, terms) => {
|
||||||
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
||||||
target.push(Target::to_structure(ct.name(), terms.len(), cell.get()));
|
target.push(Target::to_structure(name, terms.len(), cell.get()));
|
||||||
|
|
||||||
|
if let Some(instr) = target.last_mut() {
|
||||||
|
if let Some(term) = terms.last() {
|
||||||
|
trim_structure_by_last_arg(instr, term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for subterm in terms {
|
for subterm in terms {
|
||||||
self.subterm_to_instr::<Target>(subterm, term_loc, is_exposed, &mut target);
|
self.subterm_to_instr::<Target>(subterm, term_loc, is_exposed, &mut target);
|
||||||
@@ -377,13 +421,14 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
TermRef::PartialString(lvl, cell, string, tail) => {
|
TermRef::PartialString(lvl, cell, string, tail) => {
|
||||||
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
||||||
|
let atom = self.atom_tbl.build_with(&string);
|
||||||
|
|
||||||
if let Some(tail) = tail {
|
target.push(Target::to_pstr(lvl, atom, cell.get(), true));
|
||||||
target.push(Target::to_pstr(lvl, string, cell.get(), true));
|
|
||||||
self.subterm_to_instr::<Target>(tail, term_loc, is_exposed, &mut target);
|
self.subterm_to_instr::<Target>(tail, term_loc, is_exposed, &mut target);
|
||||||
} else {
|
|
||||||
target.push(Target::to_pstr(lvl, string, cell.get(), false));
|
|
||||||
}
|
}
|
||||||
|
TermRef::CompleteString(lvl, cell, atom) => {
|
||||||
|
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
||||||
|
target.push(Target::to_pstr(lvl, atom, cell.get(), false));
|
||||||
}
|
}
|
||||||
TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => {
|
TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => {
|
||||||
if self.marker.is_unbound(var.clone()) {
|
if self.marker.is_unbound(var.clone()) {
|
||||||
@@ -397,6 +442,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
perm_v!(1),
|
perm_v!(1),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -430,7 +476,6 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.update_var_count(chunked_term.post_order_iter());
|
self.update_var_count(chunked_term.post_order_iter());
|
||||||
|
|
||||||
vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc);
|
vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -451,10 +496,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
self.jmp_by_locs.push(code.len());
|
self.jmp_by_locs.push(code.len());
|
||||||
code.push(instr!("jmp_by_call", vars.len(), 0, pvs));
|
code.push(instr!("jmp_by_call", vars.len(), 0, pvs));
|
||||||
}
|
}
|
||||||
&QueryTerm::Clause(_, ref ct, _, true) => {
|
&QueryTerm::Clause(_, ref ct, _, CallPolicy::Default) => {
|
||||||
code.push(call_clause_by_default!(ct.clone(), pvs));
|
code.push(call_clause_by_default!(ct.clone(), pvs));
|
||||||
}
|
}
|
||||||
&QueryTerm::Clause(_, ref ct, _, false) => {
|
&QueryTerm::Clause(_, ref ct, _, CallPolicy::Counted) => {
|
||||||
code.push(call_clause!(ct.clone(), pvs));
|
code.push(call_clause!(ct.clone(), pvs));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -501,35 +546,39 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
&InlinedClauseType::CompareNumber(mut cmp) => {
|
&InlinedClauseType::CompareNumber(mut cmp) => {
|
||||||
self.marker.reset_arg(2);
|
self.marker.reset_arg(2);
|
||||||
|
|
||||||
let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc)?;
|
let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc, 1)?;
|
||||||
let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc)?;
|
|
||||||
|
|
||||||
let at_1 = if let &Term::Var(ref vr, ref name) = &terms[0] {
|
if !matches!(terms[0], Term::Var(..)) {
|
||||||
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 1, term_loc, vr, code))
|
self.marker.advance_arg();
|
||||||
} else {
|
}
|
||||||
at_1.unwrap_or(interm!(1))
|
|
||||||
};
|
|
||||||
|
|
||||||
let at_2 = if let &Term::Var(ref vr, ref name) = &terms[1] {
|
let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc, 2)?;
|
||||||
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code))
|
|
||||||
} else {
|
|
||||||
at_2.unwrap_or(interm!(2))
|
|
||||||
};
|
|
||||||
|
|
||||||
code.append(&mut lcode);
|
code.append(&mut lcode);
|
||||||
code.append(&mut rcode);
|
code.append(&mut rcode);
|
||||||
|
|
||||||
|
let at_1 = at_1.unwrap_or(interm!(1));
|
||||||
|
let at_2 = at_2.unwrap_or(interm!(2));
|
||||||
|
|
||||||
code.push(compare_number_instr!(cmp, at_1, at_2));
|
code.push(compare_number_instr!(cmp, at_1, at_2));
|
||||||
}
|
}
|
||||||
&InlinedClauseType::IsAtom(..) => match &terms[0] {
|
&InlinedClauseType::IsAtom(..) => match &terms[0] {
|
||||||
&Term::Literal(_, Literal::Char(_))
|
&Term::Literal(_, Literal::Char(_)) |
|
||||||
| &Term::Literal(_, Literal::Atom(atom!("[]")))
|
&Term::Literal(_, Literal::Atom(atom!("[]"))) |
|
||||||
| &Term::Literal(_, Literal::Atom(..)) => {
|
&Term::Literal(_, Literal::Atom(..)) => {
|
||||||
code.push(instr!("$succeed", 0));
|
code.push(instr!("$succeed", 0));
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
self.marker.reset_arg(1);
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
|
||||||
|
let r = self.marker.mark_non_callable(
|
||||||
|
name.clone(),
|
||||||
|
1,
|
||||||
|
term_loc,
|
||||||
|
vr,
|
||||||
|
code,
|
||||||
|
);
|
||||||
|
|
||||||
code.push(instr!("atom", r, 0));
|
code.push(instr!("atom", r, 0));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -537,7 +586,11 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
&InlinedClauseType::IsAtomic(..) => match &terms[0] {
|
&InlinedClauseType::IsAtomic(..) => match &terms[0] {
|
||||||
&Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) => {
|
&Term::AnonVar |
|
||||||
|
&Term::Clause(..) |
|
||||||
|
&Term::Cons(..) |
|
||||||
|
&Term::PartialString(..) |
|
||||||
|
&Term::CompleteString(..) => {
|
||||||
code.push(instr!("$fail", 0));
|
code.push(instr!("$fail", 0));
|
||||||
}
|
}
|
||||||
&Term::Literal(_, Literal::String(_)) => {
|
&Term::Literal(_, Literal::String(_)) => {
|
||||||
@@ -548,18 +601,37 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
self.marker.reset_arg(1);
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
|
||||||
|
let r = self.marker.mark_non_callable(
|
||||||
|
name.clone(),
|
||||||
|
1,
|
||||||
|
term_loc,
|
||||||
|
vr,
|
||||||
|
code,
|
||||||
|
);
|
||||||
|
|
||||||
code.push(instr!("atomic", r, 0));
|
code.push(instr!("atomic", r, 0));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&InlinedClauseType::IsCompound(..) => match &terms[0] {
|
&InlinedClauseType::IsCompound(..) => match &terms[0] {
|
||||||
&Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) |
|
&Term::Clause(..) |
|
||||||
|
&Term::Cons(..) |
|
||||||
|
&Term::PartialString(..) |
|
||||||
|
&Term::CompleteString(..) |
|
||||||
&Term::Literal(_, Literal::String(..)) => {
|
&Term::Literal(_, Literal::String(..)) => {
|
||||||
code.push(instr!("$succeed", 0));
|
code.push(instr!("$succeed", 0));
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
self.marker.reset_arg(1);
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
|
||||||
|
let r = self.marker.mark_non_callable(
|
||||||
|
name.clone(),
|
||||||
|
1,
|
||||||
|
term_loc,
|
||||||
|
vr,
|
||||||
|
code,
|
||||||
|
);
|
||||||
|
|
||||||
code.push(instr!("compound", r, 0));
|
code.push(instr!("compound", r, 0));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -572,7 +644,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
self.marker.reset_arg(1);
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
let r = self.marker.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
||||||
code.push(instr!("rational", r, 0));
|
code.push(instr!("rational", r, 0));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -585,7 +657,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
self.marker.reset_arg(1);
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
|
||||||
|
let r = self.marker.mark_non_callable(
|
||||||
|
name.clone(),
|
||||||
|
1,
|
||||||
|
term_loc,
|
||||||
|
vr,
|
||||||
|
code,
|
||||||
|
);
|
||||||
|
|
||||||
code.push(instr!("float", r, 0));
|
code.push(instr!("float", r, 0));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -593,15 +673,23 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
&InlinedClauseType::IsNumber(..) => match &terms[0] {
|
&InlinedClauseType::IsNumber(..) => match &terms[0] {
|
||||||
&Term::Literal(_, Literal::Float(_))
|
&Term::Literal(_, Literal::Float(_)) |
|
||||||
| &Term::Literal(_, Literal::Rational(_))
|
&Term::Literal(_, Literal::Rational(_)) |
|
||||||
| &Term::Literal(_, Literal::Integer(_))
|
&Term::Literal(_, Literal::Integer(_)) |
|
||||||
| &Term::Literal(_, Literal::Fixnum(_)) => {
|
&Term::Literal(_, Literal::Fixnum(_)) => {
|
||||||
code.push(instr!("$succeed", 0));
|
code.push(instr!("$succeed", 0));
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
self.marker.reset_arg(1);
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
|
||||||
|
let r = self.marker.mark_non_callable(
|
||||||
|
name.clone(),
|
||||||
|
1,
|
||||||
|
term_loc,
|
||||||
|
vr,
|
||||||
|
code,
|
||||||
|
);
|
||||||
|
|
||||||
code.push(instr!("number", r, 0));
|
code.push(instr!("number", r, 0));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -614,7 +702,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
self.marker.reset_arg(1);
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
|
||||||
|
let r = self.marker.mark_non_callable(
|
||||||
|
name.clone(),
|
||||||
|
1,
|
||||||
|
term_loc,
|
||||||
|
vr,
|
||||||
|
code,
|
||||||
|
);
|
||||||
|
|
||||||
code.push(instr!("nonvar", r, 0));
|
code.push(instr!("nonvar", r, 0));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -622,12 +718,21 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
&InlinedClauseType::IsInteger(..) => match &terms[0] {
|
&InlinedClauseType::IsInteger(..) => match &terms[0] {
|
||||||
&Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => {
|
&Term::Literal(_, Literal::Integer(_)) |
|
||||||
|
&Term::Literal(_, Literal::Fixnum(_)) => {
|
||||||
code.push(instr!("$succeed", 0));
|
code.push(instr!("$succeed", 0));
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
self.marker.reset_arg(1);
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
|
||||||
|
let r = self.marker.mark_non_callable(
|
||||||
|
name.clone(),
|
||||||
|
1,
|
||||||
|
term_loc,
|
||||||
|
vr,
|
||||||
|
code,
|
||||||
|
);
|
||||||
|
|
||||||
code.push(instr!("integer", r, 0));
|
code.push(instr!("integer", r, 0));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -635,10 +740,11 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
&InlinedClauseType::IsVar(..) => match &terms[0] {
|
&InlinedClauseType::IsVar(..) => match &terms[0] {
|
||||||
&Term::Literal(..)
|
&Term::Literal(..) |
|
||||||
| &Term::Clause(..)
|
&Term::Clause(..) |
|
||||||
| &Term::Cons(..)
|
&Term::Cons(..) |
|
||||||
| &Term::PartialString(..) => {
|
&Term::PartialString(..) |
|
||||||
|
&Term::CompleteString(..) => {
|
||||||
code.push(instr!("$fail", 0));
|
code.push(instr!("$fail", 0));
|
||||||
}
|
}
|
||||||
&Term::AnonVar => {
|
&Term::AnonVar => {
|
||||||
@@ -646,7 +752,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
self.marker.reset_arg(1);
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
|
||||||
|
let r = self.marker.mark_non_callable(
|
||||||
|
name.clone(),
|
||||||
|
1,
|
||||||
|
term_loc,
|
||||||
|
vr,
|
||||||
|
code,
|
||||||
|
);
|
||||||
|
|
||||||
code.push(instr!("var", r, 0));
|
code.push(instr!("var", r, 0));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -660,9 +774,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
term: &Term,
|
term: &Term,
|
||||||
target_int: usize,
|
target_int: usize,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
|
arg: usize,
|
||||||
) -> Result<ArithCont, ArithmeticError> {
|
) -> Result<ArithCont, ArithmeticError> {
|
||||||
let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int);
|
let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int);
|
||||||
evaluator.eval(term, term_loc)
|
evaluator.compile_is(term, term_loc, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_is_call(
|
fn compile_is_call(
|
||||||
@@ -670,11 +785,11 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
terms: &Vec<Term>,
|
terms: &Vec<Term>,
|
||||||
code: &mut Code,
|
code: &mut Code,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
use_default_call_policy: bool,
|
call_policy: CallPolicy,
|
||||||
) -> Result<(), CompilationError> {
|
) -> Result<(), CompilationError> {
|
||||||
macro_rules! compile_expr {
|
macro_rules! compile_expr {
|
||||||
($self:expr, $terms:expr, $term_loc:expr, $code:expr) => ({
|
($self:expr, $terms:expr, $term_loc:expr, $code:expr) => ({
|
||||||
let (acode, at) = $self.compile_arith_expr(&$terms[1], 1, $term_loc)?;
|
let (acode, at) = $self.compile_arith_expr(&$terms[1], 1, $term_loc, 2)?;
|
||||||
$code.extend(acode.into_iter());
|
$code.extend(acode.into_iter());
|
||||||
at
|
at
|
||||||
});
|
});
|
||||||
@@ -712,7 +827,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
|
|
||||||
let at = at.unwrap_or(interm!(1));
|
let at = at.unwrap_or(interm!(1));
|
||||||
|
|
||||||
Ok(if use_default_call_policy {
|
Ok(if let CallPolicy::Default = call_policy {
|
||||||
code.push(instr!("is", default, temp_v!(1), at, 0));
|
code.push(instr!("is", default, temp_v!(1), at, 0));
|
||||||
} else {
|
} else {
|
||||||
code.push(instr!("is", temp_v!(1), at, 0));
|
code.push(instr!("is", temp_v!(1), at, 0));
|
||||||
@@ -774,8 +889,8 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
_,
|
_,
|
||||||
ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
|
ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
|
||||||
ref terms,
|
ref terms,
|
||||||
use_default_call_policy,
|
call_policy,
|
||||||
) => self.compile_is_call(terms, code, term_loc, use_default_call_policy)?,
|
) => self.compile_is_call(terms, code, term_loc, call_policy)?,
|
||||||
&QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => {
|
&QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => {
|
||||||
self.compile_inlined(ct, terms, term_loc, code)?
|
self.compile_inlined(ct, terms, term_loc, code)?
|
||||||
}
|
}
|
||||||
@@ -787,6 +902,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.compile_query_line(term, term_loc, code, num_perm_vars, is_exposed);
|
self.compile_query_line(term, term_loc, code, num_perm_vars, is_exposed);
|
||||||
|
|
||||||
|
if self.marker.max_reg_allocated() > MAX_ARITY {
|
||||||
|
return Err(CompilationError::ExceededMaxArity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -856,6 +975,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
let iter = FactIterator::from_rule_head_clause(args);
|
let iter = FactIterator::from_rule_head_clause(args);
|
||||||
let mut fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head, false);
|
let mut fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head, false);
|
||||||
|
|
||||||
|
if self.marker.max_reg_allocated() > MAX_ARITY {
|
||||||
|
return Err(CompilationError::ExceededMaxArity);
|
||||||
|
}
|
||||||
|
|
||||||
let mut unsafe_var_marker = UnsafeVarMarker::new();
|
let mut unsafe_var_marker = UnsafeVarMarker::new();
|
||||||
|
|
||||||
if !fact.is_empty() {
|
if !fact.is_empty() {
|
||||||
@@ -893,7 +1016,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
UnsafeVarMarker::from_safe_vars(safe_vars)
|
UnsafeVarMarker::from_safe_vars(safe_vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn compile_fact(&mut self, term: &Term) -> Code {
|
pub(crate) fn compile_fact(&mut self, term: &Term) -> Result<Code, CompilationError> {
|
||||||
self.update_var_count(post_order_iter(term));
|
self.update_var_count(post_order_iter(term));
|
||||||
|
|
||||||
let mut vs = VariableFixtures::new();
|
let mut vs = VariableFixtures::new();
|
||||||
@@ -915,6 +1038,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if self.marker.max_reg_allocated() > MAX_ARITY {
|
||||||
|
return Err(CompilationError::ExceededMaxArity);
|
||||||
|
}
|
||||||
|
|
||||||
self.mark_unsafe_fact_vars(&mut compiled_fact);
|
self.mark_unsafe_fact_vars(&mut compiled_fact);
|
||||||
|
|
||||||
if !compiled_fact.is_empty() {
|
if !compiled_fact.is_empty() {
|
||||||
@@ -923,7 +1050,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
code.push(instr!("proceed"));
|
code.push(instr!("proceed"));
|
||||||
code
|
Ok(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_query_line(
|
fn compile_query_line(
|
||||||
@@ -939,10 +1066,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
let iter = query_term_post_order_iter(term);
|
let iter = query_term_post_order_iter(term);
|
||||||
let query = self.compile_target::<QueryInstruction, _>(iter, term_loc, is_exposed);
|
let query = self.compile_target::<QueryInstruction, _>(iter, term_loc, is_exposed);
|
||||||
|
|
||||||
if !query.is_empty() {
|
|
||||||
code.extend(query.into_iter());
|
code.extend(query.into_iter());
|
||||||
}
|
|
||||||
|
|
||||||
self.add_conditional_call(code, term, num_perm_vars_left);
|
self.add_conditional_call(code, term, num_perm_vars_left);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1033,14 +1157,13 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
self.global_jmp_by_locs_offset = self.jmp_by_locs.len();
|
self.global_jmp_by_locs_offset = self.jmp_by_locs.len();
|
||||||
|
|
||||||
let clause_code = match clause {
|
let clause_code = match clause {
|
||||||
&PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact),
|
&PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact)?,
|
||||||
&PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
|
&PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
if clauses.len() > 1 {
|
if clauses.len() > 1 {
|
||||||
let choice = match i {
|
let choice = match i {
|
||||||
0 => self.settings.internal_try_me_else(clause_code.len() + 1),
|
0 => self.settings.internal_try_me_else(clause_code.len() + 1),
|
||||||
//Instruction::TryMeElse(clause_code.len() + 1),
|
|
||||||
_ if i == clauses.len() - 1 => self.settings.internal_trust_me(),
|
_ if i == clauses.len() - 1 => self.settings.internal_trust_me(),
|
||||||
_ => self.settings.internal_retry_me_else(clause_code.len() + 1),
|
_ => self.settings.internal_retry_me_else(clause_code.len() + 1),
|
||||||
};
|
};
|
||||||
@@ -1062,28 +1185,39 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
skip_stub_try_me_else = !self.settings.is_dynamic();
|
skip_stub_try_me_else = !self.settings.is_dynamic();
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg = match clause.args() {
|
let arg = clause.args().and_then(|args| args.iter().nth(optimal_index));
|
||||||
Some(args) => match args.iter().nth(optimal_index) {
|
|
||||||
Some(term) => Some(term),
|
|
||||||
None => None,
|
|
||||||
},
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(arg) = arg {
|
if let Some(arg) = arg {
|
||||||
let index = code.len();
|
let index = code.len();
|
||||||
|
|
||||||
|
if clauses.len() > 1 || self.settings.is_dynamic() {
|
||||||
code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl);
|
code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !(clauses.len() == 1 && self.settings.is_extensible) {
|
if !(code_offsets.no_indices() && clauses.len() == 1 && self.settings.is_extensible) {
|
||||||
|
// the peculiar condition of this block, when false,
|
||||||
|
// anticipates code.pop_front() being called about a
|
||||||
|
// dozen lines below.
|
||||||
|
|
||||||
|
if !skip_stub_try_me_else {
|
||||||
|
// if the condition is false, code_offsets.no_indices() is false,
|
||||||
|
// so don't repeat the work of the condition on skip_stub_try_me_else
|
||||||
|
// below.
|
||||||
self.increment_jmp_by_locs_by(code.len());
|
self.increment_jmp_by_locs_by(code.len());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.skeleton.clauses.push_back(clause_index_info);
|
self.skeleton.clauses.push_back(clause_index_info);
|
||||||
code.extend(clause_code.into_iter());
|
code.extend(clause_code.into_iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
let index_code = code_offsets.compute_indices(skip_stub_try_me_else);
|
let index_code = if clauses.len() > 1 || self.settings.is_dynamic() {
|
||||||
|
code_offsets.compute_indices(skip_stub_try_me_else)
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
self.global_jmp_by_locs_offset = jmp_by_locs_len;
|
self.global_jmp_by_locs_offset = jmp_by_locs_len;
|
||||||
|
|
||||||
if !index_code.is_empty() {
|
if !index_code.is_empty() {
|
||||||
@@ -1147,7 +1281,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
|||||||
if self.settings.is_extensible {
|
if self.settings.is_extensible {
|
||||||
let segment_is_indexed = code_segment[0].to_indexing_line().is_some();
|
let segment_is_indexed = code_segment[0].to_indexing_line().is_some();
|
||||||
|
|
||||||
for clause_index_info in self.skeleton.clauses[skel_lower_bound..].iter_mut() {
|
for clause_index_info in self.skeleton.clauses
|
||||||
|
.make_contiguous()[skel_lower_bound..]
|
||||||
|
.iter_mut()
|
||||||
|
{
|
||||||
clause_index_info.clause_start +=
|
clause_index_info.clause_start +=
|
||||||
clause_start_offset + 2 * (segment_is_indexed as usize);
|
clause_start_offset + 2 * (segment_is_indexed as usize);
|
||||||
clause_index_info.opt_arg_index_key += clause_start_offset + 1;
|
clause_index_info.opt_arg_index_key += clause_start_offset + 1;
|
||||||
|
|||||||
@@ -151,16 +151,13 @@ impl DebrayAllocator {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_reg_to_var<'a, Target>(
|
fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
var: &String,
|
var: &String,
|
||||||
lvl: Level,
|
lvl: Level,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
target: &mut Vec<Instruction>,
|
target: &mut Vec<Instruction>,
|
||||||
) -> usize
|
) -> usize {
|
||||||
where
|
|
||||||
Target: CompilationTarget<'a>,
|
|
||||||
{
|
|
||||||
match term_loc {
|
match term_loc {
|
||||||
GenContext::Head => {
|
GenContext::Head => {
|
||||||
if let Level::Shallow = lvl {
|
if let Level::Shallow = lvl {
|
||||||
@@ -404,4 +401,9 @@ impl Allocator for DebrayAllocator {
|
|||||||
self.arg_c = 1;
|
self.arg_c = 1;
|
||||||
self.temp_lb = arity + 1;
|
self.temp_lb = arity + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn max_reg_allocated(&self) -> usize {
|
||||||
|
std::cmp::max(self.temp_lb, self.arg_c)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
83
src/forms.rs
83
src/forms.rs
@@ -15,9 +15,8 @@ use fxhash::FxBuildHasher;
|
|||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
use slice_deque::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::collections::VecDeque;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::AddAssign;
|
use std::ops::AddAssign;
|
||||||
@@ -58,7 +57,7 @@ impl AppendOrPrepend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Level {
|
pub enum Level {
|
||||||
Deep,
|
Deep,
|
||||||
Root,
|
Root,
|
||||||
@@ -74,10 +73,16 @@ impl Level {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum CallPolicy {
|
||||||
|
Default,
|
||||||
|
Counted,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum QueryTerm {
|
pub enum QueryTerm {
|
||||||
// register, clause type, subterms, use default call policy.
|
// register, clause type, subterms, clause call policy.
|
||||||
Clause(Cell<RegType>, ClauseType, Vec<Term>, bool),
|
Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
|
||||||
BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q.
|
BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q.
|
||||||
UnblockedCut(Cell<VarReg>),
|
UnblockedCut(Cell<VarReg>),
|
||||||
GetLevelAndUnify(Cell<VarReg>, Rc<String>),
|
GetLevelAndUnify(Cell<VarReg>, Rc<String>),
|
||||||
@@ -85,9 +90,9 @@ pub enum QueryTerm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl QueryTerm {
|
impl QueryTerm {
|
||||||
pub(crate) fn set_default_caller(&mut self) {
|
pub(crate) fn set_call_policy(&mut self, cp: CallPolicy) {
|
||||||
match self {
|
match self {
|
||||||
&mut QueryTerm::Clause(_, _, _, ref mut use_default_cp) => *use_default_cp = true,
|
&mut QueryTerm::Clause(_, _, _, ref mut clause_cp) => *clause_cp = cp,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,24 +154,21 @@ impl ClauseInfo for PredicateKey {
|
|||||||
|
|
||||||
impl ClauseInfo for Term {
|
impl ClauseInfo for Term {
|
||||||
fn name(&self) -> Option<Atom> {
|
fn name(&self) -> Option<Atom> {
|
||||||
//, atom_tbl: &AtomTable) -> Option<StringBuffer> {
|
|
||||||
match self {
|
match self {
|
||||||
Term::Clause(_, name, terms) => {
|
Term::Clause(_, name, terms) => {
|
||||||
// let str_buf = StringBuffer::from(*name, atom_tbl);
|
|
||||||
|
|
||||||
match name.as_str() {
|
match name {
|
||||||
// str_buf.as_str() {
|
atom!(":-") => {
|
||||||
":-" => {
|
|
||||||
match terms.len() {
|
match terms.len() {
|
||||||
1 => None, // a declaration.
|
1 => None, // a declaration.
|
||||||
2 => terms[0].name(), //.map(|name| StringBuffer::from(name, atom_tbl)),
|
2 => terms[0].name(),
|
||||||
_ => Some(*name),
|
_ => Some(*name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Some(*name), //str_buf),
|
_ => Some(*name), //str_buf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Term::Literal(_, Literal::Atom(name)) => Some(*name), //Some(StringBuffer::from(*name, atom_tbl)),
|
Term::Literal(_, Literal::Atom(name)) => Some(*name),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,6 +269,7 @@ pub enum MetaSpec {
|
|||||||
Minus,
|
Minus,
|
||||||
Plus,
|
Plus,
|
||||||
Either,
|
Either,
|
||||||
|
Colon,
|
||||||
RequiresExpansionWithArgument(usize),
|
RequiresExpansionWithArgument(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,6 +366,18 @@ pub enum AtomOrString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AtomOrString {
|
impl AtomOrString {
|
||||||
|
#[inline]
|
||||||
|
pub fn as_atom(&self, atom_tbl: &mut AtomTable) -> Atom {
|
||||||
|
match self {
|
||||||
|
&AtomOrString::Atom(atom) => {
|
||||||
|
atom
|
||||||
|
}
|
||||||
|
AtomOrString::String(string) => {
|
||||||
|
atom_tbl.build_with(&string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
@@ -607,7 +622,7 @@ impl ArenaFrom<Number> for Literal {
|
|||||||
match value {
|
match value {
|
||||||
Number::Fixnum(n) => Literal::Fixnum(n),
|
Number::Fixnum(n) => Literal::Fixnum(n),
|
||||||
Number::Integer(n) => Literal::Integer(n),
|
Number::Integer(n) => Literal::Integer(n),
|
||||||
Number::Float(f) => Literal::Float(arena_alloc!(f, arena)),
|
Number::Float(OrderedFloat(f)) => Literal::from(float_alloc!(f, arena)),
|
||||||
Number::Rational(r) => Literal::Rational(r),
|
Number::Rational(r) => Literal::Rational(r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -619,13 +634,29 @@ impl ArenaFrom<Number> for HeapCellValue {
|
|||||||
match value {
|
match value {
|
||||||
Number::Fixnum(n) => fixnum_as_cell!(n),
|
Number::Fixnum(n) => fixnum_as_cell!(n),
|
||||||
Number::Integer(n) => typed_arena_ptr_as_cell!(n),
|
Number::Integer(n) => typed_arena_ptr_as_cell!(n),
|
||||||
Number::Float(n) => typed_arena_ptr_as_cell!(arena_alloc!(n, arena)),
|
Number::Float(OrderedFloat(n)) => HeapCellValue::from(float_alloc!(n, arena)),
|
||||||
Number::Rational(n) => typed_arena_ptr_as_cell!(n),
|
Number::Rational(n) => typed_arena_ptr_as_cell!(n),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Number {
|
impl Number {
|
||||||
|
pub(crate) fn sign(&self) -> Number {
|
||||||
|
match self {
|
||||||
|
&Number::Float(f) if f == 0.0 => Number::Float(OrderedFloat(0f64)),
|
||||||
|
&Number::Float(f) => Number::Float(OrderedFloat(f.signum())),
|
||||||
|
_ => {
|
||||||
|
if self.is_positive() {
|
||||||
|
Number::Fixnum(Fixnum::build_with(1))
|
||||||
|
} else if self.is_negative() {
|
||||||
|
Number::Fixnum(Fixnum::build_with(-1))
|
||||||
|
} else {
|
||||||
|
Number::Fixnum(Fixnum::build_with(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn is_positive(&self) -> bool {
|
pub(crate) fn is_positive(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
@@ -791,7 +822,7 @@ pub(crate) struct LocalPredicateSkeleton {
|
|||||||
pub(crate) is_discontiguous: bool,
|
pub(crate) is_discontiguous: bool,
|
||||||
pub(crate) is_dynamic: bool,
|
pub(crate) is_dynamic: bool,
|
||||||
pub(crate) is_multifile: bool,
|
pub(crate) is_multifile: bool,
|
||||||
pub(crate) clause_clause_locs: SliceDeque<usize>,
|
pub(crate) clause_clause_locs: VecDeque<usize>,
|
||||||
pub(crate) clause_assert_margin: usize,
|
pub(crate) clause_assert_margin: usize,
|
||||||
pub(crate) retracted_dynamic_clauses: Option<Vec<ClauseIndexInfo>>, // always None if non-dynamic.
|
pub(crate) retracted_dynamic_clauses: Option<Vec<ClauseIndexInfo>>, // always None if non-dynamic.
|
||||||
}
|
}
|
||||||
@@ -803,7 +834,7 @@ impl LocalPredicateSkeleton {
|
|||||||
is_discontiguous: false,
|
is_discontiguous: false,
|
||||||
is_dynamic: false,
|
is_dynamic: false,
|
||||||
is_multifile: false,
|
is_multifile: false,
|
||||||
clause_clause_locs: sdeq![],
|
clause_clause_locs: VecDeque::new(),
|
||||||
clause_assert_margin: 0,
|
clause_assert_margin: 0,
|
||||||
retracted_dynamic_clauses: Some(vec![]),
|
retracted_dynamic_clauses: Some(vec![]),
|
||||||
}
|
}
|
||||||
@@ -844,7 +875,7 @@ impl LocalPredicateSkeleton {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct PredicateSkeleton {
|
pub(crate) struct PredicateSkeleton {
|
||||||
pub(crate) core: LocalPredicateSkeleton,
|
pub(crate) core: LocalPredicateSkeleton,
|
||||||
pub(crate) clauses: SliceDeque<ClauseIndexInfo>,
|
pub(crate) clauses: VecDeque<ClauseIndexInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PredicateSkeleton {
|
impl PredicateSkeleton {
|
||||||
@@ -852,7 +883,7 @@ impl PredicateSkeleton {
|
|||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
PredicateSkeleton {
|
PredicateSkeleton {
|
||||||
core: LocalPredicateSkeleton::new(),
|
core: LocalPredicateSkeleton::new(),
|
||||||
clauses: sdeq![],
|
clauses: VecDeque::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -868,18 +899,22 @@ impl PredicateSkeleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn target_pos_of_clause_clause_loc(
|
pub(crate) fn target_pos_of_clause_clause_loc(
|
||||||
&self,
|
&mut self,
|
||||||
clause_clause_loc: usize,
|
clause_clause_loc: usize,
|
||||||
) -> Option<usize> {
|
) -> Option<usize> {
|
||||||
let search_result = self.core.clause_clause_locs[0..self.core.clause_assert_margin]
|
let search_result = self.core.clause_clause_locs
|
||||||
|
.make_contiguous()[0..self.core.clause_assert_margin]
|
||||||
.binary_search_by(|loc| clause_clause_loc.cmp(&loc));
|
.binary_search_by(|loc| clause_clause_loc.cmp(&loc));
|
||||||
|
|
||||||
match search_result {
|
match search_result {
|
||||||
Ok(loc) => Some(loc),
|
Ok(loc) => Some(loc),
|
||||||
Err(_) => self.core.clause_clause_locs[self.core.clause_assert_margin..]
|
Err(_) => {
|
||||||
|
self.core.clause_clause_locs
|
||||||
|
.make_contiguous()[self.core.clause_assert_margin..]
|
||||||
.binary_search_by(|loc| loc.cmp(&clause_clause_loc))
|
.binary_search_by(|loc| loc.cmp(&clause_clause_loc))
|
||||||
.map(|loc| loc + self.core.clause_assert_margin)
|
.map(|loc| loc + self.core.clause_assert_margin)
|
||||||
.ok(),
|
.ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
275
src/heap_iter.rs
275
src/heap_iter.rs
@@ -1,3 +1,4 @@
|
|||||||
|
#[cfg(test)]
|
||||||
pub(crate) use crate::machine::gc::{IteratorUMP, StacklessPreOrderHeapIter};
|
pub(crate) use crate::machine::gc::{IteratorUMP, StacklessPreOrderHeapIter};
|
||||||
use crate::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
|
|
||||||
@@ -9,6 +10,49 @@ use modular_bitfield::prelude::*;
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
#[derive(BitfieldSpecifier, Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
#[bits = 2]
|
||||||
|
enum IterStackLocTag {
|
||||||
|
Iterable,
|
||||||
|
Marked,
|
||||||
|
PendingMark,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[repr(u64)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct IterStackLoc {
|
||||||
|
value: B62,
|
||||||
|
tag: IterStackLocTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IterStackLoc {
|
||||||
|
#[inline]
|
||||||
|
pub fn iterable_heap_loc(h: usize) -> Self {
|
||||||
|
IterStackLoc::new().with_tag(IterStackLocTag::Iterable).with_value(h as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mark_heap_loc(h: usize) -> Self {
|
||||||
|
IterStackLoc::new().with_tag(IterStackLocTag::Marked).with_value(h as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn pending_mark_heap_loc(h: usize) -> Self {
|
||||||
|
IterStackLoc::new().with_tag(IterStackLocTag::PendingMark).with_value(h as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_marked(self) -> bool {
|
||||||
|
self.tag() == IterStackLocTag::Marked
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_pending_mark(self) -> bool {
|
||||||
|
self.tag() == IterStackLocTag::PendingMark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) {
|
fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) {
|
||||||
read_heap_cell!(heap[h],
|
read_heap_cell!(heap[h],
|
||||||
@@ -25,26 +69,6 @@ fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bitfield]
|
|
||||||
#[repr(u64)]
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct IterStackLoc {
|
|
||||||
value: B63,
|
|
||||||
m: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IterStackLoc {
|
|
||||||
#[inline]
|
|
||||||
pub fn iterable_heap_loc(h: usize) -> Self {
|
|
||||||
IterStackLoc::new().with_m(false).with_value(h as u64)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn mark_heap_loc(h: usize) -> Self {
|
|
||||||
IterStackLoc::new().with_m(true).with_value(h as u64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StackfulPreOrderHeapIter<'a> {
|
pub struct StackfulPreOrderHeapIter<'a> {
|
||||||
pub heap: &'a mut Vec<HeapCellValue>,
|
pub heap: &'a mut Vec<HeapCellValue>,
|
||||||
@@ -65,6 +89,17 @@ impl<'a> Drop for StackfulPreOrderHeapIter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait FocusedHeapIter: Iterator<Item = HeapCellValue> {
|
||||||
|
fn focus(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FocusedHeapIter for StackfulPreOrderHeapIter<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn focus(&self) -> usize {
|
||||||
|
self.h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> StackfulPreOrderHeapIter<'a> {
|
impl<'a> StackfulPreOrderHeapIter<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
|
fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
|
||||||
@@ -86,11 +121,11 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn stack_last(&self) -> Option<usize> {
|
pub fn stack_last(&self) -> Option<usize> {
|
||||||
for h in self.stack.iter().rev() {
|
for h in self.stack.iter().rev() {
|
||||||
let is_readable_marked = h.m();
|
let is_readable_marked = h.is_marked();
|
||||||
let h = h.value() as usize;
|
let h = h.value() as usize;
|
||||||
let cell = self.heap[h];
|
let cell = self.heap[h];
|
||||||
|
|
||||||
if cell.get_forwarding_bit() == Some(true) {
|
if cell.get_forwarding_bit() {
|
||||||
return Some(h);
|
return Some(h);
|
||||||
} else if cell.get_mark_bit() && !is_readable_marked {
|
} else if cell.get_mark_bit() && !is_readable_marked {
|
||||||
continue;
|
continue;
|
||||||
@@ -102,26 +137,16 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn stack_is_empty(&self) -> bool {
|
|
||||||
self.stack.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn focus(&self) -> usize {
|
|
||||||
self.h
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pop_stack(&mut self) -> Option<HeapCellValue> {
|
pub fn pop_stack(&mut self) -> Option<HeapCellValue> {
|
||||||
while let Some(h) = self.stack.pop() {
|
while let Some(h) = self.stack.pop() {
|
||||||
let is_readable_marked = h.m();
|
let is_readable_marked = h.is_marked();
|
||||||
let h = h.value() as usize;
|
let h = h.value() as usize;
|
||||||
self.h = h;
|
self.h = h;
|
||||||
|
|
||||||
let cell = &mut self.heap[h];
|
let cell = &mut self.heap[h];
|
||||||
|
|
||||||
if cell.get_forwarding_bit() == Some(true) {
|
if cell.get_forwarding_bit() {
|
||||||
cell.set_forwarding_bit(false);
|
cell.set_forwarding_bit(false);
|
||||||
} else if cell.get_mark_bit() && !is_readable_marked {
|
} else if cell.get_mark_bit() && !is_readable_marked {
|
||||||
cell.set_mark_bit(false);
|
cell.set_mark_bit(false);
|
||||||
@@ -143,13 +168,23 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
|||||||
|
|
||||||
fn follow(&mut self) -> Option<HeapCellValue> {
|
fn follow(&mut self) -> Option<HeapCellValue> {
|
||||||
while let Some(h) = self.stack.pop() {
|
while let Some(h) = self.stack.pop() {
|
||||||
let is_readable_marked = h.m();
|
if h.is_pending_mark() {
|
||||||
|
let h = h.value() as usize;
|
||||||
|
|
||||||
|
self.push_if_unmarked(h);
|
||||||
|
self.stack.push(IterStackLoc::mark_heap_loc(h));
|
||||||
|
|
||||||
|
forward_if_referent_marked(&mut self.heap, h);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_readable_marked = h.is_marked();
|
||||||
let h = h.value() as usize;
|
let h = h.value() as usize;
|
||||||
|
|
||||||
self.h = h;
|
self.h = h;
|
||||||
let cell = &mut self.heap[h];
|
let cell = &mut self.heap[h];
|
||||||
|
|
||||||
if cell.get_forwarding_bit() == Some(true) {
|
if cell.get_forwarding_bit() {
|
||||||
let copy = *cell;
|
let copy = *cell;
|
||||||
cell.set_forwarding_bit(false);
|
cell.set_forwarding_bit(false);
|
||||||
return Some(copy);
|
return Some(copy);
|
||||||
@@ -159,23 +194,23 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
read_heap_cell!(*cell,
|
read_heap_cell!(*cell,
|
||||||
(HeapCellValueTag::Str, vh) => {
|
(HeapCellValueTag::Str | HeapCellValueTag::PStrLoc, vh) => {
|
||||||
self.stack.push(IterStackLoc::iterable_heap_loc(vh));
|
self.push_if_unmarked(vh);
|
||||||
|
self.stack.push(IterStackLoc::mark_heap_loc(vh));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Lis, vh) => {
|
(HeapCellValueTag::Lis, vh) => {
|
||||||
self.push_if_unmarked(vh);
|
self.push_if_unmarked(vh);
|
||||||
|
|
||||||
self.stack.push(IterStackLoc::iterable_heap_loc(vh + 1));
|
self.stack.push(IterStackLoc::pending_mark_heap_loc(vh + 1));
|
||||||
forward_if_referent_marked(&mut self.heap, vh + 1);
|
|
||||||
|
|
||||||
self.stack.push(IterStackLoc::mark_heap_loc(vh));
|
self.stack.push(IterStackLoc::mark_heap_loc(vh));
|
||||||
|
|
||||||
forward_if_referent_marked(&mut self.heap, vh);
|
forward_if_referent_marked(&mut self.heap, vh);
|
||||||
|
|
||||||
return Some(self.heap[h]);
|
return Some(self.heap[h]);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | HeapCellValueTag::Var, vh) => {
|
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, vh) => {
|
||||||
self.push_if_unmarked(h);
|
self.push_if_unmarked(vh);
|
||||||
self.stack.push(IterStackLoc::iterable_heap_loc(vh));
|
self.stack.push(IterStackLoc::mark_heap_loc(vh));
|
||||||
forward_if_referent_marked(&mut self.heap, vh);
|
forward_if_referent_marked(&mut self.heap, vh);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStrOffset, offset) => {
|
(HeapCellValueTag::PStrOffset, offset) => {
|
||||||
@@ -187,19 +222,20 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
|||||||
(HeapCellValueTag::PStr) => {
|
(HeapCellValueTag::PStr) => {
|
||||||
self.push_if_unmarked(h);
|
self.push_if_unmarked(h);
|
||||||
|
|
||||||
forward_if_referent_marked(&mut self.heap, h+1);
|
|
||||||
self.stack.push(IterStackLoc::iterable_heap_loc(h+1));
|
self.stack.push(IterStackLoc::iterable_heap_loc(h+1));
|
||||||
|
forward_if_referent_marked(&mut self.heap, h+1);
|
||||||
|
|
||||||
return Some(self.heap[h]);
|
return Some(self.heap[h]);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Atom, (_name, arity)) => {
|
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||||
if arity > 0 {
|
for h in (h + 2 .. h + arity + 1).rev() {
|
||||||
self.push_if_unmarked(h);
|
self.stack.push(IterStackLoc::pending_mark_heap_loc(h));
|
||||||
}
|
}
|
||||||
|
|
||||||
for h in (h + 1 .. h + arity + 1).rev() {
|
if arity > 0 {
|
||||||
forward_if_referent_marked(&mut self.heap, h);
|
self.push_if_unmarked(h+1);
|
||||||
self.stack.push(IterStackLoc::iterable_heap_loc(h));
|
self.stack.push(IterStackLoc::mark_heap_loc(h+1));
|
||||||
|
forward_if_referent_marked(&mut self.heap, h+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(self.heap[h]);
|
return Some(self.heap[h]);
|
||||||
@@ -223,12 +259,13 @@ impl<'a> Iterator for StackfulPreOrderHeapIter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn stackless_preorder_iter(
|
pub(crate) fn stackless_preorder_iter(
|
||||||
heap: &mut Vec<HeapCellValue>,
|
heap: &mut Vec<HeapCellValue>,
|
||||||
cell: HeapCellValue,
|
cell: HeapCellValue,
|
||||||
) -> StacklessPreOrderHeapIter<IteratorUMP> {
|
) -> StacklessPreOrderHeapIter<IteratorUMP> {
|
||||||
StacklessPreOrderHeapIter::new(heap, cell)
|
StacklessPreOrderHeapIter::<IteratorUMP>::new(heap, cell)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -240,13 +277,14 @@ pub(crate) fn stackful_preorder_iter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct PostOrderIterator<Iter: Iterator<Item = HeapCellValue>> {
|
pub(crate) struct PostOrderIterator<Iter: FocusedHeapIter> {
|
||||||
|
focus: usize,
|
||||||
base_iter: Iter,
|
base_iter: Iter,
|
||||||
base_iter_valid: bool,
|
base_iter_valid: bool,
|
||||||
parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node.
|
parent_stack: Vec<(usize, HeapCellValue, usize)>, // number of children, parent node, focus.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Iter: Iterator<Item = HeapCellValue>> Deref for PostOrderIterator<Iter> {
|
impl<Iter: FocusedHeapIter> Deref for PostOrderIterator<Iter> {
|
||||||
type Target = Iter;
|
type Target = Iter;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@@ -254,9 +292,10 @@ impl<Iter: Iterator<Item = HeapCellValue>> Deref for PostOrderIterator<Iter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Iter: Iterator<Item = HeapCellValue>> PostOrderIterator<Iter> {
|
impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
|
||||||
pub(crate) fn new(base_iter: Iter) -> Self {
|
pub(crate) fn new(base_iter: Iter) -> Self {
|
||||||
PostOrderIterator {
|
PostOrderIterator {
|
||||||
|
focus: 0,
|
||||||
base_iter,
|
base_iter,
|
||||||
base_iter_valid: true,
|
base_iter_valid: true,
|
||||||
parent_stack: vec![],
|
parent_stack: vec![],
|
||||||
@@ -264,32 +303,36 @@ impl<Iter: Iterator<Item = HeapCellValue>> PostOrderIterator<Iter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Iter: Iterator<Item = HeapCellValue>> Iterator for PostOrderIterator<Iter> {
|
impl<Iter: FocusedHeapIter> Iterator for PostOrderIterator<Iter> {
|
||||||
type Item = HeapCellValue;
|
type Item = HeapCellValue;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
loop {
|
loop {
|
||||||
if let Some((child_count, node)) = self.parent_stack.pop() {
|
if let Some((child_count, node, focus)) = self.parent_stack.pop() {
|
||||||
if child_count == 0 {
|
if child_count == 0 {
|
||||||
|
self.focus = focus;
|
||||||
return Some(node);
|
return Some(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.parent_stack.push((child_count - 1, node));
|
self.parent_stack.push((child_count - 1, node, focus));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.base_iter_valid {
|
if self.base_iter_valid {
|
||||||
if let Some(item) = self.base_iter.next() {
|
if let Some(item) = self.base_iter.next() {
|
||||||
|
let focus = self.base_iter.focus();
|
||||||
|
|
||||||
read_heap_cell!(item,
|
read_heap_cell!(item,
|
||||||
(HeapCellValueTag::Atom, (_name, arity)) => {
|
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||||
self.parent_stack.push((arity, item));
|
self.parent_stack.push((arity, item, focus));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Lis) => {
|
(HeapCellValueTag::Lis) => {
|
||||||
self.parent_stack.push((2, item));
|
self.parent_stack.push((2, item, focus));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
||||||
self.parent_stack.push((1, item));
|
self.parent_stack.push((1, item, focus));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
self.focus = focus;
|
||||||
return Some(item);
|
return Some(item);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -307,12 +350,40 @@ impl<Iter: Iterator<Item = HeapCellValue>> Iterator for PostOrderIterator<Iter>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Iter: FocusedHeapIter> FocusedHeapIter for PostOrderIterator<Iter> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn focus(&self) -> usize {
|
||||||
|
self.focus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
|
||||||
|
/* return true if the term at heap offset idx_loc is a
|
||||||
|
* direct/inlined subterm of a structure at the focus of
|
||||||
|
* self.stack.last(). this function is used to determine, e.g.,
|
||||||
|
* ownership of inlined code indices.
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn direct_subterm_of_str(&self, idx_loc: usize) -> bool {
|
||||||
|
if let Some((_child_count, item, focus)) = self.parent_stack.last() {
|
||||||
|
read_heap_cell!(item,
|
||||||
|
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||||
|
return focus + arity >= idx_loc && *focus < idx_loc;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator<StackfulPreOrderHeapIter<'a>>;
|
pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator<StackfulPreOrderHeapIter<'a>>;
|
||||||
|
|
||||||
impl<'a> LeftistPostOrderHeapIter<'a> {
|
impl<'a> LeftistPostOrderHeapIter<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pop_stack(&mut self) {
|
pub fn pop_stack(&mut self) {
|
||||||
if let Some((child_count, _)) = self.parent_stack.last() {
|
if let Some((child_count, ..)) = self.parent_stack.last() {
|
||||||
for _ in 0 .. *child_count {
|
for _ in 0 .. *child_count {
|
||||||
self.base_iter.pop_stack();
|
self.base_iter.pop_stack();
|
||||||
}
|
}
|
||||||
@@ -335,9 +406,11 @@ pub(crate) fn stackful_post_order_iter<'a>(
|
|||||||
PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, cell))
|
PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, cell))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) type RightistPostOrderHeapIter<'a> =
|
pub(crate) type RightistPostOrderHeapIter<'a> =
|
||||||
PostOrderIterator<StacklessPreOrderHeapIter<'a, IteratorUMP>>;
|
PostOrderIterator<StacklessPreOrderHeapIter<'a, IteratorUMP>>;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn stackless_post_order_iter<'a>(
|
pub(crate) fn stackless_post_order_iter<'a>(
|
||||||
heap: &'a mut Heap,
|
heap: &'a mut Heap,
|
||||||
@@ -351,6 +424,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::machine::mock_wam::*;
|
use crate::machine::mock_wam::*;
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn heap_stackless_iter_tests() {
|
fn heap_stackless_iter_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
@@ -513,6 +587,7 @@ mod tests {
|
|||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
atom_as_cell!(b_atom)
|
atom_as_cell!(b_atom)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
atom_as_cell!(a_atom)
|
atom_as_cell!(a_atom)
|
||||||
@@ -574,7 +649,7 @@ mod tests {
|
|||||||
heap_loc_as_cell!(1),
|
heap_loc_as_cell!(1),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(iter.next(), None);
|
assert!(iter.next().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(wam.machine_st.heap[0], pstr_cell);
|
assert_eq!(wam.machine_st.heap[0], pstr_cell);
|
||||||
@@ -601,7 +676,7 @@ mod tests {
|
|||||||
heap_loc_as_cell!(3),
|
heap_loc_as_cell!(3),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(iter.next(), None);
|
assert!(iter.next().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(wam.machine_st.heap[0], pstr_cell);
|
assert_eq!(wam.machine_st.heap[0], pstr_cell);
|
||||||
@@ -623,8 +698,8 @@ mod tests {
|
|||||||
let pstr_offset_cell = pstr_offset_as_cell!(0);
|
let pstr_offset_cell = pstr_offset_as_cell!(0);
|
||||||
|
|
||||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
|
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
|
||||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
|
|
||||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
|
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
|
||||||
|
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
|
||||||
|
|
||||||
assert_eq!(iter.next(), None);
|
assert_eq!(iter.next(), None);
|
||||||
}
|
}
|
||||||
@@ -1257,6 +1332,42 @@ mod tests {
|
|||||||
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(atom!("f"), 2));
|
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(atom!("f"), 2));
|
||||||
assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1));
|
assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1));
|
||||||
assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(1));
|
assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(1));
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
// representation of one of the heap terms as in issue #1384.
|
||||||
|
/*
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(7));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(0));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(5));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(2));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(2));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(3));
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut iter = stackless_preorder_iter(
|
||||||
|
&mut wam.machine_st.heap,
|
||||||
|
heap_loc_as_cell!(0),
|
||||||
|
);
|
||||||
|
|
||||||
|
while let Some(_) = iter.next() {
|
||||||
|
print_heap_terms(iter.heap.iter(), 0);
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
assert_eq!(
|
||||||
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
|
atom_as_cell!(atom!("f"), 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(iter.next().is_none());
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1271,7 +1382,7 @@ mod tests {
|
|||||||
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
|
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
|
let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, str_loc_as_cell!(0));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
@@ -1302,7 +1413,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
|
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
|
let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, str_loc_as_cell!(0));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
@@ -1425,7 +1536,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
list_loc_as_cell!(1)
|
heap_loc_as_cell!(0)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(iter.next(), None);
|
assert_eq!(iter.next(), None);
|
||||||
@@ -1669,7 +1780,9 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut link_back = list_loc_as_cell!(1);
|
let mut link_back = list_loc_as_cell!(1);
|
||||||
|
|
||||||
link_back.set_forwarding_bit(true);
|
link_back.set_forwarding_bit(true);
|
||||||
|
link_back.set_mark_bit(true);
|
||||||
|
|
||||||
assert_eq!(iter.next().unwrap(), link_back);
|
assert_eq!(iter.next().unwrap(), link_back);
|
||||||
|
|
||||||
@@ -1691,9 +1804,14 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut cyclic_link = list_loc_as_cell!(1);
|
let mut cyclic_link = list_loc_as_cell!(1);
|
||||||
cyclic_link.set_forwarding_bit(true);
|
|
||||||
|
|
||||||
assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1));
|
cyclic_link.set_forwarding_bit(true);
|
||||||
|
cyclic_link.set_mark_bit(true);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
|
list_loc_as_cell!(1)
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
list_loc_as_cell!(1)
|
list_loc_as_cell!(1)
|
||||||
@@ -1757,11 +1875,11 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
str_loc_as_cell!(1)
|
heap_loc_as_cell!(0)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
iter.next().unwrap(),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
atom_as_cell!(atom!("y"))
|
atom_as_cell!(atom!("y"))
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1781,7 +1899,7 @@ mod tests {
|
|||||||
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
|
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
|
let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
@@ -1812,7 +1930,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
|
|
||||||
for _ in 0..20 { // 0000 {
|
for _ in 0..20 { // 0000 {
|
||||||
let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
|
let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
@@ -1929,7 +2047,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
list_loc_as_cell!(1)
|
heap_loc_as_cell!(0)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
@@ -2157,7 +2275,9 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut link_back = list_loc_as_cell!(1);
|
let mut link_back = list_loc_as_cell!(1);
|
||||||
|
|
||||||
link_back.set_forwarding_bit(true);
|
link_back.set_forwarding_bit(true);
|
||||||
|
link_back.set_mark_bit(true);
|
||||||
|
|
||||||
assert_eq!(iter.next().unwrap(), link_back);
|
assert_eq!(iter.next().unwrap(), link_back);
|
||||||
|
|
||||||
@@ -2271,6 +2391,11 @@ mod tests {
|
|||||||
|
|
||||||
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
|
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
|
heap_loc_as_cell!(1)
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
unmark_cell_bits!(iter.next().unwrap()),
|
unmark_cell_bits!(iter.next().unwrap()),
|
||||||
heap_loc_as_cell!(0)
|
heap_loc_as_cell!(0)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::instructions::*;
|
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::parser::rug::{Integer, Rational};
|
use crate::parser::rug::{Integer, Rational};
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -116,7 +115,6 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
|||||||
let mut parent_spec = DirectedOp::Left(atom!("-"), OpDesc::build_with(200, FY as u8));
|
let mut parent_spec = DirectedOp::Left(atom!("-"), OpDesc::build_with(200, FY as u8));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// match self.machine_st.store(self.machine_st.deref(addr)) {
|
|
||||||
read_heap_cell!(self.heap[h],
|
read_heap_cell!(self.heap[h],
|
||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
read_heap_cell!(self.heap[s],
|
read_heap_cell!(self.heap[s],
|
||||||
@@ -156,7 +154,6 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
|||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// let addr = self.machine_st.store(self.machine_st.deref(addr));
|
|
||||||
property_check(addr)
|
property_check(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,16 +168,12 @@ fn char_to_string(is_quoted: bool, c: char) -> String {
|
|||||||
'\u{0c}' if is_quoted => "\\f".to_string(), // UTF-8 form feed
|
'\u{0c}' if is_quoted => "\\f".to_string(), // UTF-8 form feed
|
||||||
'\u{08}' if is_quoted => "\\b".to_string(), // UTF-8 backspace
|
'\u{08}' if is_quoted => "\\b".to_string(), // UTF-8 backspace
|
||||||
'\u{07}' if is_quoted => "\\a".to_string(), // UTF-8 alert
|
'\u{07}' if is_quoted => "\\a".to_string(), // UTF-8 alert
|
||||||
'"' if is_quoted => "\\\"".to_string(),
|
|
||||||
'\\' if is_quoted => "\\\\".to_string(),
|
'\\' if is_quoted => "\\\\".to_string(),
|
||||||
'\'' | '\n' | '\r' | '\t' | '\u{0b}' | '\u{0c}' | '\u{08}' | '\u{07}' | '"' | '\\' => {
|
'\'' | '\n' | '\r' | '\t' | '\u{0b}' | '\u{0c}' | '\u{08}' | '\u{07}' | '"' | '\\' => {
|
||||||
c.to_string()
|
c.to_string()
|
||||||
}
|
}
|
||||||
'\u{a0}'..='\u{d6}' => c.to_string(),
|
'\u{0}'..='\u{1f}' => format!("\\x{:x}\\", c as u32), // print all other control characters in hex.
|
||||||
'\u{d8}'..='\u{f6}' => c.to_string(),
|
_ => c.to_string(),
|
||||||
'\u{f8}'..='\u{74f}' => c.to_string(),
|
|
||||||
'\x20'..='\x7e' => c.to_string(),
|
|
||||||
_ => format!("\\x{:x}\\", c as u32),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,9 +201,10 @@ enum TokenOrRedirect {
|
|||||||
Op(Atom, OpDesc),
|
Op(Atom, OpDesc),
|
||||||
NumberedVar(String),
|
NumberedVar(String),
|
||||||
CompositeRedirect(usize, DirectedOp),
|
CompositeRedirect(usize, DirectedOp),
|
||||||
|
CurlyBracketRedirect(usize),
|
||||||
FunctorRedirect(usize),
|
FunctorRedirect(usize),
|
||||||
#[allow(unused)] IpAddr(IpAddr),
|
#[allow(unused)] IpAddr(IpAddr),
|
||||||
NumberFocus(NumberFocus, Option<DirectedOp>),
|
NumberFocus(usize, NumberFocus, Option<DirectedOp>),
|
||||||
Open,
|
Open,
|
||||||
Close,
|
Close,
|
||||||
Comma,
|
Comma,
|
||||||
@@ -382,9 +376,9 @@ impl HCValueOutputter for PrinterOutputter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool {
|
fn is_numbered_var(name: Atom, arity: usize) -> bool {
|
||||||
arity == 1 && ct.name().as_str() == "$VAR"
|
arity == 1 && name == atom!("$VAR")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -407,43 +401,6 @@ fn negated_op_needs_bracketing(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String> {
|
|
||||||
fn numbervar(n: Integer) -> String {
|
|
||||||
static CHAR_CODES: [char; 26] = [
|
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
|
|
||||||
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
|
||||||
];
|
|
||||||
|
|
||||||
let i = n.mod_u(26) as usize;
|
|
||||||
let j = n.div_rem_floor(Integer::from(26));
|
|
||||||
let j = <(Integer, Integer)>::from(j).0;
|
|
||||||
|
|
||||||
if j == 0 {
|
|
||||||
CHAR_CODES[i].to_string()
|
|
||||||
} else {
|
|
||||||
format!("{}{}", CHAR_CODES[i], j)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match Number::try_from(addr) {
|
|
||||||
Ok(Number::Fixnum(n)) => {
|
|
||||||
if n.get_num() >= 0 {
|
|
||||||
Some(numbervar(offset + Integer::from(n.get_num())))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Number::Integer(n)) => {
|
|
||||||
if &*n >= &0 {
|
|
||||||
Some(numbervar(Integer::from(offset + &*n)))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! push_char {
|
macro_rules! push_char {
|
||||||
($self:ident, $c:expr) => {{
|
($self:ident, $c:expr) => {{
|
||||||
$self.outputter.push_char($c);
|
$self.outputter.push_char($c);
|
||||||
@@ -484,11 +441,33 @@ macro_rules! print_char {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fmt_float(mut fl: f64) -> String {
|
||||||
|
if OrderedFloat(fl) == -0f64 {
|
||||||
|
fl = 0f64;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buffer = ryu::Buffer::new();
|
||||||
|
let fl_str = buffer.format(fl);
|
||||||
|
|
||||||
|
/* When printing floats with zero fractional parts in scientific notation, ryu
|
||||||
|
* prints "{integer part}e{exponent}" without a ".0" preceding "e",
|
||||||
|
* which is not valid ISO Prolog syntax. Add ".0" manually in this
|
||||||
|
* case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if let Some(e_index) = fl_str.find('e') {
|
||||||
|
if !fl_str[0 .. e_index].contains('.') {
|
||||||
|
return fl_str[0 .. e_index].to_string() + ".0" + &fl_str[e_index ..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fl_str.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HCPrinter<'a, Outputter> {
|
pub struct HCPrinter<'a, Outputter> {
|
||||||
outputter: Outputter,
|
outputter: Outputter,
|
||||||
iter: StackfulPreOrderHeapIter<'a>,
|
iter: StackfulPreOrderHeapIter<'a>,
|
||||||
arena: &'a mut Arena,
|
|
||||||
op_dir: &'a OpDir,
|
op_dir: &'a OpDir,
|
||||||
state_stack: Vec<TokenOrRedirect>,
|
state_stack: Vec<TokenOrRedirect>,
|
||||||
toplevel_spec: Option<DirectedOp>,
|
toplevel_spec: Option<DirectedOp>,
|
||||||
@@ -513,10 +492,46 @@ macro_rules! push_space_if_amb {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String> {
|
||||||
|
fn numbervar(n: Integer) -> String {
|
||||||
|
static CHAR_CODES: [char; 26] = [
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
|
||||||
|
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||||
|
];
|
||||||
|
|
||||||
|
let i = n.mod_u(26) as usize;
|
||||||
|
let j = n.div_rem_floor(Integer::from(26));
|
||||||
|
let j = <(Integer, Integer)>::from(j).0;
|
||||||
|
|
||||||
|
if j == 0 {
|
||||||
|
CHAR_CODES[i].to_string()
|
||||||
|
} else {
|
||||||
|
format!("{}{}", CHAR_CODES[i], j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match Number::try_from(addr) {
|
||||||
|
Ok(Number::Fixnum(n)) => {
|
||||||
|
if n.get_num() >= 0 {
|
||||||
|
Some(numbervar(offset + Integer::from(n.get_num())))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Number::Integer(n)) => {
|
||||||
|
if &*n >= &0 {
|
||||||
|
Some(numbervar(Integer::from(offset + &*n)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
heap: &'a mut Heap,
|
heap: &'a mut Heap,
|
||||||
arena: &'a mut Arena,
|
|
||||||
op_dir: &'a OpDir,
|
op_dir: &'a OpDir,
|
||||||
output: Outputter,
|
output: Outputter,
|
||||||
cell: HeapCellValue,
|
cell: HeapCellValue,
|
||||||
@@ -524,7 +539,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
HCPrinter {
|
HCPrinter {
|
||||||
outputter: output,
|
outputter: output,
|
||||||
iter: stackful_preorder_iter(heap, cell),
|
iter: stackful_preorder_iter(heap, cell),
|
||||||
arena,
|
|
||||||
op_dir,
|
op_dir,
|
||||||
state_stack: vec![],
|
state_stack: vec![],
|
||||||
toplevel_spec: None,
|
toplevel_spec: None,
|
||||||
@@ -545,9 +559,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
requires_space(tail, atom)
|
requires_space(tail, atom)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enqueue_op(&mut self, mut max_depth: usize, ct: ClauseType, spec: OpDesc) {
|
fn enqueue_op(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) {
|
||||||
let name = ct.name();
|
|
||||||
|
|
||||||
if is_postfix!(spec.get_spec()) {
|
if is_postfix!(spec.get_spec()) {
|
||||||
if self.check_max_depth(&mut max_depth) {
|
if self.check_max_depth(&mut max_depth) {
|
||||||
self.iter.pop_stack();
|
self.iter.pop_stack();
|
||||||
@@ -634,26 +646,30 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
self.iter.pop_stack();
|
self.iter.pop_stack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if arity > 0 {
|
||||||
self.state_stack.push(TokenOrRedirect::Close);
|
self.state_stack.push(TokenOrRedirect::Close);
|
||||||
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
|
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
|
||||||
self.state_stack.push(TokenOrRedirect::Open);
|
self.state_stack.push(TokenOrRedirect::Open);
|
||||||
|
}
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::Atom(name));
|
self.state_stack.push(TokenOrRedirect::Atom(name));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if arity > 0 {
|
||||||
self.state_stack.push(TokenOrRedirect::Close);
|
self.state_stack.push(TokenOrRedirect::Close);
|
||||||
|
|
||||||
for _ in 0..arity {
|
for _ in 0..arity {
|
||||||
self.state_stack
|
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
|
||||||
.push(TokenOrRedirect::FunctorRedirect(max_depth));
|
|
||||||
self.state_stack.push(TokenOrRedirect::Comma);
|
self.state_stack.push(TokenOrRedirect::Comma);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state_stack.pop();
|
self.state_stack.pop();
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::Open);
|
self.state_stack.push(TokenOrRedirect::Open);
|
||||||
|
}
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::Atom(name));
|
self.state_stack.push(TokenOrRedirect::Atom(name));
|
||||||
|
|
||||||
true
|
true
|
||||||
@@ -672,8 +688,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
|
|
||||||
let op = DirectedOp::Left(name, spec);
|
let op = DirectedOp::Left(name, spec);
|
||||||
|
|
||||||
self.state_stack
|
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
|
||||||
.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
|
|
||||||
self.state_stack.push(TokenOrRedirect::Space);
|
self.state_stack.push(TokenOrRedirect::Space);
|
||||||
self.state_stack.push(TokenOrRedirect::Atom(name));
|
self.state_stack.push(TokenOrRedirect::Atom(name));
|
||||||
}
|
}
|
||||||
@@ -720,9 +735,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::RightCurly);
|
self.state_stack.push(TokenOrRedirect::RightCurly);
|
||||||
self.state_stack
|
self.state_stack.push(TokenOrRedirect::CurlyBracketRedirect(max_depth));
|
||||||
.push(TokenOrRedirect::FunctorRedirect(max_depth));
|
|
||||||
self.state_stack.push(TokenOrRedirect::LeftCurly);
|
self.state_stack.push(TokenOrRedirect::LeftCurly);
|
||||||
|
|
||||||
true
|
true
|
||||||
@@ -731,8 +746,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
fn format_numbered_vars(&mut self) -> bool {
|
fn format_numbered_vars(&mut self) -> bool {
|
||||||
let h = self.iter.stack_last().unwrap();
|
let h = self.iter.stack_last().unwrap();
|
||||||
|
|
||||||
|
let addr = self.iter.heap[h];
|
||||||
|
let addr = heap_bound_store(
|
||||||
|
&self.iter.heap,
|
||||||
|
heap_bound_deref(&self.iter.heap, addr),
|
||||||
|
);
|
||||||
|
|
||||||
// 7.10.4
|
// 7.10.4
|
||||||
if let Some(var) = numbervar(&self.numbervars_offset, self.iter.heap[h]) {
|
if let Some(var) = numbervar(&self.numbervars_offset, addr) {
|
||||||
self.iter.pop_stack();
|
self.iter.pop_stack();
|
||||||
self.state_stack.push(TokenOrRedirect::NumberedVar(var));
|
self.state_stack.push(TokenOrRedirect::NumberedVar(var));
|
||||||
return true;
|
return true;
|
||||||
@@ -745,17 +766,16 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
max_depth: usize,
|
max_depth: usize,
|
||||||
arity: usize,
|
arity: usize,
|
||||||
ct: ClauseType,
|
name: Atom,
|
||||||
op_desc: Option<OpDesc>,
|
op_desc: Option<OpDesc>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if self.numbervars && is_numbered_var(&ct, arity) {
|
if self.numbervars && is_numbered_var(name, arity) {
|
||||||
if self.format_numbered_vars() {
|
if self.format_numbered_vars() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let dot_atom = atom!(".");
|
let dot_atom = atom!(".");
|
||||||
let name = ct.name();
|
|
||||||
|
|
||||||
if let Some(spec) = op_desc {
|
if let Some(spec) = op_desc {
|
||||||
if dot_atom == name && is_infix!(spec.get_spec()) {
|
if dot_atom == name && is_infix!(spec.get_spec()) {
|
||||||
@@ -766,13 +786,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !self.ignore_ops && spec.get_prec() > 0 {
|
if !self.ignore_ops && spec.get_prec() > 0 {
|
||||||
self.enqueue_op(max_depth, ct, spec);
|
self.enqueue_op(max_depth, name, spec);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return match (name.as_str(), arity) {
|
return match (name, arity) {
|
||||||
("{}", 1) if !self.ignore_ops => self.format_curly_braces(max_depth),
|
(atom!("{}"), 1) if !self.ignore_ops => self.format_curly_braces(max_depth),
|
||||||
_ => self.format_struct(max_depth, arity, name),
|
_ => self.format_struct(max_depth, arity, name),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -810,7 +830,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
|
|
||||||
fn check_for_seen(&mut self) -> Option<HeapCellValue> {
|
fn check_for_seen(&mut self) -> Option<HeapCellValue> {
|
||||||
if let Some(addr) = self.iter.next() {
|
if let Some(addr) = self.iter.next() {
|
||||||
let is_cyclic = addr.is_forwarded();
|
let is_cyclic = addr.get_forwarding_bit();
|
||||||
|
|
||||||
let addr = heap_bound_store(
|
let addr = heap_bound_store(
|
||||||
self.iter.heap,
|
self.iter.heap,
|
||||||
@@ -836,7 +856,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
var_opt => {
|
var_opt => {
|
||||||
if is_cyclic && addr.is_compound() {
|
if is_cyclic && addr.is_compound(self.iter.heap) {
|
||||||
// self-referential variables are marked "cyclic".
|
// self-referential variables are marked "cyclic".
|
||||||
match var_opt {
|
match var_opt {
|
||||||
Some(var) => {
|
Some(var) => {
|
||||||
@@ -922,7 +942,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
append_str!(self, &format!("0x{:x}", ptr as *const u8 as usize));
|
append_str!(self, &format!("0x{:x}", ptr as *const u8 as usize));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_number(&mut self, n: NumberFocus, op: &Option<DirectedOp>) {
|
fn print_number(&mut self, max_depth: usize, n: NumberFocus, op: &Option<DirectedOp>) {
|
||||||
let add_brackets = if let Some(op) = op {
|
let add_brackets = if let Some(op) = op {
|
||||||
op.is_negative_sign() && !n.is_negative()
|
op.is_negative_sign() && !n.is_negative()
|
||||||
} else {
|
} else {
|
||||||
@@ -935,30 +955,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
|
|
||||||
match n {
|
match n {
|
||||||
NumberFocus::Unfocused(n) => match n {
|
NumberFocus::Unfocused(n) => match n {
|
||||||
Number::Float(OrderedFloat(mut fl)) => {
|
Number::Float(OrderedFloat(fl)) => {
|
||||||
if OrderedFloat(fl) == -0f64 {
|
let output_str = fmt_float(fl);
|
||||||
fl = 0f64;
|
|
||||||
}
|
|
||||||
|
|
||||||
let output_str = if fl.fract() == 0f64 {
|
|
||||||
if fl.abs() >= 1.0e16 {
|
|
||||||
format!("{:.1e}", fl.trunc())
|
|
||||||
} else {
|
|
||||||
format!("{:.1}", fl.trunc())
|
|
||||||
}
|
|
||||||
} else if 0f64 < fl.fract().abs() && fl.fract().abs() <= 1.0e-16 {
|
|
||||||
format!("{:>1e}", fl)
|
|
||||||
} else {
|
|
||||||
format!("{}", fl)
|
|
||||||
};
|
|
||||||
|
|
||||||
push_space_if_amb!(self, &output_str, {
|
push_space_if_amb!(self, &output_str, {
|
||||||
append_str!(self, &output_str);
|
append_str!(self, &output_str);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Number::Rational(r) => {
|
Number::Rational(r) => {
|
||||||
self.print_rational(r, add_brackets);
|
self.print_rational(max_depth, r);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
n => {
|
n => {
|
||||||
let output_str = format!("{}", n);
|
let output_str = format!("{}", n);
|
||||||
@@ -989,11 +994,27 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_rational(&mut self, r: TypedArenaPtr<Rational>, add_brackets: bool) {
|
fn print_rational(&mut self, mut max_depth: usize, r: TypedArenaPtr<Rational>) {
|
||||||
|
if self.check_max_depth(&mut max_depth) {
|
||||||
|
self.state_stack.push(TokenOrRedirect::Close);
|
||||||
|
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
|
||||||
|
self.state_stack.push(TokenOrRedirect::Open);
|
||||||
|
|
||||||
|
self.state_stack.push(TokenOrRedirect::Atom(atom!("rdiv")));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) {
|
match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) {
|
||||||
Some(op_desc) => {
|
Some(op_desc) => {
|
||||||
if add_brackets {
|
if r.is_integer() {
|
||||||
self.state_stack.push(TokenOrRedirect::Close);
|
let output_str = format!("{}", r);
|
||||||
|
|
||||||
|
push_space_if_amb!(self, &output_str, {
|
||||||
|
append_str!(self, &output_str);
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rdiv_ct = atom!("rdiv");
|
let rdiv_ct = atom!("rdiv");
|
||||||
@@ -1010,8 +1031,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if op_desc.get_prec() > 0 {
|
if !self.ignore_ops && op_desc.get_prec() > 0 {
|
||||||
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
||||||
|
max_depth,
|
||||||
NumberFocus::Denominator(r),
|
NumberFocus::Denominator(r),
|
||||||
left_directed_op,
|
left_directed_op,
|
||||||
));
|
));
|
||||||
@@ -1020,6 +1042,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
.push(TokenOrRedirect::Op(rdiv_ct, *op_desc));
|
.push(TokenOrRedirect::Op(rdiv_ct, *op_desc));
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
||||||
|
max_depth,
|
||||||
NumberFocus::Numerator(r),
|
NumberFocus::Numerator(r),
|
||||||
right_directed_op,
|
right_directed_op,
|
||||||
));
|
));
|
||||||
@@ -1027,6 +1050,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
self.state_stack.push(TokenOrRedirect::Close);
|
self.state_stack.push(TokenOrRedirect::Close);
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
||||||
|
max_depth,
|
||||||
NumberFocus::Denominator(r),
|
NumberFocus::Denominator(r),
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
@@ -1034,6 +1058,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
self.state_stack.push(TokenOrRedirect::Comma);
|
self.state_stack.push(TokenOrRedirect::Comma);
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
||||||
|
max_depth,
|
||||||
NumberFocus::Numerator(r),
|
NumberFocus::Numerator(r),
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
@@ -1076,10 +1101,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
push_char!(self, '"');
|
push_char!(self, '"');
|
||||||
|
|
||||||
let iter = HeapPStrIter::new(self.iter.heap, focus);
|
let iter = HeapPStrIter::new(self.iter.heap, focus);
|
||||||
|
let char_to_string = |c: char| {
|
||||||
|
// refrain from quoting characters other than '"' and '\'
|
||||||
|
// unless self.quoted is true.
|
||||||
|
match c {
|
||||||
|
'\\' => "\\\\".to_string(),
|
||||||
|
'"' => "\\\"".to_string(),
|
||||||
|
_ => char_to_string(self.quoted, c),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if max_depth == 0 {
|
if max_depth == 0 {
|
||||||
for c in iter.chars() {
|
for c in iter.chars() {
|
||||||
for c in char_to_string(self.quoted, c).chars() {
|
for c in char_to_string(c).chars() {
|
||||||
push_char!(self, c);
|
push_char!(self, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1089,7 +1123,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
for c in iter.chars().take(max_depth) {
|
for c in iter.chars().take(max_depth) {
|
||||||
char_count += 1;
|
char_count += 1;
|
||||||
|
|
||||||
for c in char_to_string(self.quoted, c).chars() {
|
for c in char_to_string(c).chars() {
|
||||||
push_char!(self, c);
|
push_char!(self, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1175,18 +1209,25 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
let pstr = cell_as_string!(self.iter.heap[h]);
|
let pstr = cell_as_string!(self.iter.heap[h]);
|
||||||
|
|
||||||
let pstr = pstr.as_str_from(offset.get_num() as usize);
|
let pstr = pstr.as_str_from(offset.get_num() as usize);
|
||||||
|
let tag = value.get_tag();
|
||||||
|
|
||||||
|
if tag == HeapCellValueTag::PStrOffset {
|
||||||
|
// remove the fixnum offset from the iterator stack so we don't
|
||||||
|
// print an extraneous number. pstr offset value cells are never
|
||||||
|
// used by the iterator to mark cyclic terms so the removal is safe.
|
||||||
|
self.iter.pop_stack();
|
||||||
|
}
|
||||||
|
|
||||||
if max_depth > 0 && pstr.chars().count() + 1 >= max_depth {
|
if max_depth > 0 && pstr.chars().count() + 1 >= max_depth {
|
||||||
if value.get_tag() != HeapCellValueTag::CStr {
|
if tag != HeapCellValueTag::PStrOffset && tag != HeapCellValueTag::CStr {
|
||||||
self.iter.pop_stack();
|
self.iter.pop_stack();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
|
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
|
||||||
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
|
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
|
||||||
} else if end_cell != empty_list_as_cell!() {
|
} else if end_cell != empty_list_as_cell!() {
|
||||||
if value.get_tag() != HeapCellValueTag::CStr {
|
if tag == HeapCellValueTag::PStrOffset {
|
||||||
self.iter.pop_stack();
|
self.iter.push_stack(end_h);
|
||||||
self.iter.push_stack(h+1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
|
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
|
||||||
@@ -1264,9 +1305,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
max_depth: usize,
|
max_depth: usize,
|
||||||
) {
|
) {
|
||||||
let add_brackets = if !self.ignore_ops {
|
let add_brackets = if !self.ignore_ops {
|
||||||
negated_operand
|
negated_operand ||
|
||||||
|| if let Some(ref op) = op {
|
if let Some(ref op) = op {
|
||||||
if self.numbervars && arity == 1 && name.as_str() == "$VAR" {
|
if self.numbervars && arity == 1 && name == atom!("$VAR") {
|
||||||
!self.iter.immediate_leaf_has_property(|addr| {
|
!self.iter.immediate_leaf_has_property(|addr| {
|
||||||
match Number::try_from(addr) {
|
match Number::try_from(addr) {
|
||||||
Ok(Number::Integer(n)) => &*n >= &0,
|
Ok(Number::Integer(n)) => &*n >= &0,
|
||||||
@@ -1290,9 +1331,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
self.state_stack.push(TokenOrRedirect::Close);
|
self.state_stack.push(TokenOrRedirect::Close);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ct = ClauseType::from(name, arity);
|
if self.format_clause(max_depth, arity, name, Some(op_desc)) && add_brackets {
|
||||||
|
|
||||||
if self.format_clause(max_depth, arity, ct, Some(op_desc)) && add_brackets {
|
|
||||||
self.state_stack.push(TokenOrRedirect::Open);
|
self.state_stack.push(TokenOrRedirect::Open);
|
||||||
|
|
||||||
if let Some(ref op) = &op {
|
if let Some(ref op) = &op {
|
||||||
@@ -1306,10 +1345,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) {
|
fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) {
|
||||||
let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() {
|
let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() {
|
||||||
(
|
(addr.ip(), addr.port())
|
||||||
addr.ip(),
|
|
||||||
Number::arena_from(addr.port() as usize, self.arena),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
let disconnected_atom = atom!("$disconnected_tcp_listener");
|
let disconnected_atom = atom!("$disconnected_tcp_listener");
|
||||||
self.state_stack
|
self.state_stack
|
||||||
@@ -1327,7 +1363,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
self.state_stack.pop();
|
self.state_stack.pop();
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
||||||
NumberFocus::Unfocused(port),
|
max_depth,
|
||||||
|
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port as i64))),
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
self.state_stack.push(TokenOrRedirect::Comma);
|
self.state_stack.push(TokenOrRedirect::Comma);
|
||||||
@@ -1338,6 +1375,31 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_index_ptr(&mut self, index_ptr: IndexPtr, max_depth: usize) {
|
||||||
|
if self.format_struct(max_depth, 1, atom!("$index_ptr")) {
|
||||||
|
let atom = self.state_stack.pop().unwrap();
|
||||||
|
|
||||||
|
self.state_stack.pop();
|
||||||
|
self.state_stack.pop();
|
||||||
|
|
||||||
|
let offset = if index_ptr.is_undefined() || index_ptr.is_dynamic_undefined() {
|
||||||
|
TokenOrRedirect::Atom(atom!("undefined"))
|
||||||
|
} else {
|
||||||
|
let idx = index_ptr.p() as i64;
|
||||||
|
|
||||||
|
TokenOrRedirect::NumberFocus(
|
||||||
|
max_depth,
|
||||||
|
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx))),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.state_stack.push(offset);
|
||||||
|
self.state_stack.push(TokenOrRedirect::Open);
|
||||||
|
self.state_stack.push(atom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn print_stream(&mut self, stream: Stream, max_depth: usize) {
|
fn print_stream(&mut self, stream: Stream, max_depth: usize) {
|
||||||
if let Some(alias) = stream.options().get_alias() {
|
if let Some(alias) = stream.options().get_alias() {
|
||||||
self.print_atom(alias);
|
self.print_atom(alias);
|
||||||
@@ -1395,8 +1457,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
push_space_if_amb!(self, name.as_str(), {
|
push_space_if_amb!(self, name.as_str(), {
|
||||||
let ct = ClauseType::from(name, arity);
|
self.format_clause(max_depth, arity, name, None);
|
||||||
self.format_clause(max_depth, arity, ct, None);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if fetch_op_spec(name, arity, self.op_dir).is_some() {
|
} else if fetch_op_spec(name, arity, self.op_dir).is_some() {
|
||||||
@@ -1441,16 +1502,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
push_space_if_amb!(self, name.as_str(), {
|
push_space_if_amb!(self, name.as_str(), {
|
||||||
let ct = ClauseType::from(name, arity);
|
self.format_clause(max_depth, arity, name, None);
|
||||||
self.format_clause(max_depth, arity, ct, None);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Fixnum, n) => {
|
(HeapCellValueTag::Fixnum, n) => {
|
||||||
self.print_number(NumberFocus::Unfocused(Number::Fixnum(n)), &op);
|
self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::F64, f) => {
|
(HeapCellValueTag::F64, f) => {
|
||||||
self.print_number(NumberFocus::Unfocused(Number::Float(**f)), &op);
|
self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(*f)), &op);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
(HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
||||||
self.print_list_like(max_depth);
|
self.print_list_like(max_depth);
|
||||||
@@ -1477,20 +1537,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
(HeapCellValueTag::Cons, c) => {
|
(HeapCellValueTag::Cons, c) => {
|
||||||
match_untyped_arena_ptr!(c,
|
match_untyped_arena_ptr!(c,
|
||||||
(ArenaHeaderTag::F64, f) => {
|
|
||||||
self.print_number(NumberFocus::Unfocused(Number::Float(*f)), &op);
|
|
||||||
}
|
|
||||||
(ArenaHeaderTag::Integer, n) => {
|
(ArenaHeaderTag::Integer, n) => {
|
||||||
self.print_number(NumberFocus::Unfocused(Number::Integer(n)), &op);
|
self.print_number(max_depth, NumberFocus::Unfocused(Number::Integer(n)), &op);
|
||||||
}
|
}
|
||||||
(ArenaHeaderTag::Rational, r) => {
|
(ArenaHeaderTag::Rational, r) => {
|
||||||
self.print_number(NumberFocus::Unfocused(Number::Rational(r)), &op);
|
self.print_number(max_depth, NumberFocus::Unfocused(Number::Rational(r)), &op);
|
||||||
}
|
}
|
||||||
(ArenaHeaderTag::Stream, stream) => {
|
(ArenaHeaderTag::Stream, stream) => {
|
||||||
self.print_stream(stream, max_depth);
|
self.print_stream(stream, max_depth);
|
||||||
}
|
}
|
||||||
(ArenaHeaderTag::OssifiedOpDir, _op_dir) => {
|
(ArenaHeaderTag::OssifiedOpDir, _op_dir) => {
|
||||||
append_str!(self, "$ossified_op_dir");
|
self.print_atom(atom!("$ossified_op_dir"));
|
||||||
|
}
|
||||||
|
(ArenaHeaderTag::Dropped, _value) => {
|
||||||
|
self.print_atom(atom!("$dropped_value"));
|
||||||
|
}
|
||||||
|
(ArenaHeaderTag::IndexPtr, index_ptr) => {
|
||||||
|
self.print_index_ptr(*index_ptr, max_depth);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
}
|
}
|
||||||
@@ -1516,8 +1579,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn print(mut self) -> Outputter {
|
pub fn print(mut self) -> Outputter {
|
||||||
loop {
|
let spec = self.toplevel_spec.take();
|
||||||
if let Some(loc_data) = self.state_stack.pop() {
|
self.handle_heap_term(spec, false, self.max_depth);
|
||||||
|
|
||||||
|
while let Some(loc_data) = self.state_stack.pop() {
|
||||||
match loc_data {
|
match loc_data {
|
||||||
TokenOrRedirect::Atom(atom) => self.print_atom(atom),
|
TokenOrRedirect::Atom(atom) => self.print_atom(atom),
|
||||||
TokenOrRedirect::BarAsOp => append_str!(self, " | "),
|
TokenOrRedirect::BarAsOp => append_str!(self, " | "),
|
||||||
@@ -1527,6 +1592,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
TokenOrRedirect::CompositeRedirect(max_depth, op) => {
|
TokenOrRedirect::CompositeRedirect(max_depth, op) => {
|
||||||
self.handle_heap_term(Some(op), false, max_depth)
|
self.handle_heap_term(Some(op), false, max_depth)
|
||||||
}
|
}
|
||||||
|
TokenOrRedirect::CurlyBracketRedirect(max_depth) => {
|
||||||
|
self.handle_heap_term(None, false, max_depth)
|
||||||
|
}
|
||||||
TokenOrRedirect::FunctorRedirect(max_depth) => {
|
TokenOrRedirect::FunctorRedirect(max_depth) => {
|
||||||
self.handle_heap_term(None, true, max_depth)
|
self.handle_heap_term(None, true, max_depth)
|
||||||
}
|
}
|
||||||
@@ -1548,18 +1616,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TokenOrRedirect::HeadTailSeparator => append_str!(self, "|"),
|
TokenOrRedirect::HeadTailSeparator => append_str!(self, "|"),
|
||||||
TokenOrRedirect::NumberFocus(n, op) => self.print_number(n, &op),
|
TokenOrRedirect::NumberFocus(max_depth, n, op) => {
|
||||||
|
self.print_number(max_depth, n, &op);
|
||||||
|
}
|
||||||
TokenOrRedirect::Comma => append_str!(self, ","),
|
TokenOrRedirect::Comma => append_str!(self, ","),
|
||||||
TokenOrRedirect::Space => push_char!(self, ' '),
|
TokenOrRedirect::Space => push_char!(self, ' '),
|
||||||
TokenOrRedirect::LeftCurly => push_char!(self, '{'),
|
TokenOrRedirect::LeftCurly => push_char!(self, '{'),
|
||||||
TokenOrRedirect::RightCurly => push_char!(self, '}'),
|
TokenOrRedirect::RightCurly => push_char!(self, '}'),
|
||||||
}
|
}
|
||||||
} else if !self.iter.stack_is_empty() {
|
|
||||||
let spec = self.toplevel_spec.take();
|
|
||||||
self.handle_heap_term(spec, false, self.max_depth);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.outputter
|
self.outputter
|
||||||
@@ -1586,7 +1650,6 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0)
|
heap_loc_as_cell!(0)
|
||||||
@@ -1614,7 +1677,6 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0)
|
heap_loc_as_cell!(0)
|
||||||
@@ -1637,7 +1699,6 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0)
|
heap_loc_as_cell!(0)
|
||||||
@@ -1649,7 +1710,6 @@ mod tests {
|
|||||||
|
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0)
|
heap_loc_as_cell!(0)
|
||||||
@@ -1681,7 +1741,6 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
heap_loc_as_cell!(0),
|
||||||
@@ -1699,7 +1758,6 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
heap_loc_as_cell!(0),
|
||||||
@@ -1715,7 +1773,6 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0)
|
heap_loc_as_cell!(0)
|
||||||
@@ -1746,7 +1803,6 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0)
|
heap_loc_as_cell!(0)
|
||||||
@@ -1768,7 +1824,6 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
pstr_loc_as_cell!(0)
|
pstr_loc_as_cell!(0)
|
||||||
@@ -1795,7 +1850,6 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
&mut wam.machine_st.arena,
|
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
heap_loc_as_cell!(0),
|
||||||
|
|||||||
25
src/http.rs
Normal file
25
src/http.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use std::convert::Infallible;
|
||||||
|
|
||||||
|
use hyper::{Response, Request, Body};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
||||||
|
|
||||||
|
pub struct HttpListener {
|
||||||
|
pub incoming: Receiver<HttpRequest>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HttpRequest {
|
||||||
|
pub request: Request<Body>,
|
||||||
|
pub response: HttpResponse,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type HttpResponse = Sender<Response<Body>>;
|
||||||
|
|
||||||
|
pub async fn serve_req(req: Request<Body>, tx: Arc<Mutex<Sender<HttpRequest>>>) -> Result<Response<Body>, Infallible> {
|
||||||
|
let (response_tx, mut rx) = channel(1);
|
||||||
|
let http_request = HttpRequest { request: req, response: response_tx };
|
||||||
|
tx.lock().await.send(http_request).await.unwrap();
|
||||||
|
Ok(rx.recv().await.unwrap())
|
||||||
|
}
|
||||||
138
src/indexing.rs
138
src/indexing.rs
@@ -4,8 +4,8 @@ use crate::parser::ast::*;
|
|||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
|
|
||||||
|
use fxhash::FxBuildHasher;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use slice_deque::{sdeq, SliceDeque};
|
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
@@ -108,7 +108,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
self.append_or_prepend,
|
self.append_or_prepend,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut constants = IndexMap::new();
|
let mut constants = IndexMap::with_hasher(FxBuildHasher::default());
|
||||||
|
|
||||||
match constant_key {
|
match constant_key {
|
||||||
Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
|
Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
|
||||||
@@ -148,15 +148,15 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
index: usize,
|
index: usize,
|
||||||
) {
|
) {
|
||||||
let third_level_index = if self.append_or_prepend.is_append() {
|
let third_level_index = if self.append_or_prepend.is_append() {
|
||||||
sdeq![
|
vec![
|
||||||
IndexedChoiceInstruction::Try(external),
|
IndexedChoiceInstruction::Try(external),
|
||||||
IndexedChoiceInstruction::Trust(index)
|
IndexedChoiceInstruction::Trust(index)
|
||||||
]
|
].into()
|
||||||
} else {
|
} else {
|
||||||
sdeq![
|
vec![
|
||||||
IndexedChoiceInstruction::Try(index),
|
IndexedChoiceInstruction::Try(index),
|
||||||
IndexedChoiceInstruction::Trust(external)
|
IndexedChoiceInstruction::Trust(external)
|
||||||
]
|
].into()
|
||||||
};
|
};
|
||||||
|
|
||||||
let indexing_code_len = self.indexing_code.len();
|
let indexing_code_len = self.indexing_code.len();
|
||||||
@@ -182,9 +182,9 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
index: usize,
|
index: usize,
|
||||||
) {
|
) {
|
||||||
let third_level_index = if self.append_or_prepend.is_append() {
|
let third_level_index = if self.append_or_prepend.is_append() {
|
||||||
sdeq![external, index]
|
vec![external, index].into()
|
||||||
} else {
|
} else {
|
||||||
sdeq![index, external]
|
vec![index, external].into()
|
||||||
};
|
};
|
||||||
|
|
||||||
let indexing_code_len = self.indexing_code.len();
|
let indexing_code_len = self.indexing_code.len();
|
||||||
@@ -208,11 +208,11 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs)
|
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs)
|
||||||
if self.append_or_prepend.is_append() =>
|
if self.append_or_prepend.is_append() =>
|
||||||
{
|
{
|
||||||
uncap_choice_seq_with_trust(indexed_choice_instrs);
|
uncap_choice_seq_with_trust(indexed_choice_instrs.make_contiguous());
|
||||||
indexed_choice_instrs.push_back(IndexedChoiceInstruction::Trust(index));
|
indexed_choice_instrs.push_back(IndexedChoiceInstruction::Trust(index));
|
||||||
}
|
}
|
||||||
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
|
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
|
||||||
uncap_choice_seq_with_try(indexed_choice_instrs);
|
uncap_choice_seq_with_try(indexed_choice_instrs.make_contiguous());
|
||||||
indexed_choice_instrs.push_front(IndexedChoiceInstruction::Try(index));
|
indexed_choice_instrs.push_front(IndexedChoiceInstruction::Try(index));
|
||||||
}
|
}
|
||||||
IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs)
|
IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs)
|
||||||
@@ -250,7 +250,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
|
IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
|
||||||
let mut constants = IndexMap::new();
|
let mut constants = IndexMap::with_hasher(FxBuildHasher::default());
|
||||||
constants.insert(orig_constant, *c);
|
constants.insert(orig_constant, *c);
|
||||||
|
|
||||||
*c = IndexingCodePtr::Internal(indexing_code_len);
|
*c = IndexingCodePtr::Internal(indexing_code_len);
|
||||||
@@ -390,7 +390,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
self.append_or_prepend,
|
self.append_or_prepend,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut structures = IndexMap::new();
|
let mut structures = IndexMap::with_hasher(FxBuildHasher::default());
|
||||||
|
|
||||||
match structure_key {
|
match structure_key {
|
||||||
Some(OptArgIndexKey::Structure(_, _, name, arity)) => {
|
Some(OptArgIndexKey::Structure(_, _, name, arity)) => {
|
||||||
@@ -430,15 +430,15 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
index: usize,
|
index: usize,
|
||||||
) {
|
) {
|
||||||
let third_level_index = if self.append_or_prepend.is_append() {
|
let third_level_index = if self.append_or_prepend.is_append() {
|
||||||
sdeq![
|
vec![
|
||||||
IndexedChoiceInstruction::Try(external),
|
IndexedChoiceInstruction::Try(external),
|
||||||
IndexedChoiceInstruction::Trust(index)
|
IndexedChoiceInstruction::Trust(index)
|
||||||
]
|
].into()
|
||||||
} else {
|
} else {
|
||||||
sdeq![
|
vec![
|
||||||
IndexedChoiceInstruction::Try(index),
|
IndexedChoiceInstruction::Try(index),
|
||||||
IndexedChoiceInstruction::Trust(external)
|
IndexedChoiceInstruction::Trust(external)
|
||||||
]
|
].into()
|
||||||
};
|
};
|
||||||
|
|
||||||
let indexing_code_len = self.indexing_code.len();
|
let indexing_code_len = self.indexing_code.len();
|
||||||
@@ -464,9 +464,9 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
index: usize,
|
index: usize,
|
||||||
) {
|
) {
|
||||||
let third_level_index = if self.append_or_prepend.is_append() {
|
let third_level_index = if self.append_or_prepend.is_append() {
|
||||||
sdeq![external, index]
|
vec![external, index].into()
|
||||||
} else {
|
} else {
|
||||||
sdeq![index, external]
|
vec![index, external].into()
|
||||||
};
|
};
|
||||||
|
|
||||||
let indexing_code_len = self.indexing_code.len();
|
let indexing_code_len = self.indexing_code.len();
|
||||||
@@ -570,9 +570,9 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
*l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
|
*l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
|
||||||
|
|
||||||
let third_level_index = if self.append_or_prepend.is_append() {
|
let third_level_index = if self.append_or_prepend.is_append() {
|
||||||
sdeq![o, index]
|
vec![o, index].into()
|
||||||
} else {
|
} else {
|
||||||
sdeq![index, o]
|
vec![index, o].into()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.indexing_code
|
self.indexing_code
|
||||||
@@ -582,15 +582,15 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
*l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
|
*l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
|
||||||
|
|
||||||
let third_level_index = if self.append_or_prepend.is_append() {
|
let third_level_index = if self.append_or_prepend.is_append() {
|
||||||
sdeq![
|
vec![
|
||||||
IndexedChoiceInstruction::Try(o),
|
IndexedChoiceInstruction::Try(o),
|
||||||
IndexedChoiceInstruction::Trust(index)
|
IndexedChoiceInstruction::Trust(index)
|
||||||
]
|
].into()
|
||||||
} else {
|
} else {
|
||||||
sdeq![
|
vec![
|
||||||
IndexedChoiceInstruction::Try(index),
|
IndexedChoiceInstruction::Try(index),
|
||||||
IndexedChoiceInstruction::Trust(o)
|
IndexedChoiceInstruction::Trust(o)
|
||||||
]
|
].into()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.indexing_code
|
self.indexing_code
|
||||||
@@ -1122,15 +1122,6 @@ pub(crate) fn constant_key_alternatives(
|
|||||||
}).unwrap();
|
}).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
Literal::Usize(n) => {
|
|
||||||
constants.push(Literal::Integer(Rc::new(Integer::from(*n))));
|
|
||||||
|
|
||||||
if let Ok(n) = isize::try_from(*n) {
|
|
||||||
constants.push(Literal::Fixnum(n));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1139,16 +1130,16 @@ pub(crate) fn constant_key_alternatives(
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct StaticCodeIndices {
|
pub(crate) struct StaticCodeIndices {
|
||||||
constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>>,
|
constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
||||||
lists: VecDeque<IndexedChoiceInstruction>,
|
lists: VecDeque<IndexedChoiceInstruction>,
|
||||||
structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>>,
|
structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct DynamicCodeIndices {
|
pub(crate) struct DynamicCodeIndices {
|
||||||
constants: IndexMap<Literal, VecDeque<usize>>,
|
constants: IndexMap<Literal, VecDeque<usize>, FxBuildHasher>,
|
||||||
lists: VecDeque<usize>,
|
lists: VecDeque<usize>,
|
||||||
structures: IndexMap<(Atom, usize), VecDeque<usize>>,
|
structures: IndexMap<(Atom, usize), VecDeque<usize>, FxBuildHasher>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait Indexer {
|
pub(crate) trait Indexer {
|
||||||
@@ -1156,20 +1147,20 @@ pub(crate) trait Indexer {
|
|||||||
|
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
|
|
||||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<Self::ThirdLevelIndex>>;
|
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>;
|
||||||
fn lists(&mut self) -> &mut VecDeque<Self::ThirdLevelIndex>;
|
fn lists(&mut self) -> &mut VecDeque<Self::ThirdLevelIndex>;
|
||||||
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<Self::ThirdLevelIndex>>;
|
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>;
|
||||||
|
|
||||||
fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex;
|
fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex;
|
||||||
|
|
||||||
fn second_level_index<IndexKey: Eq + Hash>(
|
fn second_level_index<IndexKey: Eq + Hash>(
|
||||||
indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>,
|
indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>,
|
||||||
prelude: &mut VecDeque<IndexingLine>,
|
prelude: &mut VecDeque<IndexingLine>,
|
||||||
) -> IndexMap<IndexKey, IndexingCodePtr>;
|
) -> IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>;
|
||||||
|
|
||||||
fn switch_on<IndexKey: Eq + Hash>(
|
fn switch_on<IndexKey: Eq + Hash>(
|
||||||
instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
|
instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction,
|
||||||
index: &mut IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>,
|
index: &mut IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>,
|
||||||
prelude: &mut VecDeque<IndexingLine>,
|
prelude: &mut VecDeque<IndexingLine>,
|
||||||
) -> IndexingCodePtr;
|
) -> IndexingCodePtr;
|
||||||
|
|
||||||
@@ -1178,7 +1169,7 @@ pub(crate) trait Indexer {
|
|||||||
prelude: &mut VecDeque<IndexingLine>,
|
prelude: &mut VecDeque<IndexingLine>,
|
||||||
) -> IndexingCodePtr;
|
) -> IndexingCodePtr;
|
||||||
|
|
||||||
fn remove_instruction_with_offset(code: &mut SliceDeque<Self::ThirdLevelIndex>, offset: usize);
|
fn remove_instruction_with_offset(code: &mut VecDeque<Self::ThirdLevelIndex>, offset: usize);
|
||||||
|
|
||||||
fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr;
|
fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr;
|
||||||
}
|
}
|
||||||
@@ -1189,14 +1180,14 @@ impl Indexer for StaticCodeIndices {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
constants: IndexMap::new(),
|
constants: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||||
lists: VecDeque::new(),
|
lists: VecDeque::new(),
|
||||||
structures: IndexMap::new(),
|
structures: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>> {
|
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
|
||||||
&mut self.constants
|
&mut self.constants
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1206,7 +1197,7 @@ impl Indexer for StaticCodeIndices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>> {
|
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
|
||||||
&mut self.structures
|
&mut self.structures
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1219,10 +1210,10 @@ impl Indexer for StaticCodeIndices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn second_level_index<IndexKey: Eq + Hash>(
|
fn second_level_index<IndexKey: Eq + Hash>(
|
||||||
indices: IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>,
|
indices: IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
||||||
prelude: &mut VecDeque<IndexingLine>,
|
prelude: &mut VecDeque<IndexingLine>,
|
||||||
) -> IndexMap<IndexKey, IndexingCodePtr> {
|
) -> IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher> {
|
||||||
let mut index_locs = IndexMap::new();
|
let mut index_locs = IndexMap::with_hasher(FxBuildHasher::default());
|
||||||
|
|
||||||
for (key, mut code) in indices.into_iter() {
|
for (key, mut code) in indices.into_iter() {
|
||||||
if code.len() > 1 {
|
if code.len() > 1 {
|
||||||
@@ -1240,11 +1231,11 @@ impl Indexer for StaticCodeIndices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn switch_on<IndexKey: Eq + Hash>(
|
fn switch_on<IndexKey: Eq + Hash>(
|
||||||
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
|
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction,
|
||||||
index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>,
|
index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
||||||
prelude: &mut VecDeque<IndexingLine>,
|
prelude: &mut VecDeque<IndexingLine>,
|
||||||
) -> IndexingCodePtr {
|
) -> IndexingCodePtr {
|
||||||
let index = mem::replace(index, IndexMap::new());
|
let index = mem::replace(index, IndexMap::with_hasher(FxBuildHasher::default()));
|
||||||
let index = Self::second_level_index(index, prelude);
|
let index = Self::second_level_index(index, prelude);
|
||||||
|
|
||||||
if index.len() > 1 {
|
if index.len() > 1 {
|
||||||
@@ -1281,13 +1272,13 @@ impl Indexer for StaticCodeIndices {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn remove_instruction_with_offset(
|
fn remove_instruction_with_offset(
|
||||||
code: &mut SliceDeque<IndexedChoiceInstruction>,
|
code: &mut VecDeque<IndexedChoiceInstruction>,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
) {
|
) {
|
||||||
for (index, line) in code.iter().enumerate() {
|
for (index, line) in code.iter().enumerate() {
|
||||||
if offset == line.offset() {
|
if offset == line.offset() {
|
||||||
code.remove(index);
|
code.remove(index);
|
||||||
cap_choice_seq(code);
|
cap_choice_seq(code.make_contiguous());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1305,14 +1296,14 @@ impl Indexer for DynamicCodeIndices {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
constants: IndexMap::new(),
|
constants: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||||
lists: VecDeque::new(),
|
lists: VecDeque::new(),
|
||||||
structures: IndexMap::new(),
|
structures: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>> {
|
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>, FxBuildHasher> {
|
||||||
&mut self.constants
|
&mut self.constants
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1322,7 +1313,7 @@ impl Indexer for DynamicCodeIndices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<usize>> {
|
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<usize>, FxBuildHasher> {
|
||||||
&mut self.structures
|
&mut self.structures
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1332,10 +1323,10 @@ impl Indexer for DynamicCodeIndices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn second_level_index<IndexKey: Eq + Hash>(
|
fn second_level_index<IndexKey: Eq + Hash>(
|
||||||
indices: IndexMap<IndexKey, VecDeque<usize>>,
|
indices: IndexMap<IndexKey, VecDeque<usize>, FxBuildHasher>,
|
||||||
prelude: &mut VecDeque<IndexingLine>,
|
prelude: &mut VecDeque<IndexingLine>,
|
||||||
) -> IndexMap<IndexKey, IndexingCodePtr> {
|
) -> IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher> {
|
||||||
let mut index_locs = IndexMap::new();
|
let mut index_locs = IndexMap::with_hasher(FxBuildHasher::default());
|
||||||
|
|
||||||
for (key, code) in indices.into_iter() {
|
for (key, code) in indices.into_iter() {
|
||||||
if code.len() > 1 {
|
if code.len() > 1 {
|
||||||
@@ -1352,11 +1343,11 @@ impl Indexer for DynamicCodeIndices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn switch_on<IndexKey: Eq + Hash>(
|
fn switch_on<IndexKey: Eq + Hash>(
|
||||||
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
|
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction,
|
||||||
index: &mut IndexMap<IndexKey, VecDeque<usize>>,
|
index: &mut IndexMap<IndexKey, VecDeque<usize>, FxBuildHasher>,
|
||||||
prelude: &mut VecDeque<IndexingLine>,
|
prelude: &mut VecDeque<IndexingLine>,
|
||||||
) -> IndexingCodePtr {
|
) -> IndexingCodePtr {
|
||||||
let index = mem::replace(index, IndexMap::new());
|
let index = mem::replace(index, IndexMap::with_hasher(FxBuildHasher::default()));
|
||||||
let index = Self::second_level_index(index, prelude);
|
let index = Self::second_level_index(index, prelude);
|
||||||
|
|
||||||
if index.len() > 1 {
|
if index.len() > 1 {
|
||||||
@@ -1390,7 +1381,7 @@ impl Indexer for DynamicCodeIndices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn remove_instruction_with_offset(code: &mut SliceDeque<usize>, offset: usize) {
|
fn remove_instruction_with_offset(code: &mut VecDeque<usize>, offset: usize) {
|
||||||
for (index, line) in code.iter().enumerate() {
|
for (index, line) in code.iter().enumerate() {
|
||||||
if offset == *line {
|
if offset == *line {
|
||||||
code.remove(index);
|
code.remove(index);
|
||||||
@@ -1475,17 +1466,20 @@ impl<I: Indexer> CodeOffsets<I> {
|
|||||||
atom_tbl: &mut AtomTable,
|
atom_tbl: &mut AtomTable,
|
||||||
) {
|
) {
|
||||||
match optimal_arg {
|
match optimal_arg {
|
||||||
|
&Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
|
||||||
|
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
||||||
|
self.index_list(index);
|
||||||
|
}
|
||||||
|
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
|
||||||
|
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
||||||
|
self.index_list(index);
|
||||||
|
}
|
||||||
&Term::Clause(_, name, ref terms) => {
|
&Term::Clause(_, name, ref terms) => {
|
||||||
clause_index_info.opt_arg_index_key =
|
clause_index_info.opt_arg_index_key =
|
||||||
OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len());
|
OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len());
|
||||||
|
|
||||||
self.index_structure(name, terms.len(), index);
|
self.index_structure(name, terms.len(), index);
|
||||||
}
|
}
|
||||||
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
|
|
||||||
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
|
||||||
|
|
||||||
self.index_list(index);
|
|
||||||
}
|
|
||||||
&Term::Literal(_, constant) => {
|
&Term::Literal(_, constant) => {
|
||||||
let overlapping_constants = self.index_constant(atom_tbl, constant, index);
|
let overlapping_constants = self.index_constant(atom_tbl, constant, index);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::machine::machine_indices::*;
|
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
@@ -16,8 +15,9 @@ pub(crate) enum TermRef<'a> {
|
|||||||
AnonVar(Level),
|
AnonVar(Level),
|
||||||
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||||
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Term>),
|
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
||||||
PartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
|
PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
||||||
|
CompleteString(Level, &'a Cell<RegType>, Atom),
|
||||||
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,8 +28,9 @@ impl<'a> TermRef<'a> {
|
|||||||
| TermRef::Cons(lvl, ..)
|
| TermRef::Cons(lvl, ..)
|
||||||
| TermRef::Literal(lvl, ..)
|
| TermRef::Literal(lvl, ..)
|
||||||
| TermRef::Var(lvl, ..)
|
| TermRef::Var(lvl, ..)
|
||||||
| TermRef::Clause(lvl, ..) => lvl,
|
| TermRef::Clause(lvl, ..)
|
||||||
TermRef::PartialString(lvl, ..) => lvl,
|
| TermRef::CompleteString(lvl, ..)
|
||||||
|
| TermRef::PartialString(lvl, ..) => lvl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,11 +39,12 @@ impl<'a> TermRef<'a> {
|
|||||||
pub(crate) enum TermIterState<'a> {
|
pub(crate) enum TermIterState<'a> {
|
||||||
AnonVar(Level),
|
AnonVar(Level),
|
||||||
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||||
Clause(Level, usize, &'a Cell<RegType>, ClauseType, &'a Vec<Term>),
|
Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
||||||
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
InitialPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
|
InitialPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
||||||
FinalPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
|
FinalPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
||||||
|
CompleteString(Level, &'a Cell<RegType>, Atom),
|
||||||
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,15 +53,17 @@ impl<'a> TermIterState<'a> {
|
|||||||
match term {
|
match term {
|
||||||
Term::AnonVar => TermIterState::AnonVar(lvl),
|
Term::AnonVar => TermIterState::AnonVar(lvl),
|
||||||
Term::Clause(cell, name, subterms) => {
|
Term::Clause(cell, name, subterms) => {
|
||||||
let ct = ClauseType::Named(subterms.len(), *name, CodeIndex::default());
|
TermIterState::Clause(lvl, 0, cell, *name, subterms)
|
||||||
TermIterState::Clause(lvl, 0, cell, ct, subterms)
|
|
||||||
}
|
}
|
||||||
Term::Cons(cell, head, tail) => {
|
Term::Cons(cell, head, tail) => {
|
||||||
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
|
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
|
||||||
}
|
}
|
||||||
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
|
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
|
||||||
Term::PartialString(cell, string_buf, tail) => {
|
Term::PartialString(cell, string_buf, tail) => {
|
||||||
TermIterState::InitialPartialString(lvl, cell, *string_buf, tail)
|
TermIterState::InitialPartialString(lvl, cell, string_buf, tail)
|
||||||
|
}
|
||||||
|
Term::CompleteString(cell, atom) => {
|
||||||
|
TermIterState::CompleteString(lvl, cell, *atom)
|
||||||
}
|
}
|
||||||
Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()),
|
Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()),
|
||||||
}
|
}
|
||||||
@@ -89,7 +93,8 @@ impl<'a> QueryIterator<'a> {
|
|||||||
|
|
||||||
fn from_term(term: &'a Term) -> Self {
|
fn from_term(term: &'a Term) -> Self {
|
||||||
let state = match term {
|
let state = match term {
|
||||||
Term::AnonVar | Term::Cons(..) | Term::Literal(..) | Term::PartialString(..) => {
|
Term::AnonVar | Term::Cons(..) | Term::Literal(..) |
|
||||||
|
Term::PartialString(..) | Term::CompleteString(..) => {
|
||||||
return QueryIterator {
|
return QueryIterator {
|
||||||
state_stack: vec![],
|
state_stack: vec![],
|
||||||
}
|
}
|
||||||
@@ -98,7 +103,7 @@ impl<'a> QueryIterator<'a> {
|
|||||||
Level::Root,
|
Level::Root,
|
||||||
0,
|
0,
|
||||||
r,
|
r,
|
||||||
ClauseType::from(*name, terms.len()),
|
*name,
|
||||||
terms,
|
terms,
|
||||||
),
|
),
|
||||||
Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()),
|
Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()),
|
||||||
@@ -111,14 +116,14 @@ impl<'a> QueryIterator<'a> {
|
|||||||
|
|
||||||
fn new(term: &'a QueryTerm) -> Self {
|
fn new(term: &'a QueryTerm) -> Self {
|
||||||
match term {
|
match term {
|
||||||
&QueryTerm::Clause(ref cell, ClauseType::CallN(arity), ref terms, _) => {
|
&QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
|
||||||
let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN(arity), terms);
|
let state = TermIterState::Clause(Level::Root, 1, cell, atom!("$call"), terms);
|
||||||
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.name(), terms);
|
||||||
QueryIterator {
|
QueryIterator {
|
||||||
state_stack: vec![state],
|
state_stack: vec![state],
|
||||||
}
|
}
|
||||||
@@ -160,28 +165,25 @@ impl<'a> Iterator for QueryIterator<'a> {
|
|||||||
TermIterState::AnonVar(lvl) => {
|
TermIterState::AnonVar(lvl) => {
|
||||||
return Some(TermRef::AnonVar(lvl));
|
return Some(TermRef::AnonVar(lvl));
|
||||||
}
|
}
|
||||||
TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => {
|
TermIterState::Clause(lvl, child_num, cell, name, child_terms) => {
|
||||||
if child_num == child_terms.len() {
|
if child_num == child_terms.len() {
|
||||||
match ct {
|
match name {
|
||||||
ClauseType::CallN(_) => {
|
atom!("$call") if lvl == Level::Root => {
|
||||||
self.push_subterm(Level::Shallow, &child_terms[0]);
|
self.push_subterm(Level::Shallow, &child_terms[0]);
|
||||||
}
|
}
|
||||||
ClauseType::Named(..) => {
|
_ => {
|
||||||
return match lvl {
|
return match lvl {
|
||||||
Level::Root => None,
|
Level::Root => None,
|
||||||
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
|
lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
self.state_stack.push(TermIterState::Clause(
|
self.state_stack.push(TermIterState::Clause(
|
||||||
lvl,
|
lvl,
|
||||||
child_num + 1,
|
child_num + 1,
|
||||||
cell,
|
cell,
|
||||||
ct,
|
name,
|
||||||
child_terms,
|
child_terms,
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -196,13 +198,13 @@ impl<'a> Iterator for QueryIterator<'a> {
|
|||||||
}
|
}
|
||||||
TermIterState::InitialPartialString(lvl, cell, string, tail) => {
|
TermIterState::InitialPartialString(lvl, cell, string, tail) => {
|
||||||
self.state_stack.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
|
self.state_stack.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
|
||||||
|
|
||||||
if let Some(tail) = tail {
|
|
||||||
self.push_subterm(lvl.child_level(), tail);
|
self.push_subterm(lvl.child_level(), tail);
|
||||||
}
|
}
|
||||||
|
TermIterState::FinalPartialString(lvl, cell, atom, tail) => {
|
||||||
|
return Some(TermRef::PartialString(lvl, cell, atom, tail));
|
||||||
}
|
}
|
||||||
TermIterState::FinalPartialString(lvl, cell, string, tail) => {
|
TermIterState::CompleteString(lvl, cell, atom) => {
|
||||||
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
return Some(TermRef::CompleteString(lvl, cell, atom));
|
||||||
}
|
}
|
||||||
TermIterState::FinalCons(lvl, cell, head, tail) => {
|
TermIterState::FinalCons(lvl, cell, head, tail) => {
|
||||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||||
@@ -250,8 +252,7 @@ impl<'a> FactIterator<'a> {
|
|||||||
vec![TermIterState::AnonVar(Level::Root)]
|
vec![TermIterState::AnonVar(Level::Root)]
|
||||||
}
|
}
|
||||||
Term::Clause(cell, name, terms) => {
|
Term::Clause(cell, name, terms) => {
|
||||||
let ct = ClauseType::from(*name, terms.len());
|
vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)]
|
||||||
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
|
|
||||||
}
|
}
|
||||||
Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
|
Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
|
||||||
Level::Root,
|
Level::Root,
|
||||||
@@ -259,12 +260,19 @@ impl<'a> FactIterator<'a> {
|
|||||||
head.as_ref(),
|
head.as_ref(),
|
||||||
tail.as_ref(),
|
tail.as_ref(),
|
||||||
)],
|
)],
|
||||||
Term::PartialString(cell, string_buf, tail_opt) => {
|
Term::PartialString(cell, string_buf, tail) => {
|
||||||
vec![TermIterState::InitialPartialString(
|
vec![TermIterState::InitialPartialString(
|
||||||
Level::Root,
|
Level::Root,
|
||||||
cell,
|
cell,
|
||||||
*string_buf,
|
string_buf,
|
||||||
tail_opt,
|
tail,
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
Term::CompleteString(cell, atom) => {
|
||||||
|
vec![TermIterState::CompleteString(
|
||||||
|
Level::Root,
|
||||||
|
cell,
|
||||||
|
*atom,
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
Term::Literal(cell, constant) => {
|
Term::Literal(cell, constant) => {
|
||||||
@@ -291,14 +299,14 @@ impl<'a> Iterator for FactIterator<'a> {
|
|||||||
TermIterState::AnonVar(lvl) => {
|
TermIterState::AnonVar(lvl) => {
|
||||||
return Some(TermRef::AnonVar(lvl));
|
return Some(TermRef::AnonVar(lvl));
|
||||||
}
|
}
|
||||||
TermIterState::Clause(lvl, _, cell, ct, child_terms) => {
|
TermIterState::Clause(lvl, _, cell, name, child_terms) => {
|
||||||
for child_term in child_terms {
|
for child_term in child_terms {
|
||||||
self.push_subterm(lvl.child_level(), child_term);
|
self.push_subterm(lvl.child_level(), child_term);
|
||||||
}
|
}
|
||||||
|
|
||||||
match lvl {
|
match lvl {
|
||||||
Level::Root if !self.iterable_root => continue,
|
Level::Root if !self.iterable_root => continue,
|
||||||
_ => return Some(TermRef::Clause(lvl, cell, ct, child_terms)),
|
_ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||||
@@ -307,12 +315,12 @@ impl<'a> Iterator for FactIterator<'a> {
|
|||||||
|
|
||||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||||
}
|
}
|
||||||
TermIterState::InitialPartialString(lvl, cell, string_buf, tail_opt) => {
|
TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => {
|
||||||
if let Some(tail) = tail_opt {
|
|
||||||
self.push_subterm(Level::Deep, tail);
|
self.push_subterm(Level::Deep, tail);
|
||||||
|
return Some(TermRef::PartialString(lvl, cell, string_buf, tail));
|
||||||
}
|
}
|
||||||
|
TermIterState::CompleteString(lvl, cell, atom) => {
|
||||||
return Some(TermRef::PartialString(lvl, cell, string_buf, tail_opt));
|
return Some(TermRef::CompleteString(lvl, cell, atom));
|
||||||
}
|
}
|
||||||
TermIterState::Literal(lvl, cell, constant) => {
|
TermIterState::Literal(lvl, cell, constant) => {
|
||||||
return Some(TermRef::Literal(lvl, cell, constant))
|
return Some(TermRef::Literal(lvl, cell, constant))
|
||||||
@@ -407,16 +415,7 @@ impl<'a> ChunkedIterator<'a> {
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
pub(crate) fn from_term_sequence(terms: &'a [QueryTerm]) -> Self {
|
|
||||||
ChunkedIterator {
|
|
||||||
chunk_num: 0,
|
|
||||||
iter: Box::new(terms.iter().map(|t| ChunkedTerm::BodyTerm(t))),
|
|
||||||
deep_cut_encountered: false,
|
|
||||||
cut_var_in_head: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
pub(crate) fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self {
|
pub(crate) fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self {
|
||||||
let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
|
let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
|
||||||
let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)));
|
let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)));
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ mod fixtures;
|
|||||||
mod forms;
|
mod forms;
|
||||||
mod heap_iter;
|
mod heap_iter;
|
||||||
pub mod heap_print;
|
pub mod heap_print;
|
||||||
|
mod http;
|
||||||
mod indexing;
|
mod indexing;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod instructions {
|
pub mod instructions {
|
||||||
@@ -28,6 +29,7 @@ mod iterators;
|
|||||||
pub mod machine;
|
pub mod machine;
|
||||||
mod raw_block;
|
mod raw_block;
|
||||||
pub mod read;
|
pub mod read;
|
||||||
|
mod repl_helper;
|
||||||
mod targets;
|
mod targets;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -251,7 +251,7 @@ chars_base64(Cs, Bs, Options) :-
|
|||||||
'$chars_base64'(Cs, Bs, Padding, Charset)
|
'$chars_base64'(Cs, Bs, Padding, Charset)
|
||||||
; must_be(chars, Cs),
|
; must_be(chars, Cs),
|
||||||
( '$first_non_octet'(Cs, N) ->
|
( '$first_non_octet'(Cs, N) ->
|
||||||
domain_error(byte_char, N, chars_base64/3)
|
domain_error(octet_character, N, chars_base64/3)
|
||||||
; '$chars_base64'(Cs, Bs, Padding, Charset)
|
; '$chars_base64'(Cs, Bs, Padding, Charset)
|
||||||
)
|
)
|
||||||
).
|
).
|
||||||
|
|||||||
@@ -1122,6 +1122,8 @@ indomain(1).
|
|||||||
% CountAnd = 1.
|
% CountAnd = 1.
|
||||||
% ==
|
% ==
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sat_count(Sat0, N) :-
|
sat_count(Sat0, N) :-
|
||||||
catch((parse_sat(Sat0, Sat),
|
catch((parse_sat(Sat0, Sat),
|
||||||
sat_bdd(Sat, BDD),
|
sat_bdd(Sat, BDD),
|
||||||
|
|||||||
153
src/lib/clpz.pl
153
src/lib/clpz.pl
@@ -3,7 +3,7 @@
|
|||||||
Author: Markus Triska
|
Author: Markus Triska
|
||||||
E-mail: triska@metalevel.at
|
E-mail: triska@metalevel.at
|
||||||
WWW: https://www.metalevel.at
|
WWW: https://www.metalevel.at
|
||||||
Copyright (C): 2016-2021 Markus Triska
|
Copyright (C): 2016-2022 Markus Triska
|
||||||
|
|
||||||
This library provides CLP(ℤ):
|
This library provides CLP(ℤ):
|
||||||
|
|
||||||
@@ -123,6 +123,8 @@
|
|||||||
:- use_module(library(si)).
|
:- use_module(library(si)).
|
||||||
:- use_module(library(freeze)).
|
:- use_module(library(freeze)).
|
||||||
:- use_module(library(arithmetic)).
|
:- use_module(library(arithmetic)).
|
||||||
|
:- use_module(library(debug)).
|
||||||
|
:- use_module(library(format)).
|
||||||
|
|
||||||
% :- use_module(library(types)).
|
% :- use_module(library(types)).
|
||||||
|
|
||||||
@@ -194,6 +196,8 @@ type_error(Expectation, Term) :-
|
|||||||
type_error(Expectation, Term, unknown(Term)-1).
|
type_error(Expectation, Term, unknown(Term)-1).
|
||||||
|
|
||||||
|
|
||||||
|
:- meta_predicate(partition(1, ?, ?, ?)).
|
||||||
|
|
||||||
partition(Pred, Ls0, As, Bs) :-
|
partition(Pred, Ls0, As, Bs) :-
|
||||||
include(Pred, Ls0, As),
|
include(Pred, Ls0, As),
|
||||||
exclude(Pred, Ls0, Bs).
|
exclude(Pred, Ls0, Bs).
|
||||||
@@ -214,6 +218,8 @@ partition_([X|Xs], Pred, Ls0, Es0, Gs0) :-
|
|||||||
include/3 and exclude/3
|
include/3 and exclude/3
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
:- meta_predicate(include(1, ?, ?)).
|
||||||
|
|
||||||
include(Goal, Ls0, Ls) :-
|
include(Goal, Ls0, Ls) :-
|
||||||
include_(Ls0, Goal, Ls).
|
include_(Ls0, Goal, Ls).
|
||||||
|
|
||||||
@@ -226,6 +232,7 @@ include_([L|Ls0], Goal, Ls) :-
|
|||||||
include_(Ls0, Goal, Rest).
|
include_(Ls0, Goal, Rest).
|
||||||
|
|
||||||
|
|
||||||
|
:- meta_predicate(exclude(1, ?, ?)).
|
||||||
|
|
||||||
exclude(Goal, Ls0, Ls) :-
|
exclude(Goal, Ls0, Ls) :-
|
||||||
exclude_(Ls0, Goal, Ls).
|
exclude_(Ls0, Goal, Ls).
|
||||||
@@ -390,6 +397,7 @@ In total, the arithmetic constraints are:
|
|||||||
| Expr `mod` Expr | Modulo induced by floored division |
|
| Expr `mod` Expr | Modulo induced by floored division |
|
||||||
| Expr `rem` Expr | Modulo induced by truncated division |
|
| Expr `rem` Expr | Modulo induced by truncated division |
|
||||||
| abs(Expr) | Absolute value |
|
| abs(Expr) | Absolute value |
|
||||||
|
| sign(Expr) | Sign (-1, 0, 1) of Expr |
|
||||||
| Expr // Expr | Truncated integer division |
|
| Expr // Expr | Truncated integer division |
|
||||||
| Expr div Expr | Floored integer division |
|
| Expr div Expr | Floored integer division |
|
||||||
|
|
||||||
@@ -2235,8 +2243,8 @@ all_distinct(Ls) :-
|
|||||||
fd_must_be_list(Ls, all_distinct(Ls)-1),
|
fd_must_be_list(Ls, all_distinct(Ls)-1),
|
||||||
maplist(fd_variable, Ls),
|
maplist(fd_variable, Ls),
|
||||||
make_propagator(pdistinct(Ls), Prop),
|
make_propagator(pdistinct(Ls), Prop),
|
||||||
distinct_attach(Ls, Prop, []),
|
new_queue(Q0),
|
||||||
trigger_once(Prop).
|
phrase((distinct_attach(Ls, Prop, []),trigger_prop(Prop),do_queue), [Q0], _).
|
||||||
|
|
||||||
%% nvalue(?N, +Vars).
|
%% nvalue(?N, +Vars).
|
||||||
%
|
%
|
||||||
@@ -2564,6 +2572,7 @@ parse_clpz(E, R,
|
|||||||
m(A//B) => [g(B #\= 0), p(ptzdiv(A, B, R))],
|
m(A//B) => [g(B #\= 0), p(ptzdiv(A, B, R))],
|
||||||
m(A div B) => [g(?(R) #= (A - (A mod B)) // B)],
|
m(A div B) => [g(?(R) #= (A - (A mod B)) // B)],
|
||||||
m(A^B) => [p(pexp(A, B, R))],
|
m(A^B) => [p(pexp(A, B, R))],
|
||||||
|
m(sign(A)) => [g(R in -1..1), p(psign(A, R))],
|
||||||
% bitwise operations
|
% bitwise operations
|
||||||
m(\A) => [p(pfunction(\, A, R))],
|
m(\A) => [p(pfunction(\, A, R))],
|
||||||
m(msb(A)) => [p(pfunction(msb, A, R))],
|
m(msb(A)) => [p(pfunction(msb, A, R))],
|
||||||
@@ -4043,12 +4052,13 @@ trigger_props(fd_props(Gs,Bs,Os)) -->
|
|||||||
trigger_props_([]) --> [].
|
trigger_props_([]) --> [].
|
||||||
trigger_props_([P|Ps]) --> trigger_prop(P), trigger_props_(Ps).
|
trigger_props_([P|Ps]) --> trigger_prop(P), trigger_props_(Ps).
|
||||||
|
|
||||||
trigger_prop(_P) :- true. % TODO: What to do?
|
trigger_prop(P) :- trigger_once(P).
|
||||||
|
|
||||||
trigger_prop(Propagator) -->
|
trigger_prop(Propagator) -->
|
||||||
{ propagator_state(Propagator, State) },
|
{ propagator_state(Propagator, State) },
|
||||||
( { State == dead } -> []
|
( { State == dead } -> []
|
||||||
; { get_attr(State, clpz_aux, queued) } -> []
|
; { get_attr(State, clpz_aux, queued) } -> []
|
||||||
|
; { bb_get('$clpz_current_propagator', C), C == State } -> []
|
||||||
; % passive
|
; % passive
|
||||||
%{ format("triggering: ~w\n", [Propagator]) },
|
%{ format("triggering: ~w\n", [Propagator]) },
|
||||||
{ put_attr(State, clpz_aux, queued) },
|
{ put_attr(State, clpz_aux, queued) },
|
||||||
@@ -4141,12 +4151,13 @@ no_reactivation(pgcc_single(_,_)).
|
|||||||
%no_reactivation(scalar_product(_,_,_,_)).
|
%no_reactivation(scalar_product(_,_,_,_)).
|
||||||
|
|
||||||
activate_propagator(propagator(P,State)) -->
|
activate_propagator(propagator(P,State)) -->
|
||||||
|
% { portray_clause(running(P)) },
|
||||||
( State == dead -> []
|
( State == dead -> []
|
||||||
; { del_attr(State, clpz_aux) },
|
; { del_attr(State, clpz_aux) },
|
||||||
( { no_reactivation(P) } ->
|
( { no_reactivation(P) } ->
|
||||||
%b_setval('$clpz_current_propagator', State), TODO
|
{ bb_b_put('$clpz_current_propagator', State) },
|
||||||
run_propagator(P, State)
|
run_propagator(P, State),
|
||||||
%b_setval('$clpz_current_propagator', [])
|
{ bb_b_put('$clpz_current_propagator', []) }
|
||||||
; run_propagator(P, State)
|
; run_propagator(P, State)
|
||||||
)
|
)
|
||||||
).
|
).
|
||||||
@@ -4192,7 +4203,8 @@ queue_get_arg_(Queue, Which, Element) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
queue_enabled --> state(queue(_,_,_,Aux)), { \+ get_atts(Aux, +enabled(false)) }.
|
queue_enabled --> state(queue(_,_,_,Aux)), { \+ get_atts(Aux, +enabled(false)) }.
|
||||||
|
disable_queue --> state(queue(_,_,_,Aux)), { put_atts(Aux, +enabled(false)) }.
|
||||||
|
enable_queue --> state(queue(_,_,_,Aux)), { put_atts(Aux, +enabled(true)) }.
|
||||||
|
|
||||||
portray_propagator(propagator(P,_), F) :- functor(P, F, _).
|
portray_propagator(propagator(P,_), F) :- functor(P, F, _).
|
||||||
|
|
||||||
@@ -4387,14 +4399,14 @@ run_propagator(pdifferent(Left,Right,X,_), MState) -->
|
|||||||
run_propagator(pexclude(Left,Right,X), MState).
|
run_propagator(pexclude(Left,Right,X), MState).
|
||||||
|
|
||||||
run_propagator(pexclude(Left,Right,X), _) -->
|
run_propagator(pexclude(Left,Right,X), _) -->
|
||||||
{ ( ground(X) ->
|
( ground(X) ->
|
||||||
disable_queue,
|
disable_queue,
|
||||||
exclude_fire(Left, Right, X),
|
exclude_fire(Left, Right, X),
|
||||||
enable_queue
|
enable_queue
|
||||||
; true
|
; true
|
||||||
) }.
|
).
|
||||||
|
|
||||||
run_propagator(pdistinct(Ls), _MState) --> { distinct(Ls) }.
|
run_propagator(pdistinct(Ls), _MState) --> distinct(Ls).
|
||||||
|
|
||||||
run_propagator(pnvalue(N, Vars), _MState) --> { propagate_nvalue(N, Vars) }.
|
run_propagator(pnvalue(N, Vars), _MState) --> { propagate_nvalue(N, Vars) }.
|
||||||
|
|
||||||
@@ -4428,8 +4440,8 @@ run_propagator(pgcc(Vs, _, Pairs), _) --> { gcc_global(Vs, Pairs) }.
|
|||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
run_propagator(pcircuit(Vs), _MState) -->
|
run_propagator(pcircuit(Vs), _MState) -->
|
||||||
{ distinct(Vs),
|
distinct(Vs),
|
||||||
propagate_circuit(Vs) }.
|
{ propagate_circuit(Vs) }.
|
||||||
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
@@ -5134,7 +5146,6 @@ run_propagator(pmodz(X,Y,Z), MState) -->
|
|||||||
domain_remove_smaller_than(ZD3, ZMin, ZD5) },
|
domain_remove_smaller_than(ZD3, ZMin, ZD5) },
|
||||||
fd_put(Z, ZD5, ZPs)
|
fd_put(Z, ZD5, ZPs)
|
||||||
% queue_goal(Z in ZMin..ZMax)
|
% queue_goal(Z in ZMin..ZMax)
|
||||||
%/* This doesn't work very well.
|
|
||||||
; { fd_get(Y, _, _, n(YU), _), YU > 0 } ->
|
; { fd_get(Y, _, _, n(YU), _), YU > 0 } ->
|
||||||
{ fd_get(Z, ZD1, ZPs),
|
{ fd_get(Z, ZD1, ZPs),
|
||||||
ZMax is YU - 1,
|
ZMax is YU - 1,
|
||||||
@@ -5147,7 +5158,6 @@ run_propagator(pmodz(X,Y,Z), MState) -->
|
|||||||
domain_remove_smaller_than(ZD1, ZMin, ZD3) },
|
domain_remove_smaller_than(ZD1, ZMin, ZD3) },
|
||||||
fd_put(Z, ZD3, ZPs)
|
fd_put(Z, ZD3, ZPs)
|
||||||
% queue_goal(Z #> YL)
|
% queue_goal(Z #> YL)
|
||||||
% * /
|
|
||||||
; true
|
; true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -5484,6 +5494,21 @@ run_propagator(pexp(X,Y,Z), MState) -->
|
|||||||
; true
|
; true
|
||||||
).
|
).
|
||||||
|
|
||||||
|
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%% % Y = sign(X)
|
||||||
|
|
||||||
|
run_propagator(psign(X,Y), MState) -->
|
||||||
|
( nonvar(X) -> kill(MState), queue_goal(Y is sign(X))
|
||||||
|
; Y == -1 -> kill(MState), queue_goal(X #< 0)
|
||||||
|
; Y == 0 -> kill(MState), queue_goal(X = 0)
|
||||||
|
; Y == 1 -> kill(MState), queue_goal(X #> 0)
|
||||||
|
; { fd_get(X, _, XL, XU, _) },
|
||||||
|
( { XL = n(L), L > 0 } -> kill(MState), queue_goal(Y = 1)
|
||||||
|
; { XU = n(U), U < 0 } -> kill(MState), queue_goal(Y = -1)
|
||||||
|
; true
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% % Y = popcount(X)
|
%% % Y = popcount(X)
|
||||||
|
|
||||||
@@ -5913,12 +5938,12 @@ max_factor(L1, U1, L2, U2, Max) :-
|
|||||||
CSPs", AAAI-94, Seattle, WA, USA, pp 362--367, 1994
|
CSPs", AAAI-94, Seattle, WA, USA, pp 362--367, 1994
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
distinct_attach([], _, _).
|
distinct_attach([], _, _) --> [].
|
||||||
distinct_attach([X|Xs], Prop, Right) :-
|
distinct_attach([X|Xs], Prop, Right) -->
|
||||||
( var(X) ->
|
( var(X) ->
|
||||||
init_propagator(X, Prop),
|
{ init_propagator(X, Prop),
|
||||||
make_propagator(pexclude(Xs,Right,X), P1),
|
make_propagator(pexclude(Xs,Right,X), P1),
|
||||||
init_propagator(X, P1),
|
init_propagator(X, P1) },
|
||||||
trigger_prop(P1)
|
trigger_prop(P1)
|
||||||
; exclude_fire(Xs, Right, X)
|
; exclude_fire(Xs, Right, X)
|
||||||
),
|
),
|
||||||
@@ -6087,59 +6112,26 @@ put_free(F) :- put_attr(F, free, true).
|
|||||||
|
|
||||||
free_node(F) :- get_attr(F, free, true).
|
free_node(F) :- get_attr(F, free, true).
|
||||||
|
|
||||||
del_vars_attr(Vars, Attr) :- maplist(del_attr(Attr), Vars).
|
|
||||||
|
|
||||||
%del_attr_(Attr, Var) :- del_attr(Var, Attr).
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
This needs to be spelt out.
|
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
|
|
||||||
% del_attr_(edges, Var) :- del_attr(Var, edges).
|
|
||||||
% del_attr_(parent, Var) :- del_attr(Var, parent).
|
|
||||||
% del_attr_(g0_edges, Var) :- del_attr(Var, g0_edges).
|
|
||||||
% del_attr_(index, Var) :- del_attr(Var, index).
|
|
||||||
% del_attr_(visited, Var) :- del_attr(Var, visited).
|
|
||||||
|
|
||||||
del_all_attrs(Var) :-
|
|
||||||
( var(Var) ->
|
|
||||||
Atts = [clpz,
|
|
||||||
clpz_aux,
|
|
||||||
clpz_relation,
|
|
||||||
edges,
|
|
||||||
flow,
|
|
||||||
parent,
|
|
||||||
free,
|
|
||||||
g0_edges,
|
|
||||||
used,
|
|
||||||
lowlink,
|
|
||||||
value,
|
|
||||||
visited,
|
|
||||||
index,
|
|
||||||
in_stack,
|
|
||||||
clpz_gcc_vs,
|
|
||||||
clpz_gcc_num,
|
|
||||||
clpz_gcc_occurred],
|
|
||||||
maplist(remove_attr(Var), Atts)
|
|
||||||
; true
|
|
||||||
).
|
|
||||||
|
|
||||||
remove_attr(Var, Attr) :-
|
|
||||||
functor(Term, Attr, 1),
|
|
||||||
put_atts(Var, -Term).
|
|
||||||
|
|
||||||
:- meta_predicate with_local_attributes(?, 0, ?).
|
:- meta_predicate with_local_attributes(?, 0, ?).
|
||||||
|
|
||||||
|
:- dynamic(nat_copy/1).
|
||||||
|
|
||||||
with_local_attributes(Vars, Goal, Result) :-
|
with_local_attributes(Vars, Goal, Result) :-
|
||||||
catch((Goal,
|
catch((Goal,
|
||||||
maplist(del_all_attrs, Vars),
|
% Create a copy where all attributes are removed. Only
|
||||||
% reset all attributes, only the result matters
|
% the result and its relation to Vars matters. We throw
|
||||||
throw(local_attributes(Result,Vars))),
|
% an exception to undo all modifications to attributes
|
||||||
local_attributes(Result,Vars),
|
% we made during propagation, and unify the variables
|
||||||
|
% in the thrown copy with Vars in order to get the
|
||||||
|
% intended variables in Result.
|
||||||
|
asserta(nat_copy(Vars-Result)),
|
||||||
|
retract(nat_copy(Copy)),
|
||||||
|
throw(local_attributes(Copy))),
|
||||||
|
local_attributes(Vars-Result),
|
||||||
true).
|
true).
|
||||||
|
|
||||||
distinct(Vars) :-
|
distinct(Vars) -->
|
||||||
with_local_attributes(Vars,
|
{ with_local_attributes(Vars,
|
||||||
( difference_arcs(Vars, FreeLeft, FreeRight0),
|
( difference_arcs(Vars, FreeLeft, FreeRight0),
|
||||||
length(FreeLeft, LFL),
|
length(FreeLeft, LFL),
|
||||||
length(FreeRight0, LFR),
|
length(FreeRight0, LFR),
|
||||||
@@ -6150,11 +6142,16 @@ distinct(Vars) :-
|
|||||||
maplist(g_g0, FreeLeft),
|
maplist(g_g0, FreeLeft),
|
||||||
scc(FreeLeft, g0_successors),
|
scc(FreeLeft, g0_successors),
|
||||||
maplist(dfs_used, FreeRight),
|
maplist(dfs_used, FreeRight),
|
||||||
phrase(distinct_goals(FreeLeft), Gs)), Gs),
|
phrase(distinct_goals(FreeLeft), Gs)), Gs) },
|
||||||
disable_queue,
|
disable_queue,
|
||||||
maplist(call, Gs),
|
neq_nums(Gs),
|
||||||
enable_queue.
|
enable_queue.
|
||||||
|
|
||||||
|
neq_nums([]) --> [].
|
||||||
|
neq_nums([neq_num(V,N)|VNs]) -->
|
||||||
|
% { portray_clause(neq_num(V, N)) },
|
||||||
|
neq_num(V, N), neq_nums(VNs).
|
||||||
|
|
||||||
distinct_goals([]) --> [].
|
distinct_goals([]) --> [].
|
||||||
distinct_goals([V|Vs]) -->
|
distinct_goals([V|Vs]) -->
|
||||||
{ get_attr(V, edges, Es) },
|
{ get_attr(V, edges, Es) },
|
||||||
@@ -6169,7 +6166,7 @@ distinct_goals_([flow_to(F,To)|Es], V) -->
|
|||||||
get_attr(To, lowlink, L2),
|
get_attr(To, lowlink, L2),
|
||||||
L1 =\= L2 } ->
|
L1 =\= L2 } ->
|
||||||
{ get_attr(To, value, N) },
|
{ get_attr(To, value, N) },
|
||||||
[clpz:neq_num(V, N)]
|
[neq_num(V, N)]
|
||||||
; []
|
; []
|
||||||
),
|
),
|
||||||
distinct_goals_(Es, V).
|
distinct_goals_(Es, V).
|
||||||
@@ -6361,6 +6358,10 @@ exclude_fire(Left, Right, E) :-
|
|||||||
all_neq(Left, E),
|
all_neq(Left, E),
|
||||||
all_neq(Right, E).
|
all_neq(Right, E).
|
||||||
|
|
||||||
|
exclude_fire(Left, Right, E) -->
|
||||||
|
all_neq(Left, E),
|
||||||
|
all_neq(Right, E).
|
||||||
|
|
||||||
list_contains([X|Xs], Y) :-
|
list_contains([X|Xs], Y) :-
|
||||||
( X == Y -> true
|
( X == Y -> true
|
||||||
; list_contains(Xs, Y)
|
; list_contains(Xs, Y)
|
||||||
@@ -6922,6 +6923,11 @@ vs_key_min_others([V|Vs], Key, Min0, Min, Others) :-
|
|||||||
)
|
)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
all_neq([], _) --> [].
|
||||||
|
all_neq([X|Xs], C) -->
|
||||||
|
neq_num(X, C),
|
||||||
|
all_neq(Xs, C).
|
||||||
|
|
||||||
all_neq([], _).
|
all_neq([], _).
|
||||||
all_neq([X|Xs], C) :-
|
all_neq([X|Xs], C) :-
|
||||||
neq_num(X, C),
|
neq_num(X, C),
|
||||||
@@ -6953,8 +6959,8 @@ circuit(Vs) :-
|
|||||||
( L =:= 1 -> true
|
( L =:= 1 -> true
|
||||||
; neq_index(Vs, 1),
|
; neq_index(Vs, 1),
|
||||||
make_propagator(pcircuit(Vs), Prop),
|
make_propagator(pcircuit(Vs), Prop),
|
||||||
distinct_attach(Vs, Prop, []),
|
new_queue(Q0),
|
||||||
trigger_once(Prop)
|
phrase((distinct_attach(Vs, Prop, []),trigger_prop(Prop),do_queue), [Q0], _)
|
||||||
).
|
).
|
||||||
|
|
||||||
neq_index([], _).
|
neq_index([], _).
|
||||||
@@ -7134,10 +7140,6 @@ contribution_at(T, Task, Offset-Bs, Contribution) :-
|
|||||||
?(Contribution) #= B*C
|
?(Contribution) #= B*C
|
||||||
).
|
).
|
||||||
|
|
||||||
nth1(I, Es, E) :-
|
|
||||||
I0 is I-1,
|
|
||||||
nth0(I0, Es, E).
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
%% disjoint2(+Rectangles)
|
%% disjoint2(+Rectangles)
|
||||||
@@ -7696,6 +7698,7 @@ attribute_goal_(ptzdiv(X,Y,Z)) --> [?(X) // ?(Y) #= ?(Z)].
|
|||||||
attribute_goal_(pdiv(X,Y,Z)) --> [?(X) div ?(Y) #= ?(Z)].
|
attribute_goal_(pdiv(X,Y,Z)) --> [?(X) div ?(Y) #= ?(Z)].
|
||||||
attribute_goal_(prdiv(X,Y,Z)) --> [?(X) / ?(Y) #= ?(Z)].
|
attribute_goal_(prdiv(X,Y,Z)) --> [?(X) / ?(Y) #= ?(Z)].
|
||||||
attribute_goal_(pexp(X,Y,Z)) --> [?(X) ^ ?(Y) #= ?(Z)].
|
attribute_goal_(pexp(X,Y,Z)) --> [?(X) ^ ?(Y) #= ?(Z)].
|
||||||
|
attribute_goal_(psign(X,Y)) --> [?(Y) #= sign(?(X))].
|
||||||
attribute_goal_(pabs(X,Y)) --> [?(Y) #= abs(?(X))].
|
attribute_goal_(pabs(X,Y)) --> [?(Y) #= abs(?(X))].
|
||||||
attribute_goal_(pmod(X,M,K)) --> [?(X) mod ?(M) #= ?(K)].
|
attribute_goal_(pmod(X,M,K)) --> [?(X) mod ?(M) #= ?(K)].
|
||||||
attribute_goal_(prem(X,Y,Z)) --> [?(X) rem ?(Y) #= ?(Z)].
|
attribute_goal_(prem(X,Y,Z)) --> [?(X) rem ?(Y) #= ?(Z)].
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
In Scryer Prolog, lists of characters are very efficiently represented,
|
In Scryer Prolog, lists of characters are very efficiently represented,
|
||||||
and strings have the advantage that the atom table remains unmodified.
|
and strings have the advantage that the atom table remains unmodified.
|
||||||
|
|
||||||
Especially for cryptographic applications, it as an advantage that
|
Especially for cryptographic applications, it is an advantage that
|
||||||
using strings leaves little trace of what was processed in the system.
|
using strings leaves little trace of what was processed in the system.
|
||||||
|
|
||||||
For predicates that accept an encoding/1 option to specify the encoding
|
For predicates that accept an encoding/1 option to specify the encoding
|
||||||
@@ -65,8 +65,7 @@
|
|||||||
|
|
||||||
hex_bytes(Hs, Bytes) :-
|
hex_bytes(Hs, Bytes) :-
|
||||||
( ground(Hs) ->
|
( ground(Hs) ->
|
||||||
must_be(list, Hs),
|
must_be(chars, Hs),
|
||||||
maplist(must_be(atom), Hs),
|
|
||||||
( phrase(hex_bytes(Hs), Bytes) ->
|
( phrase(hex_bytes(Hs), Bytes) ->
|
||||||
true
|
true
|
||||||
; domain_error(hex_encoding, Hs, hex_bytes/2)
|
; domain_error(hex_encoding, Hs, hex_bytes/2)
|
||||||
@@ -104,10 +103,10 @@ must_be_bytes(Bytes, Context) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
must_be_byte_chars(Chars, Context) :-
|
must_be_octet_chars(Chars, Context) :-
|
||||||
must_be(chars, Chars),
|
must_be(chars, Chars),
|
||||||
( '$first_non_octet'(Chars, F) ->
|
( '$first_non_octet'(Chars, F) ->
|
||||||
domain_error(byte_char, F, Context)
|
domain_error(octet_character, F, Context)
|
||||||
; true
|
; true
|
||||||
).
|
).
|
||||||
|
|
||||||
@@ -611,7 +610,7 @@ encoding_chars(octet, Bs, Cs) :-
|
|||||||
maplist(char_code, Cs, Bs)
|
maplist(char_code, Cs, Bs)
|
||||||
; Bs = Cs
|
; Bs = Cs
|
||||||
),
|
),
|
||||||
must_be_byte_chars(Cs, crypto_encoding).
|
must_be_octet_chars(Cs, crypto_encoding).
|
||||||
encoding_chars(utf8, Cs, Cs) :-
|
encoding_chars(utf8, Cs, Cs) :-
|
||||||
must_be(chars, Cs).
|
must_be(chars, Cs).
|
||||||
|
|
||||||
@@ -652,17 +651,17 @@ ed25519_new_keypair(Pair) :-
|
|||||||
'$ed25519_new_keypair'(Pair).
|
'$ed25519_new_keypair'(Pair).
|
||||||
|
|
||||||
ed25519_keypair_public_key(Pair, PublicKey) :-
|
ed25519_keypair_public_key(Pair, PublicKey) :-
|
||||||
must_be_byte_chars(Pair, ed25519_keypair_public_key),
|
must_be_octet_chars(Pair, ed25519_keypair_public_key),
|
||||||
'$ed25519_keypair_public_key'(Pair, PublicKey).
|
'$ed25519_keypair_public_key'(Pair, PublicKey).
|
||||||
|
|
||||||
ed25519_sign(Key, Data0, Signature, Options) :-
|
ed25519_sign(Key, Data0, Signature, Options) :-
|
||||||
must_be_byte_chars(Key, ed25519_sign),
|
must_be_octet_chars(Key, ed25519_sign),
|
||||||
options_data_chars(Options, Data0, Data, Encoding),
|
options_data_chars(Options, Data0, Data, Encoding),
|
||||||
'$ed25519_sign'(Key, Data, Encoding, Signature0),
|
'$ed25519_sign'(Key, Data, Encoding, Signature0),
|
||||||
hex_bytes(Signature, Signature0).
|
hex_bytes(Signature, Signature0).
|
||||||
|
|
||||||
ed25519_verify(Key, Data0, Signature0, Options) :-
|
ed25519_verify(Key, Data0, Signature0, Options) :-
|
||||||
must_be_byte_chars(Key, ed25519_verify),
|
must_be_octet_chars(Key, ed25519_verify),
|
||||||
options_data_chars(Options, Data0, Data, Encoding),
|
options_data_chars(Options, Data0, Data, Encoding),
|
||||||
hex_bytes(Signature0, Signature),
|
hex_bytes(Signature0, Signature),
|
||||||
'$ed25519_verify'(Key, Data, Encoding, Signature).
|
'$ed25519_verify'(Key, Data, Encoding, Signature).
|
||||||
@@ -714,12 +713,17 @@ curve25519_scalar_mult(Scalar, Point, Result) :-
|
|||||||
'$curve25519_scalar_mult'(ScalarBytes, PointBytes, Result).
|
'$curve25519_scalar_mult'(ScalarBytes, PointBytes, Result).
|
||||||
|
|
||||||
bytes_integer(Bs, N) :-
|
bytes_integer(Bs, N) :-
|
||||||
foldl(pow, Bs, 0-0, N-_).
|
foldl(pow, Bs, t(0,0,N), t(N,_,_)).
|
||||||
|
|
||||||
pow(B, N0-I0, N-I) :-
|
pow(B, t(N0,P0,I0), t(N,P,I)) :-
|
||||||
|
( integer(I0) ->
|
||||||
|
B #= I0 mod 256,
|
||||||
|
I #= I0 >> 8
|
||||||
|
; true
|
||||||
|
),
|
||||||
B in 0..255,
|
B in 0..255,
|
||||||
N #= N0 + B*256^I0,
|
N #= N0 + B*256^P0,
|
||||||
I #= I0 + 1.
|
P #= P0 + 1.
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Operations on Elliptic Curves
|
Operations on Elliptic Curves
|
||||||
@@ -762,11 +766,15 @@ crypto_curve_scalar_mult(Curve, Scalar, point(X,Y), point(RX, RY)) :-
|
|||||||
curve_name(Curve, Name),
|
curve_name(Curve, Name),
|
||||||
curve_field_length(Curve, L0),
|
curve_field_length(Curve, L0),
|
||||||
L #= 2*L0, % for hex encoding
|
L #= 2*L0, % for hex encoding
|
||||||
phrase(format_("04~|~`0t~16r~*+~`0t~16r~*+", [X,L,Y,L]), Hex),
|
phrase(format_("04~|~`0t~16r~*+~`0t~16r~*+", [X,L,Y,L]), PointHex),
|
||||||
hex_bytes(Hex, Bytes),
|
hex_bytes(PointHex, PointBytes),
|
||||||
'$crypto_curve_scalar_mult'(Name, Scalar, Bytes, SX, SY),
|
once(bytes_integer(ScalarBytes, Scalar)),
|
||||||
number_chars(RX, SX),
|
'$crypto_curve_scalar_mult'(Name, ScalarBytes, PointBytes, [_|Us]),
|
||||||
number_chars(RY, SY).
|
maplist(char_code, Us, Bs),
|
||||||
|
length(XBs, 32),
|
||||||
|
append(XBs, YBs, Bs),
|
||||||
|
maplist(reverse, [XBs,YBs], RBs),
|
||||||
|
maplist(bytes_integer, RBs, [RX,RY]).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
?- crypto_name_curve(secp256k1, Curve),
|
?- crypto_name_curve(secp256k1, Curve),
|
||||||
@@ -818,16 +826,6 @@ fitting_exponent(N, E0, E) :-
|
|||||||
fitting_exponent(N, E1, E)
|
fitting_exponent(N, E1, E)
|
||||||
).
|
).
|
||||||
|
|
||||||
crypto_name_curve(secp112r1,
|
|
||||||
curve(secp112r1,
|
|
||||||
0x00db7c2abf62e35e668076bead208b,
|
|
||||||
0x00db7c2abf62e35e668076bead2088,
|
|
||||||
0x659ef8ba043916eede8911702b22,
|
|
||||||
point(0x09487239995a5ee76b55f9c2f098,
|
|
||||||
0xa89ce5af8724c0a23e0e0ff77500),
|
|
||||||
0x00db7c2abf62e35e7628dfac6561c5,
|
|
||||||
14,
|
|
||||||
1)).
|
|
||||||
crypto_name_curve(secp256k1,
|
crypto_name_curve(secp256k1,
|
||||||
curve(secp256k1,
|
curve(secp256k1,
|
||||||
0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
|
0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
|
||||||
|
|||||||
122
src/lib/dcgs.pl
122
src/lib/dcgs.pl
@@ -8,19 +8,10 @@
|
|||||||
]).
|
]).
|
||||||
|
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
|
:- use_module(library(iso_ext)).
|
||||||
:- use_module(library(lists), [append/3, member/2]).
|
:- use_module(library(lists), [append/3, member/2]).
|
||||||
:- use_module(library(loader), [strip_module/3]).
|
:- use_module(library(loader), [strip_module/3]).
|
||||||
|
|
||||||
load_context(GRBody, Module, GRBody0) :-
|
|
||||||
strip_module(GRBody, Module, GRBody0),
|
|
||||||
( nonvar(Module) ->
|
|
||||||
true
|
|
||||||
; prolog_load_context(module, Module) ->
|
|
||||||
true
|
|
||||||
; true
|
|
||||||
).
|
|
||||||
|
|
||||||
|
|
||||||
:- meta_predicate phrase(2, ?).
|
:- meta_predicate phrase(2, ?).
|
||||||
|
|
||||||
:- meta_predicate phrase(2, ?, ?).
|
:- meta_predicate phrase(2, ?, ?).
|
||||||
@@ -29,12 +20,14 @@ phrase(GRBody, S0) :-
|
|||||||
phrase(GRBody, S0, []).
|
phrase(GRBody, S0, []).
|
||||||
|
|
||||||
phrase(GRBody, S0, S) :-
|
phrase(GRBody, S0, S) :-
|
||||||
load_context(GRBody, Module, GRBody0),
|
strip_module(GRBody, M, GRBody1),
|
||||||
( var(GRBody0) ->
|
( var(GRBody) ->
|
||||||
instantiation_error(phrase/3)
|
instantiation_error(phrase/3)
|
||||||
; dcg_body(GRBody0, S0, S, GRBody1, Module) ->
|
; nonvar(GRBody1),
|
||||||
call(GRBody1)
|
dcg_constr(GRBody1),
|
||||||
; type_error(callable, GRBody0, phrase/3)
|
dcg_body(GRBody1, S0, S, GRBody2) ->
|
||||||
|
call(M:GRBody2)
|
||||||
|
; call(M:GRBody1, S0, S)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
@@ -47,25 +40,25 @@ module_call_qualified(M, Call, Call1) :-
|
|||||||
% The same version of the below two dcg_rule clauses, but with module scoping.
|
% The same version of the below two dcg_rule clauses, but with module scoping.
|
||||||
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
|
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
|
||||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||||
dcg_body(GRBody, S0, S1, Goal1, _),
|
dcg_body(GRBody, S0, S1, Goal1),
|
||||||
dcg_terminals(Terminals, S, S1, Goal2),
|
dcg_terminals(Terminals, S, S1, Goal2),
|
||||||
Body = ( Goal1, Goal2 ).
|
Body = ( Goal1, Goal2 ).
|
||||||
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
|
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
|
||||||
NonTerminal \= ( _, _ ),
|
NonTerminal \= ( _, _ ),
|
||||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||||
dcg_body(GRBody, S0, S, Body, _).
|
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 )) :-
|
||||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||||
dcg_body(GRBody, S0, S1, Goal1, _),
|
dcg_body(GRBody, S0, S1, Goal1),
|
||||||
dcg_terminals(Terminals, S, S1, Goal2),
|
dcg_terminals(Terminals, S, S1, Goal2),
|
||||||
Body = ( Goal1, Goal2 ).
|
Body = ( Goal1, Goal2 ).
|
||||||
dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :-
|
dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :-
|
||||||
NonTerminal \= ( _, _ ),
|
NonTerminal \= ( _, _ ),
|
||||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||||
dcg_body(GRBody, S0, S, Body, _).
|
dcg_body(GRBody, S0, S, Body).
|
||||||
|
|
||||||
dcg_non_terminal(NonTerminal, S0, S, Goal) :-
|
dcg_non_terminal(NonTerminal, S0, S, Goal) :-
|
||||||
NonTerminal =.. NonTerminalUniv,
|
NonTerminal =.. NonTerminalUniv,
|
||||||
@@ -75,21 +68,21 @@ dcg_non_terminal(NonTerminal, S0, S, Goal) :-
|
|||||||
dcg_terminals(Terminals, S0, S, S0 = List) :-
|
dcg_terminals(Terminals, S0, S, S0 = List) :-
|
||||||
append(Terminals, S, List).
|
append(Terminals, S, List).
|
||||||
|
|
||||||
dcg_body(Var, S0, S, Body, M) :-
|
dcg_body(Var, S0, S, Body) :-
|
||||||
var(Var),
|
var(Var),
|
||||||
module_call_qualified(M, Var, Var1),
|
Body = phrase(Var, S0, S).
|
||||||
Body = phrase(Var1, S0, S).
|
dcg_body(GRBody, S0, S, Body) :-
|
||||||
dcg_body(GRBody, S0, S, Body, M) :-
|
|
||||||
nonvar(GRBody),
|
nonvar(GRBody),
|
||||||
dcg_constr(GRBody),
|
dcg_constr(GRBody),
|
||||||
dcg_cbody(GRBody, S0, S, Body, M).
|
dcg_cbody(GRBody, S0, S, Body).
|
||||||
dcg_body(NonTerminal, S0, S, Goal1, M) :-
|
dcg_body(NonTerminal, S0, S, Goal1) :-
|
||||||
nonvar(NonTerminal),
|
nonvar(NonTerminal),
|
||||||
\+ dcg_constr(NonTerminal),
|
\+ dcg_constr(NonTerminal),
|
||||||
NonTerminal \= ( _ -> _ ),
|
NonTerminal \= ( _ -> _ ),
|
||||||
NonTerminal \= ( \+ _ ),
|
NonTerminal \= ( \+ _ ),
|
||||||
module_call_qualified(M, Goal, Goal1),
|
loader:strip_module(NonTerminal, M, NonTerminal0),
|
||||||
dcg_non_terminal(NonTerminal, S0, S, Goal).
|
dcg_non_terminal(NonTerminal0, S0, S, Goal0),
|
||||||
|
module_call_qualified(M, Goal0, Goal1).
|
||||||
|
|
||||||
% The following constructs in a grammar rule body
|
% The following constructs in a grammar rule body
|
||||||
% are defined in the corresponding subclauses.
|
% are defined in the corresponding subclauses.
|
||||||
@@ -107,42 +100,44 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
|
|||||||
|
|
||||||
% The principal functor of the first argument indicates
|
% The principal functor of the first argument indicates
|
||||||
% the construct to be expanded.
|
% the construct to be expanded.
|
||||||
dcg_cbody([], S0, S, S0 = S, _M).
|
dcg_cbody([], S0, S, S0 = S).
|
||||||
dcg_cbody([T|Ts], S0, S, Goal, _M) :-
|
dcg_cbody([T|Ts], S0, S, Goal) :-
|
||||||
must_be(list, [T|Ts]),
|
must_be(list, [T|Ts]),
|
||||||
dcg_terminals([T|Ts], S0, S, Goal).
|
dcg_terminals([T|Ts], S0, S, Goal).
|
||||||
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second ), M) :-
|
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
|
||||||
dcg_body(GRFirst, S0, S1, First, M),
|
dcg_body(GRFirst, S0, S1, First),
|
||||||
dcg_body(GRSecond, S1, S, Second, M).
|
dcg_body(GRSecond, S1, S, Second).
|
||||||
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or ), M) :-
|
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or )) :-
|
||||||
\+ subsumes_term(( _ -> _ ), GREither),
|
\+ subsumes_term(( _ -> _ ), GREither),
|
||||||
dcg_body(GREither, S0, S, Either, M),
|
dcg_body(GREither, S0, S, Either),
|
||||||
dcg_body(GROr, S0, S, Or, M).
|
dcg_body(GROr, S0, S, Or).
|
||||||
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else ), M) :-
|
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
|
||||||
subsumes_term(( _GRIf -> _GRThen ), GRCond),
|
subsumes_term(( _GRIf -> _GRThen ), GRCond),
|
||||||
dcg_cbody(GRCond, S0, S, Cond, M),
|
dcg_cbody(GRCond, S0, S, Cond),
|
||||||
dcg_body(GRElse, S0, S, Else, M).
|
dcg_body(GRElse, S0, S, Else).
|
||||||
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or ), M) :-
|
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
|
||||||
dcg_body(GREither, S0, S, Either, M),
|
dcg_body(GREither, S0, S, Either),
|
||||||
dcg_body(GROr, S0, S, Or, M).
|
dcg_body(GROr, S0, S, Or).
|
||||||
dcg_cbody({Goal}, S0, S, ( Goal1, S0 = S ), M) :-
|
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
|
||||||
module_call_qualified(M, Goal, Goal1).
|
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
|
||||||
dcg_cbody(call(Cont), S0, S, call(Cont1, S0, S), M) :-
|
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
|
||||||
module_call_qualified(M, Cont, Cont1).
|
dcg_cbody(!, S0, S, ( !, S0 = S )).
|
||||||
dcg_cbody(phrase(Body), S0, S, phrase(Body1, S0, S), M) :-
|
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
|
||||||
module_call_qualified(M, Body, Body1).
|
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
|
||||||
dcg_cbody(!, S0, S, ( !, S0 = S ), _M).
|
dcg_body(GRIf, S0, S1, If),
|
||||||
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody1,S0,_), S0 = S ), M) :-
|
dcg_body(GRThen, S1, S, Then).
|
||||||
module_call_qualified(M, GRBody, GRBody1).
|
|
||||||
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then ), M) :-
|
|
||||||
dcg_body(GRIf, S0, S1, If, M),
|
|
||||||
dcg_body(GRThen, S1, S, Then, M).
|
|
||||||
|
|
||||||
user:term_expansion(Term0, Term) :-
|
user:term_expansion(Term0, Term) :-
|
||||||
nonvar(Term0),
|
nonvar(Term0),
|
||||||
dcg_rule(Term0, Term).
|
dcg_rule(Term0, Term).
|
||||||
|
|
||||||
% Describes a sequence
|
% Describes a sequence
|
||||||
|
seq(Xs, Cs0,Cs) :-
|
||||||
|
var(Xs),
|
||||||
|
Cs0 == [],
|
||||||
|
!,
|
||||||
|
Xs = [],
|
||||||
|
Cs0 = Cs.
|
||||||
seq([]) --> [].
|
seq([]) --> [].
|
||||||
seq([E|Es]) --> [E], seq(Es).
|
seq([E|Es]) --> [E], seq(Es).
|
||||||
|
|
||||||
@@ -151,14 +146,23 @@ seqq([]) --> [].
|
|||||||
seqq([Es|Ess]) --> seq(Es), seqq(Ess).
|
seqq([Es|Ess]) --> seq(Es), seqq(Ess).
|
||||||
|
|
||||||
% Describes an arbitrary number of elements
|
% Describes an arbitrary number of elements
|
||||||
|
...(Cs0,Cs) :-
|
||||||
|
Cs0 == [],
|
||||||
|
!,
|
||||||
|
Cs0 = Cs.
|
||||||
... --> [] | [_], ... .
|
... --> [] | [_], ... .
|
||||||
|
|
||||||
user:goal_expansion(phrase(GRBody, S, S0), GRBody1) :-
|
error_goal(error(E, must_be/2), error(E, must_be/2)).
|
||||||
load_context(GRBody, M, GRBody0),
|
error_goal(error(E, (=..)/2), error(E, (=..)/2)).
|
||||||
|
error_goal(E, _) :- throw(E).
|
||||||
|
|
||||||
|
user:goal_expansion(phrase(GRBody, S, S0), GRBody2) :-
|
||||||
|
loader:strip_module(GRBody, M, GRBody0),
|
||||||
nonvar(GRBody0),
|
nonvar(GRBody0),
|
||||||
catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1, M),
|
catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1),
|
||||||
error(E, must_be/2),
|
E,
|
||||||
( GRBody1 = throw(error(E, must_be/2)) )
|
dcgs:error_goal(E, GRBody1)
|
||||||
).
|
),
|
||||||
|
module_call_qualified(M, GRBody1, GRBody2).
|
||||||
|
|
||||||
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).
|
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Written September 2018 by Markus Triska (triska@metalevel.at)
|
Written 2018-2022 by Markus Triska (triska@metalevel.at)
|
||||||
I place this code in the public domain. Use it in any way you want.
|
I place this code in the public domain. Use it in any way you want.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
@@ -10,6 +10,10 @@
|
|||||||
type_error/3
|
type_error/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
|
||||||
|
:- meta_predicate check_(1, ?, ?).
|
||||||
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
must_be(Type, Term)
|
must_be(Type, Term)
|
||||||
|
|
||||||
@@ -28,8 +32,12 @@
|
|||||||
- boolean
|
- boolean
|
||||||
- character
|
- character
|
||||||
- chars
|
- chars
|
||||||
|
- in_character
|
||||||
- integer
|
- integer
|
||||||
- list
|
- list
|
||||||
|
- octet_character
|
||||||
|
- octet_chars
|
||||||
|
- term
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
must_be(Type, Term) :-
|
must_be(Type, Term) :-
|
||||||
@@ -44,9 +52,16 @@ must_be_(var, Term) :-
|
|||||||
; throw(error(uninstantiation_error(Term), must_be/2))
|
; throw(error(uninstantiation_error(Term), must_be/2))
|
||||||
).
|
).
|
||||||
must_be_(integer, Term) :- check_(integer, integer, Term).
|
must_be_(integer, Term) :- check_(integer, integer, Term).
|
||||||
|
must_be_(not_less_than_zero, N) :-
|
||||||
|
must_be(integer, N),
|
||||||
|
( N >= 0 -> true
|
||||||
|
; domain_error(not_less_than_zero, N, must_be/2)
|
||||||
|
).
|
||||||
must_be_(atom, Term) :- check_(atom, atom, Term).
|
must_be_(atom, Term) :- check_(atom, atom, Term).
|
||||||
must_be_(character, T) :- check_(error:character, character, T).
|
must_be_(character, T) :- check_(error:character, character, T).
|
||||||
|
must_be_(in_character, T) :- check_(error:in_character, in_character, T).
|
||||||
must_be_(chars, Ls) :-
|
must_be_(chars, Ls) :-
|
||||||
|
can_be(chars, Ls), % prioritize type errors over instantiation errors
|
||||||
must_be(list, Ls),
|
must_be(list, Ls),
|
||||||
( '$is_partial_string'(Ls) ->
|
( '$is_partial_string'(Ls) ->
|
||||||
% The expected case (success) uses a very fast test.
|
% The expected case (success) uses a very fast test.
|
||||||
@@ -55,9 +70,27 @@ must_be_(chars, Ls) :-
|
|||||||
true
|
true
|
||||||
; all_characters(Ls)
|
; all_characters(Ls)
|
||||||
).
|
).
|
||||||
|
must_be_(octet_character, C) :-
|
||||||
|
must_be(character, C),
|
||||||
|
( octet_character(C) -> true
|
||||||
|
; domain_error(octet_character, C, must_be/2)
|
||||||
|
).
|
||||||
|
must_be_(octet_chars, Cs) :-
|
||||||
|
must_be(chars, Cs),
|
||||||
|
( '$first_non_octet'(Cs, C) ->
|
||||||
|
domain_error(octet_character, C, must_be/2)
|
||||||
|
; true
|
||||||
|
).
|
||||||
must_be_(list, Term) :- check_(error:ilist, list, Term).
|
must_be_(list, Term) :- check_(error:ilist, list, Term).
|
||||||
must_be_(type, Term) :- check_(error:type, type, Term).
|
must_be_(type, Term) :- check_(error:type, type, Term).
|
||||||
must_be_(boolean, Term) :- check_(error:boolean, boolean, Term).
|
must_be_(boolean, Term) :- check_(error:boolean, boolean, Term).
|
||||||
|
must_be_(term, Term) :-
|
||||||
|
( \+ ground(Term) ->
|
||||||
|
instantiation_error(must_be/2)
|
||||||
|
; \+ acyclic_term(Term) ->
|
||||||
|
type_error(term, Term, must_be/2)
|
||||||
|
; true
|
||||||
|
).
|
||||||
|
|
||||||
% We cannot use maplist(must_be(character), Cs), because library(lists)
|
% We cannot use maplist(must_be(character), Cs), because library(lists)
|
||||||
% uses library(error), so importing it would create a cyclic dependency.
|
% uses library(error), so importing it would create a cyclic dependency.
|
||||||
@@ -79,6 +112,15 @@ character(C) :-
|
|||||||
atom(C),
|
atom(C),
|
||||||
atom_length(C, 1).
|
atom_length(C, 1).
|
||||||
|
|
||||||
|
octet_character(C) :-
|
||||||
|
char_code(C, Code),
|
||||||
|
0 =< Code, Code =< 0xff.
|
||||||
|
|
||||||
|
in_character(C) :-
|
||||||
|
( character(C)
|
||||||
|
; C == end_of_file
|
||||||
|
).
|
||||||
|
|
||||||
ilist(Ls) :-
|
ilist(Ls) :-
|
||||||
'$skip_max_list'(_, _, Ls, Rs),
|
'$skip_max_list'(_, _, Ls, Rs),
|
||||||
( var(Rs) ->
|
( var(Rs) ->
|
||||||
@@ -90,10 +132,15 @@ type(type).
|
|||||||
type(integer).
|
type(integer).
|
||||||
type(atom).
|
type(atom).
|
||||||
type(character).
|
type(character).
|
||||||
|
type(in_character).
|
||||||
|
type(octet_character).
|
||||||
|
type(octet_chars).
|
||||||
type(chars).
|
type(chars).
|
||||||
type(list).
|
type(list).
|
||||||
type(var).
|
type(var).
|
||||||
type(boolean).
|
type(boolean).
|
||||||
|
type(term).
|
||||||
|
type(not_less_than_zero).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
can_be(Type, Term)
|
can_be(Type, Term)
|
||||||
@@ -117,11 +164,45 @@ can_be(Type, Term) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
can_(integer, Term) :- integer(Term).
|
can_(integer, Term) :- integer(Term).
|
||||||
|
can_(not_less_than_zero, N) :-
|
||||||
|
( integer(N) ->
|
||||||
|
( N >= 0 -> true
|
||||||
|
; domain_error(not_less_than_zero, N, can_be/2)
|
||||||
|
)
|
||||||
|
; type_error(integer, N, can_be/2)
|
||||||
|
).
|
||||||
can_(atom, Term) :- atom(Term).
|
can_(atom, Term) :- atom(Term).
|
||||||
can_(character, T) :- character(T).
|
can_(character, T) :- character(T).
|
||||||
can_(chars, Ls) :- '$is_partial_string'(Ls).
|
can_(in_character, T) :- in_character(T).
|
||||||
|
can_(chars, Ls) :-
|
||||||
|
( '$is_partial_string'(Ls) -> true
|
||||||
|
; can_be(list, Ls),
|
||||||
|
can_be_chars(Ls)
|
||||||
|
).
|
||||||
|
can_(octet_character, C) :-
|
||||||
|
( octet_character(C) -> true
|
||||||
|
; domain_error(octet_character, C, can_be/2)
|
||||||
|
).
|
||||||
|
can_(octet_chars, Cs) :-
|
||||||
|
can_be(chars, Cs),
|
||||||
|
( '$skip_max_list'(_, _, Cs, []), % temporarily turn Cs into a list
|
||||||
|
'$first_non_octet'(Cs, C) ->
|
||||||
|
domain_error(octet_character, C, can_be/2)
|
||||||
|
; true
|
||||||
|
).
|
||||||
can_(list, Term) :- list_or_partial_list(Term).
|
can_(list, Term) :- list_or_partial_list(Term).
|
||||||
can_(boolean, Term) :- boolean(Term).
|
can_(boolean, Term) :- boolean(Term).
|
||||||
|
can_(term, Term) :-
|
||||||
|
( acyclic_term(Term) ->
|
||||||
|
true
|
||||||
|
; type_error(term, Term, can_be/2)
|
||||||
|
).
|
||||||
|
|
||||||
|
can_be_chars(Var) :- var(Var), !.
|
||||||
|
can_be_chars([]).
|
||||||
|
can_be_chars([X|Xs]) :-
|
||||||
|
can_be(character, X),
|
||||||
|
can_be_chars(Xs).
|
||||||
|
|
||||||
list_or_partial_list(Ls) :-
|
list_or_partial_list(Ls) :-
|
||||||
'$skip_max_list'(_, _, Ls, Rs),
|
'$skip_max_list'(_, _, Ls, Rs),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Written June 2020 by Markus Triska (triska@metalevel.at)
|
Written 2020, 2022 by Markus Triska (triska@metalevel.at)
|
||||||
Part of Scryer Prolog.
|
Part of Scryer Prolog.
|
||||||
|
|
||||||
Predicates for reasoning about files and directories.
|
Predicates for reasoning about files and directories.
|
||||||
@@ -65,52 +65,46 @@
|
|||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
:- use_module(library(charsio)).
|
:- use_module(library(charsio)).
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
list_of_chars(Cs) :-
|
|
||||||
must_be(list, Cs),
|
|
||||||
maplist(must_be(character), Cs).
|
|
||||||
|
|
||||||
directory_files(Directory, Files) :-
|
directory_files(Directory, Files) :-
|
||||||
list_of_chars(Directory),
|
must_be(chars, Directory),
|
||||||
can_be(list, Files),
|
can_be(list, Files),
|
||||||
'$directory_files'(Directory, Files).
|
'$directory_files'(Directory, Files).
|
||||||
|
|
||||||
file_size(File, Size) :-
|
file_size(File, Size) :-
|
||||||
file_must_exist(File, file_size/2),
|
file_must_exist(File, file_size/2),
|
||||||
list_of_chars(File),
|
|
||||||
can_be(integer, Size),
|
can_be(integer, Size),
|
||||||
'$file_size'(File, Size).
|
'$file_size'(File, Size).
|
||||||
|
|
||||||
file_exists(File) :-
|
file_exists(File) :-
|
||||||
list_of_chars(File),
|
must_be(chars, File),
|
||||||
'$file_exists'(File).
|
'$file_exists'(File).
|
||||||
|
|
||||||
directory_exists(Directory) :-
|
directory_exists(Directory) :-
|
||||||
list_of_chars(Directory),
|
must_be(chars, Directory),
|
||||||
'$directory_exists'(Directory).
|
'$directory_exists'(Directory).
|
||||||
|
|
||||||
make_directory(Directory) :-
|
make_directory(Directory) :-
|
||||||
list_of_chars(Directory),
|
must_be(chars, Directory),
|
||||||
'$make_directory'(Directory).
|
'$make_directory'(Directory).
|
||||||
|
|
||||||
make_directory_path(Directory) :-
|
make_directory_path(Directory) :-
|
||||||
list_of_chars(Directory),
|
must_be(chars, Directory),
|
||||||
'$make_directory_path'(Directory).
|
'$make_directory_path'(Directory).
|
||||||
|
|
||||||
delete_file(File) :-
|
delete_file(File) :-
|
||||||
file_must_exist(File, delete_file/1),
|
file_must_exist(File, delete_file/1),
|
||||||
list_of_chars(File),
|
|
||||||
'$delete_file'(File).
|
'$delete_file'(File).
|
||||||
|
|
||||||
rename_file(File, Renamed) :-
|
rename_file(File, Renamed) :-
|
||||||
file_must_exist(File, rename_file/2),
|
file_must_exist(File, rename_file/2),
|
||||||
list_of_chars(File),
|
must_be(chars, Renamed),
|
||||||
list_of_chars(Renamed),
|
|
||||||
'$rename_file'(File, Renamed).
|
'$rename_file'(File, Renamed).
|
||||||
|
|
||||||
delete_directory(Directory) :-
|
delete_directory(Directory) :-
|
||||||
directory_must_exist(Directory, delete_directory/1),
|
directory_must_exist(Directory, delete_directory/1),
|
||||||
list_of_chars(Directory),
|
must_be(chars, Directory),
|
||||||
'$delete_directory'(Directory).
|
'$delete_directory'(Directory).
|
||||||
|
|
||||||
file_must_exist(File, Context) :-
|
file_must_exist(File, Context) :-
|
||||||
@@ -150,8 +144,7 @@ working_directory(Dir0, Dir) :-
|
|||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
path_canonical(Ps, Cs) :-
|
path_canonical(Ps, Cs) :-
|
||||||
must_be(list, Ps),
|
must_be(chars, Ps),
|
||||||
maplist(must_be(character), Ps),
|
|
||||||
can_be(list, Cs),
|
can_be(list, Cs),
|
||||||
'$path_canonical'(Ps, Cs).
|
'$path_canonical'(Ps, Cs).
|
||||||
|
|
||||||
@@ -205,20 +198,20 @@ path_segments(Path, Segments) :-
|
|||||||
'$directory_separator'(Sep),
|
'$directory_separator'(Sep),
|
||||||
( var(Path) ->
|
( var(Path) ->
|
||||||
must_be(list, Segments),
|
must_be(list, Segments),
|
||||||
maplist(list_of_chars, Segments),
|
maplist(must_be(chars), Segments),
|
||||||
append_with_separator(Segments, Sep, Path)
|
phrase(append_with_separator(Segments, Sep), Path)
|
||||||
; list_of_chars(Path),
|
; must_be(chars, Path),
|
||||||
path_to_segments(Path, Sep, Segments)
|
path_to_segments(Path, Sep, Segments)
|
||||||
).
|
).
|
||||||
|
|
||||||
append_with_separator([], _, []).
|
append_with_separator([], _) --> [].
|
||||||
append_with_separator([Segment|Segments], Sep, Path) :-
|
append_with_separator([Segment|Segments], Sep) -->
|
||||||
append_with_separator_(Segments, Segment, Sep, Path).
|
append_with_separator_(Segments, Segment, Sep).
|
||||||
|
|
||||||
append_with_separator_([], Segment, _, Segment).
|
append_with_separator_([], Segment, _) --> seq(Segment).
|
||||||
append_with_separator_([Segment|Segments], Prev, Sep, Path) :-
|
append_with_separator_([Segment|Segments], Prev, Sep) -->
|
||||||
append(Prev, [Sep|Rest], Path),
|
seq(Prev), [Sep],
|
||||||
append_with_separator_(Segments, Segment, Sep, Rest).
|
append_with_separator_(Segments, Segment, Sep).
|
||||||
|
|
||||||
path_to_segments(Path, Sep, Segments) :-
|
path_to_segments(Path, Sep, Segments) :-
|
||||||
( append(Front, [Sep|Ps], Path) ->
|
( append(Front, [Sep|Ps], Path) ->
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
:- use_module(library(atts)).
|
:- use_module(library(atts)).
|
||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
|
|
||||||
:- meta_predicate freeze(?, 0).
|
:- meta_predicate freeze(-, 0).
|
||||||
|
|
||||||
:- attribute frozen/1.
|
:- attribute frozen/1.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Written 2020, 2021 by Markus Triska (triska@metalevel.at)
|
Written 2022 by Adrián Arroyo Calle (adrian.arroyocalle@gmail.com)
|
||||||
Part of Scryer Prolog.
|
Part of Scryer Prolog.
|
||||||
|
|
||||||
http_open(+Address, -Stream, +Options)
|
http_open(+Address, -Stream, +Options)
|
||||||
@@ -7,12 +7,16 @@
|
|||||||
|
|
||||||
Yields Stream to read the body of an HTTP reply from Address.
|
Yields Stream to read the body of an HTTP reply from Address.
|
||||||
Address is a list of characters, and includes the method. Both HTTP
|
Address is a list of characters, and includes the method. Both HTTP
|
||||||
and HTTPS are supported. Redirects are followed.
|
and HTTPS are supported.
|
||||||
|
|
||||||
Currently, Options must be the empty list. Options may be
|
Options supported:
|
||||||
added in the future to give more control over the connection.
|
|
||||||
|
|
||||||
We use HTTP/1.0 until we can read chunked transfer-encoding.
|
* method(+Method): Sets the HTTP method of the call. Method can be get (default), head, delete, post, put or patch.
|
||||||
|
* data(+Data): Data to be sent in the request. Useful for POST, PUT and PATCH operations.
|
||||||
|
* size(-Size): Unifies with the value of the Content-Length header
|
||||||
|
* request_headers(+RequestHeaders): Headers to be used in the request
|
||||||
|
* headers(-ListHeaders): Unifies with a list with all headers returned in the response
|
||||||
|
* status_code(-Code): Unifies with the status code of the request (200, 201, 404, ...)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -23,62 +27,42 @@
|
|||||||
|
|
||||||
:- module(http_open, [http_open/3]).
|
:- module(http_open, [http_open/3]).
|
||||||
|
|
||||||
:- use_module(library(sockets)).
|
:- use_module(library(lists)).
|
||||||
:- use_module(library(error)).
|
|
||||||
:- use_module(library(format)).
|
|
||||||
:- use_module(library(charsio)).
|
|
||||||
:- use_module(library(dcgs)).
|
|
||||||
:- use_module(library(lists), [member/2]).
|
|
||||||
:- use_module(library(tls)).
|
|
||||||
|
|
||||||
http_open(Address, Stream, Options) :-
|
http_open(Address, Response, Options) :-
|
||||||
must_be(list, Options),
|
parse_http_options(Options, OptionValues),
|
||||||
must_be(list, Address),
|
( member(method(Method), OptionValues) -> true; Method = get),
|
||||||
once(phrase((seq(SchemeCs), "://", seq(Rest)), Address)),
|
( member(data(Data), OptionValues) -> true; Data = []),
|
||||||
atom_chars(Scheme, SchemeCs),
|
( member(request_headers(RequestHeaders), OptionValues) -> true; RequestHeaders = ['user-agent'("Scryer Prolog")]),
|
||||||
chars_host_url(Rest, Host, URL),
|
( member(status_code(Code), OptionValues) -> true; true),
|
||||||
connect(Scheme, Host, Stream0),
|
( member(headers(Headers), OptionValues) -> true; true),
|
||||||
format(Stream0, "\
|
( member(size(Size), OptionValues) -> member('content-length'(Size), Headers); true),
|
||||||
GET ~s HTTP/1.0\r\n\
|
'$http_open'(Address, Response, Method, Code, Data, Headers, RequestHeaders).
|
||||||
Host: ~w\r\n\
|
|
||||||
User-Agent: Scryer Prolog\r\n\
|
|
||||||
Connection: close\r\n\r\n\
|
|
||||||
", [URL,Host]),
|
|
||||||
read_line_to_chars(Stream0, StatusLine, []),
|
|
||||||
once(phrase(("HTTP/1.",(['0']|['1'])," ",[D1]), StatusLine, _)),
|
|
||||||
read_header_lines(Stream0, HeaderLines),
|
|
||||||
handle_response(D1, HeaderLines, Stream0, Stream).
|
|
||||||
|
|
||||||
handle_response('2', _, Stream, Stream). % ok
|
parse_http_options(Options, OptionValues) :-
|
||||||
handle_response('3', HeaderLines, Stream0, Stream) :- % redirect
|
maplist(parse_http_options_, Options, OptionValues).
|
||||||
close(Stream0),
|
|
||||||
once((member(Line, HeaderLines),
|
|
||||||
phrase(("Location: ",seq(Location),"\r\n"), Line))),
|
|
||||||
http_open(Location, Stream, []).
|
|
||||||
|
|
||||||
% Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
|
parse_http_options_(method(Method), method(Method)) :-
|
||||||
|
( var(Method) ->
|
||||||
read_header_lines(Stream, Hs) :-
|
throw(error(instantiation_error, http_open/3))
|
||||||
read_line_to_chars(Stream, Cs, []),
|
;
|
||||||
( Cs == "" -> Hs = []
|
member(Method, [get, post, put, delete, patch, head]) -> true
|
||||||
; Cs == "\r\n" -> Hs = []
|
;
|
||||||
; Hs = [Cs|Rest],
|
throw(error(domain_error(http_option, method(Method)), _))
|
||||||
read_header_lines(Stream, Rest)
|
|
||||||
).
|
).
|
||||||
|
|
||||||
chars_host_url(Cs, Host, [/|Us]) :-
|
parse_http_options_(data(Data), data(Data)) :-
|
||||||
( phrase((seq(Hs),"/",seq(Us)), Cs) ->
|
( var(Data) ->
|
||||||
true
|
throw(error(instantiation_error, http_open/3))
|
||||||
; Hs = Cs,
|
; true
|
||||||
Us = []
|
).
|
||||||
),
|
|
||||||
atom_chars(Host, Hs).
|
|
||||||
|
|
||||||
connect(https, Host, Stream) :-
|
parse_http_options_(request_headers(Headers), request_headers(Headers)) :-
|
||||||
socket_client_open(Host:443, Stream0, []),
|
( var(Headers) ->
|
||||||
atom_chars(Host, HostChars),
|
throw(error(instantiation_error, http_open/3))
|
||||||
tls_client_context(Context, [hostname(HostChars)]),
|
; true
|
||||||
tls_client_negotiate(Context, Stream0, Stream).
|
).
|
||||||
connect(http, Host, Stream) :-
|
|
||||||
socket_client_open(Host:80, Stream, []).
|
|
||||||
|
|
||||||
|
parse_http_options_(size(Size), size(Size)).
|
||||||
|
parse_http_options_(status_code(Code), status_code(Code)).
|
||||||
|
parse_http_options_(headers(Headers), headers(Headers)).
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Written in December 2020 by Adrián Arroyo (adrian.arroyocalle@gmail.com)
|
Written in December 2020 by Adrián Arroyo (adrian.arroyocalle@gmail.com)
|
||||||
|
Updated in March 2022 by Adrián Arroyo to use the Hyper backend
|
||||||
Part of Scryer Prolog
|
Part of Scryer Prolog
|
||||||
|
|
||||||
This library provides an starting point to build HTTP server based applications.
|
This library provides an starting point to build HTTP server based applications.
|
||||||
It currently implements a subset of HTTP/1.0. It is recommended to put a reverse
|
It is based on Hyper, which allows for HTTP/1.0, HTTP/1.1 and HTTP/2. However,
|
||||||
proxy like nginx in front of this server to have access to more advanced features
|
some advanced features that Hyper provides are still not accesible.
|
||||||
(gzip compression, HTTPS, ...)
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
==========
|
==========
|
||||||
@@ -41,37 +41,36 @@
|
|||||||
Some things that are still missing:
|
Some things that are still missing:
|
||||||
- Read forms in multipart format
|
- Read forms in multipart format
|
||||||
- HTTP Basic Auth
|
- HTTP Basic Auth
|
||||||
- Keep-Alive support
|
|
||||||
- Session handling via cookies
|
- Session handling via cookies
|
||||||
- HTML Templating
|
- HTML Templating
|
||||||
|
|
||||||
I place this code in the public domain. Use it in any way you want.
|
I place this code in the public domain. Use it in any way you want.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
|
||||||
:- module(http_server, [
|
:- module(http_server, [
|
||||||
http_listen/2,
|
http_listen/2,
|
||||||
http_headers/2,
|
http_headers/2,
|
||||||
http_status_code/2,
|
http_status_code/2,
|
||||||
http_body/2,
|
http_body/2,
|
||||||
http_redirect/2,
|
http_redirect/2,
|
||||||
http_query/3,
|
http_query/3
|
||||||
url_decode//1
|
|
||||||
]).
|
]).
|
||||||
|
|
||||||
:- meta_predicate http_listen(?, 2).
|
:- meta_predicate http_listen(?, :).
|
||||||
|
|
||||||
:- use_module(library(sockets)).
|
|
||||||
:- use_module(library(dcgs)).
|
|
||||||
:- use_module(library(format)).
|
|
||||||
:- use_module(library(error)).
|
|
||||||
:- use_module(library(charsio)).
|
:- use_module(library(charsio)).
|
||||||
:- use_module(library(lists)).
|
|
||||||
:- use_module(library(iso_ext)).
|
|
||||||
:- use_module(library(time)).
|
|
||||||
:- use_module(library(crypto)).
|
:- use_module(library(crypto)).
|
||||||
|
:- use_module(library(error)).
|
||||||
|
:- use_module(library(format)).
|
||||||
|
:- use_module(library(iso_ext)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(pio)).
|
||||||
|
:- use_module(library(time)).
|
||||||
|
|
||||||
% Module prefix workaround with meta_predicate
|
|
||||||
http_listen(Port, Module:Handlers0) :-
|
http_listen(Port, Module:Handlers0) :-
|
||||||
|
must_be(integer, Port),
|
||||||
|
must_be(list, Handlers0),
|
||||||
maplist(module_qualification(Module), Handlers0, Handlers),
|
maplist(module_qualification(Module), Handlers0, Handlers),
|
||||||
http_listen_(Port, Handlers).
|
http_listen_(Port, Handlers).
|
||||||
|
|
||||||
@@ -79,49 +78,84 @@ module_qualification(M, H0, H) :-
|
|||||||
H0 =.. [Method, Path, Goal],
|
H0 =.. [Method, Path, Goal],
|
||||||
H =.. [Method, Path, M:Goal].
|
H =.. [Method, Path, M:Goal].
|
||||||
|
|
||||||
% Server initialization
|
|
||||||
http_listen_(Port, Handlers) :-
|
http_listen_(Port, Handlers) :-
|
||||||
must_be(integer, Port),
|
phrase(format_("0.0.0.0:~d", [Port]), Addr),
|
||||||
must_be(list, Handlers),
|
'$http_listen'(Addr, HttpListener),!,
|
||||||
once(socket_server_open(Port, Socket)),
|
format("Listening at ~s\n", [Addr]),
|
||||||
format("Listening at port ~d\n", [Port]),
|
http_loop(HttpListener, Handlers).
|
||||||
accept_loop(Socket, Handlers).
|
|
||||||
|
|
||||||
% Server loop
|
http_loop(HttpListener, Handlers) :-
|
||||||
accept_loop(Socket, Handlers) :-
|
'$http_accept'(HttpListener, RequestMethod, RequestPath, RequestHeaders, RequestQuery, RequestStream, ResponseHandle),
|
||||||
setup_call_cleanup(socket_server_accept(Socket, _Client, Stream, [type(binary)]),
|
|
||||||
(
|
|
||||||
read_header_lines(Stream, Lines),
|
|
||||||
[Request|Headers] = Lines,
|
|
||||||
(
|
|
||||||
(phrase(parse_request(_Version, Method, Path, Queries), Request), maplist(map_parse_header, Headers, HeadersKV)) -> (
|
|
||||||
(
|
|
||||||
member("content-length"-ContentLength, HeadersKV) ->
|
|
||||||
(number_chars(ContentLengthN, ContentLength), get_bytes(Stream, ContentLengthN, Body))
|
|
||||||
;true
|
|
||||||
),
|
|
||||||
current_time(Time),
|
current_time(Time),
|
||||||
phrase(format_time("%Y-%m-%d (%H:%M:%S)", Time), TimeString),
|
phrase(format_time("%Y-%m-%d (%H:%M:%S)", Time), TimeString),
|
||||||
format("~s ~w ~s\n", [TimeString, Method, Path]),
|
format("~s ~w ~s\n", [TimeString, RequestMethod, RequestPath]),
|
||||||
|
maplist(map_header_kv, RequestHeaders, RequestHeadersKV),
|
||||||
|
phrase(parse_queries(RequestQueries), RequestQuery),
|
||||||
(
|
(
|
||||||
match_handler(Handlers, Method, Path, Handler) ->
|
match_handler(Handlers, RequestMethod, RequestPath, Handler) ->
|
||||||
(
|
(
|
||||||
HttpRequest = http_request(HeadersKV, binary(Body), Queries),
|
HttpRequest = http_request(RequestHeadersKV, stream(RequestStream), RequestQueries),
|
||||||
HttpResponse = http_response(_, _, _),
|
HttpResponse = http_response(_, _, _),
|
||||||
(call(Handler, HttpRequest, HttpResponse) ->
|
(call(Handler, HttpRequest, HttpResponse) ->
|
||||||
send_response(Stream, HttpResponse)
|
send_response(ResponseHandle, HttpResponse)
|
||||||
; format(Stream, "HTTP/1.0 500 Internal Server Error\r\n\r\n", [])
|
; (
|
||||||
|
'$http_answer'(ResponseHandle, 500, [], ResponseStream),
|
||||||
|
call_cleanup(format(ResponseStream, "Internal Server Error", []), close(ResponseStream)))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
; format(Stream, "HTTP/1.0 404 Not Found\r\n\r\n", [])
|
; (
|
||||||
)
|
'$http_answer'(ResponseHandle, 404, [], ResponseStream),
|
||||||
);(
|
call_cleanup(format(ResponseStream, "Not Found"), close(ResponseStream)))
|
||||||
format(Stream, "HTTP/1.0 400 Bad Request\r\n\r\n", []) % bad format
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
! % Remove
|
http_loop(HttpListener, Handlers).
|
||||||
), close(Stream)),
|
|
||||||
accept_loop(Socket, Handlers).
|
send_response(ResponseHandle, http_response(StatusCode0, text(ResponseText), ResponseHeaders0)) :-
|
||||||
|
default(StatusCode0, 200, StatusCode),
|
||||||
|
maplist(map_header_kv_2, ResponseHeaders, ResponseHeaders0),
|
||||||
|
'$http_answer'(ResponseHandle, StatusCode, ResponseHeaders, ResponseStream),
|
||||||
|
call_cleanup(
|
||||||
|
format(ResponseStream, "~s", [ResponseText]),
|
||||||
|
close(ResponseStream)
|
||||||
|
).
|
||||||
|
|
||||||
|
send_response(ResponseHandle, http_response(StatusCode0, bytes(ResponseBytes), ResponseHeaders0)) :-
|
||||||
|
default(StatusCode0, 200, StatusCode),
|
||||||
|
maplist(map_header_kv_2, ResponseHeaders, ResponseHeaders0),
|
||||||
|
'$http_answer'(ResponseHandle, StatusCode, ResponseHeaders, ResponseStream),
|
||||||
|
call_cleanup(
|
||||||
|
format(ResponseStream, "~s", [ResponseBytes]),
|
||||||
|
close(ResponseStream)
|
||||||
|
).
|
||||||
|
|
||||||
|
send_response(ResponseHandle, http_response(StatusCode0, file(Filename), ResponseHeaders0)) :-
|
||||||
|
default(StatusCode0, 200, StatusCode),
|
||||||
|
maplist(map_header_kv_2, ResponseHeaders, ResponseHeaders0),
|
||||||
|
'$http_answer'(ResponseHandle, StatusCode, ResponseHeaders, ResponseStream),
|
||||||
|
call_cleanup(
|
||||||
|
setup_call_cleanup(
|
||||||
|
open(Filename, read, FileStream, [type(binary)]),
|
||||||
|
(
|
||||||
|
get_n_chars(FileStream, _, FileCs),
|
||||||
|
format(ResponseStream, "~s", [FileCs])
|
||||||
|
),
|
||||||
|
close(FileStream)
|
||||||
|
),
|
||||||
|
close(ResponseStream)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
default(Var, Default, Out) :-
|
||||||
|
(var(Var) -> Out = Default
|
||||||
|
; Var = Out
|
||||||
|
).
|
||||||
|
|
||||||
|
map_header_kv(T, K-V) :-
|
||||||
|
T =.. [K0, V],
|
||||||
|
atom_chars(K0, K).
|
||||||
|
|
||||||
|
map_header_kv_2(T, K-V) :-
|
||||||
|
atom_chars(K0, K),
|
||||||
|
T =.. [K0, V].
|
||||||
|
|
||||||
match_handler(Handlers, Method, "/", Handler) :-
|
match_handler(Handlers, Method, "/", Handler) :-
|
||||||
member(H, Handlers),
|
member(H, Handlers),
|
||||||
@@ -139,27 +173,6 @@ match_handler(Handlers, Method, Path, Handler) :-
|
|||||||
var(Var),
|
var(Var),
|
||||||
Var = Path.
|
Var = Path.
|
||||||
|
|
||||||
|
|
||||||
% Helper and recommended predicates
|
|
||||||
|
|
||||||
http_headers(http_request(Headers, _, _), Headers).
|
|
||||||
http_headers(http_response(_, _, Headers), Headers).
|
|
||||||
|
|
||||||
http_body(http_request(_, binary(ByteBody), _), text(TextBody)) :- chars_utf8bytes(TextBody, ByteBody).
|
|
||||||
http_body(http_request(Headers, binary(ByteBody), _), form(FormBody)) :-
|
|
||||||
member("content-type"-"application/x-www-form-urlencoded", Headers),
|
|
||||||
chars_utf8bytes(TextBody, ByteBody),
|
|
||||||
phrase(parse_queries(FormBody), TextBody).
|
|
||||||
http_body(http_request(_, Body, _), Body).
|
|
||||||
http_body(http_response(_, Body, _), Body).
|
|
||||||
|
|
||||||
http_status_code(http_response(StatusCode, _, _), StatusCode).
|
|
||||||
|
|
||||||
http_redirect(http_response(307, text("Moved Temporarily"), ["Location"-Uri]), Uri).
|
|
||||||
|
|
||||||
http_query(http_request(_, _, Queries), Key, Value) :- member(Key-Value, Queries).
|
|
||||||
|
|
||||||
% Route matching
|
|
||||||
path(Pattern) -->
|
path(Pattern) -->
|
||||||
{
|
{
|
||||||
Pattern =.. Parts,
|
Pattern =.. Parts,
|
||||||
@@ -183,76 +196,31 @@ path(Pattern) -->
|
|||||||
|
|
||||||
path([]) --> [].
|
path([]) --> [].
|
||||||
|
|
||||||
% Send responses
|
string_without(Not, [Char|String]) -->
|
||||||
send_response(Stream, http_response(StatusCode0, file(Filename), Headers)) :-
|
[Char],
|
||||||
default(StatusCode0, 200, StatusCode),
|
{
|
||||||
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
|
\+ member(Char, Not)
|
||||||
overwrite_header("connection"-"Close", Headers, Headers0),
|
},
|
||||||
write_headers(Stream, Headers0),
|
string_without(Not, String).
|
||||||
format(Stream, "\r\n", []),
|
|
||||||
setup_call_cleanup(
|
|
||||||
open(Filename, read, FileStream, [type(binary)]),
|
|
||||||
pipe_bytes(FileStream, Stream),
|
|
||||||
close(FileStream)
|
|
||||||
).
|
|
||||||
|
|
||||||
send_response(Stream, http_response(StatusCode0, text(TextResponse), Headers)) :-
|
string_without(_, []) -->
|
||||||
default(StatusCode0, 200, StatusCode),
|
[].
|
||||||
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
|
|
||||||
overwrite_header("content-type"-"text/plain", Headers, Headers0),
|
|
||||||
overwrite_header("connection"-"Close", Headers0, Headers1),
|
|
||||||
write_headers(Stream, Headers1),
|
|
||||||
format(Stream, "\r\n~s", [TextResponse]).
|
|
||||||
|
|
||||||
send_response(Stream, http_response(StatusCode0, binary(BinaryResponse), Headers)) :-
|
http_headers(http_request(Headers, _, _), Headers).
|
||||||
default(StatusCode0, 200, StatusCode),
|
http_headers(http_response(_, _, Headers), Headers).
|
||||||
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
|
|
||||||
overwrite_header("connection"-"Close", Headers, Headers0),
|
|
||||||
write_headers(Stream, Headers0),
|
|
||||||
format(Stream, "\r\n", []),
|
|
||||||
put_bytes(Stream, BinaryResponse).
|
|
||||||
|
|
||||||
default(Var, Default, Out) :-
|
http_body(http_request(_, stream(StreamBody), _), bytes(BytesBody)) :- get_n_chars(StreamBody, _, BytesBody).
|
||||||
(var(Var) -> Out = Default
|
http_body(http_request(_, stream(StreamBody), _), text(TextBody)) :- get_n_chars(StreamBody, _, TextBody).
|
||||||
; Var = Out
|
http_body(http_request(Headers, stream(StreamBody), _), form(FormBody)) :-
|
||||||
).
|
member("content-type"-"application/x-www-form-urlencoded", Headers),
|
||||||
|
get_n_chars(StreamBody, _, TextBody),
|
||||||
|
phrase(parse_queries(FormBody), TextBody).
|
||||||
|
http_body(http_request(_, Body, _), Body).
|
||||||
|
http_body(http_response(_, Body, _), Body).
|
||||||
|
|
||||||
header([]) --> [].
|
http_status_code(http_response(StatusCode, _, _), StatusCode).
|
||||||
header([Key-Value|Headers]) -->
|
http_redirect(http_response(307, text("Moved Temporarily"), ["Location"-Uri]), Uri).
|
||||||
format_("~s: ~s\r\n", [Key, Value]),
|
http_query(http_request(_, _, Queries), Key, Value) :- member(Key-Value, Queries).
|
||||||
header(Headers).
|
|
||||||
|
|
||||||
write_headers(Stream, Headers) :-
|
|
||||||
phrase(header(Headers), Cs),
|
|
||||||
format(Stream, "~s", [Cs]).
|
|
||||||
|
|
||||||
overwrite_header(Key-Value, [], [Key-Value]).
|
|
||||||
overwrite_header(Key-Value, [Header|Headers], [Header|HeadersOut]) :-
|
|
||||||
Header = Key0-_,
|
|
||||||
Key0 \= Key,
|
|
||||||
overwrite_header(Key-Value, Headers, HeadersOut).
|
|
||||||
overwrite_header(Key-Value, [Header|Headers], [NewHeader|Headers]) :-
|
|
||||||
Header = Key-_,
|
|
||||||
NewHeader = Key-Value.
|
|
||||||
|
|
||||||
parse_request(http_version(Major, Minor), Method, Path, Queries) -->
|
|
||||||
method(Method),
|
|
||||||
" ",
|
|
||||||
parse_path(Path, Queries),
|
|
||||||
" ",
|
|
||||||
"HTTP/",
|
|
||||||
natural(Major),
|
|
||||||
".",
|
|
||||||
natural(Minor),
|
|
||||||
"\r\n".
|
|
||||||
|
|
||||||
parse_path(Path, Queries) -->
|
|
||||||
string_without("?", Path),
|
|
||||||
"?",
|
|
||||||
parse_queries(Queries).
|
|
||||||
|
|
||||||
parse_path(Path, []) -->
|
|
||||||
string_without(" ", Path).
|
|
||||||
|
|
||||||
parse_queries([Key-Value|Queries]) -->
|
parse_queries([Key-Value|Queries]) -->
|
||||||
string_without("=", Key0),
|
string_without("=", Key0),
|
||||||
@@ -278,94 +246,9 @@ parse_queries([Key-Value]) -->
|
|||||||
phrase(url_decode(Value), Value0)
|
phrase(url_decode(Value), Value0)
|
||||||
}.
|
}.
|
||||||
|
|
||||||
map_parse_header(Header, HeaderKV) :-
|
parse_queries([]) -->
|
||||||
phrase(parse_header(HeaderKV), Header).
|
|
||||||
|
|
||||||
parse_header(Key-Value) -->
|
|
||||||
string_without(":", Key0),
|
|
||||||
{
|
|
||||||
chars_lower(Key0, Key)
|
|
||||||
},
|
|
||||||
": ",
|
|
||||||
string_without("\r", Value),
|
|
||||||
"\r\n".
|
|
||||||
|
|
||||||
method(options) --> "OPTIONS".
|
|
||||||
method(get) --> "GET".
|
|
||||||
method(head) --> "HEAD".
|
|
||||||
method(post) --> "POST".
|
|
||||||
method(put) --> "PUT".
|
|
||||||
method(delete) --> "DELETE".
|
|
||||||
|
|
||||||
string_without(Not, [Char|String]) -->
|
|
||||||
[Char],
|
|
||||||
{
|
|
||||||
\+ member(Char, Not)
|
|
||||||
},
|
|
||||||
string_without(Not, String).
|
|
||||||
|
|
||||||
string_without(_, []) -->
|
|
||||||
[].
|
[].
|
||||||
|
|
||||||
natural(Nat) -->
|
|
||||||
natural_(NatChars),
|
|
||||||
{
|
|
||||||
number_chars(Nat, NatChars)
|
|
||||||
}.
|
|
||||||
|
|
||||||
natural_([Nat|Nats]) -->
|
|
||||||
[Nat],
|
|
||||||
{
|
|
||||||
char_type(Nat, decimal_digit)
|
|
||||||
},
|
|
||||||
natural_(Nats).
|
|
||||||
|
|
||||||
natural_([]) -->
|
|
||||||
[].
|
|
||||||
|
|
||||||
read_header_lines(Stream, Hs) :-
|
|
||||||
read_line_to_chars(Stream, Cs, []),
|
|
||||||
( Cs == "" -> Hs = []
|
|
||||||
; Cs == "\r\n" -> Hs = []
|
|
||||||
; Hs = [Cs|Rest],
|
|
||||||
read_header_lines(Stream, Rest)
|
|
||||||
).
|
|
||||||
|
|
||||||
get_bytes(Stream, Length, Res) :- get_bytes(Stream, Length, [], Res).
|
|
||||||
get_bytes(Stream, Length, Acc, Res) :-
|
|
||||||
(Length > 0 -> (
|
|
||||||
get_byte(Stream, B),
|
|
||||||
B =\= -1,
|
|
||||||
get_bytes(Stream, Length - 1, [B|Acc], Res)
|
|
||||||
); reverse(Acc, Res)).
|
|
||||||
|
|
||||||
put_bytes(_, []).
|
|
||||||
put_bytes(Stream, [Byte|Bytes]) :-
|
|
||||||
put_byte(Stream, Byte),
|
|
||||||
put_bytes(Stream, Bytes).
|
|
||||||
|
|
||||||
pipe_bytes(StreamIn, StreamOut) :-
|
|
||||||
get_byte(StreamIn, Byte),
|
|
||||||
(
|
|
||||||
Byte =\= -1 ->
|
|
||||||
(
|
|
||||||
put_byte(StreamOut, Byte),
|
|
||||||
pipe_bytes(StreamIn, StreamOut)
|
|
||||||
)
|
|
||||||
; true).
|
|
||||||
|
|
||||||
% WARNING: This only works for ASCII chars. This code can be modified to support
|
|
||||||
% Latin1 characters also but a completely different approach is needed for other
|
|
||||||
% languages. Since HTTP internals are ASCII, this is fine for this usecase.
|
|
||||||
chars_lower(Chars, Lower) :-
|
|
||||||
maplist(char_lower, Chars, Lower).
|
|
||||||
char_lower(Char, Lower) :-
|
|
||||||
char_code(Char, Code),
|
|
||||||
((Code >= 65,Code =< 90) ->
|
|
||||||
LowerCode is Code + 32,
|
|
||||||
char_code(Lower, LowerCode)
|
|
||||||
; Char = Lower).
|
|
||||||
|
|
||||||
% Decodes a UTF-8 URL Encoded string: RFC-1738
|
% Decodes a UTF-8 URL Encoded string: RFC-1738
|
||||||
url_decode([Char|Chars]) -->
|
url_decode([Char|Chars]) -->
|
||||||
[Char],
|
[Char],
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
%% for builtins that are not part of the ISO standard.
|
|
||||||
%% must be loaded at the REPL with
|
|
||||||
|
|
||||||
%% ?- use_module(library(iso_ext)).
|
|
||||||
|
|
||||||
:- module(iso_ext, [bb_b_put/2,
|
:- module(iso_ext, [bb_b_put/2,
|
||||||
bb_get/2,
|
bb_get/2,
|
||||||
bb_put/2,
|
bb_put/2,
|
||||||
@@ -14,8 +9,9 @@
|
|||||||
partial_string_tail/2,
|
partial_string_tail/2,
|
||||||
setup_call_cleanup/3,
|
setup_call_cleanup/3,
|
||||||
call_nth/2,
|
call_nth/2,
|
||||||
% variant/2,
|
copy_term_nat/2,
|
||||||
copy_term_nat/2]).
|
asserta/2,
|
||||||
|
assertz/2]).
|
||||||
|
|
||||||
:- use_module(library(error), [can_be/2,
|
:- use_module(library(error), [can_be/2,
|
||||||
domain_error/3,
|
domain_error/3,
|
||||||
@@ -60,59 +56,64 @@ call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
|
|||||||
|
|
||||||
:- meta_predicate(setup_call_cleanup(0, 0, 0)).
|
:- meta_predicate(setup_call_cleanup(0, 0, 0)).
|
||||||
|
|
||||||
|
:- non_counted_backtracking setup_call_cleanup/3.
|
||||||
|
|
||||||
setup_call_cleanup(S, G, C) :-
|
setup_call_cleanup(S, G, C) :-
|
||||||
'$get_b_value'(B),
|
'$get_b_value'(B),
|
||||||
'$call'(S),
|
'$call_with_inference_counting'(call(S)),
|
||||||
'$set_cp_by_default'(B),
|
'$set_cp_by_default'(B),
|
||||||
'$get_current_block'(Bb),
|
'$get_current_block'(Bb),
|
||||||
( C = _:CC,
|
( C = _:CC,
|
||||||
'$call_with_default_policy'(var(CC)) ->
|
var(CC) ->
|
||||||
instantiation_error(setup_call_cleanup/3)
|
instantiation_error(setup_call_cleanup/3)
|
||||||
; '$call_with_default_policy'(scc_helper(C, G, Bb))
|
; scc_helper(C, G, Bb)
|
||||||
).
|
).
|
||||||
|
|
||||||
:- meta_predicate(scc_helper(?,0,?)).
|
:- meta_predicate(scc_helper(?,0,?)).
|
||||||
|
|
||||||
:- non_counted_backtracking scc_helper/3.
|
:- non_counted_backtracking scc_helper/3.
|
||||||
|
|
||||||
scc_helper(C, G, Bb) :-
|
scc_helper(C, G, Bb) :-
|
||||||
'$get_cp'(Cp),
|
'$get_cp'(Cp),
|
||||||
'$install_scc_cleaner'(C, NBb),
|
'$install_scc_cleaner'(C, NBb),
|
||||||
call(G),
|
'$call_with_inference_counting'(call(G)),
|
||||||
( '$check_cp'(Cp) ->
|
( '$check_cp'(Cp) ->
|
||||||
'$reset_block'(Bb),
|
'$reset_block'(Bb),
|
||||||
'$call_with_default_policy'(run_cleaners_without_handling(Cp))
|
run_cleaners_without_handling(Cp)
|
||||||
; '$call_with_default_policy'(true)
|
; true
|
||||||
; '$reset_block'(NBb),
|
; '$reset_block'(NBb),
|
||||||
'$fail'
|
'$fail'
|
||||||
).
|
).
|
||||||
scc_helper(_, _, Bb) :-
|
scc_helper(_, _, Bb) :-
|
||||||
'$reset_block'(Bb),
|
'$reset_block'(Bb),
|
||||||
'$get_ball'(Ball),
|
'$push_ball_stack',
|
||||||
'$erase_ball',
|
run_cleaners_with_handling,
|
||||||
'$call_with_default_policy'(run_cleaners_with_handling),
|
'$pop_from_ball_stack',
|
||||||
'$call_with_default_policy'(throw(Ball)).
|
'$unwind_stack'.
|
||||||
scc_helper(_, _, _) :-
|
scc_helper(_, _, _) :-
|
||||||
'$get_cp'(Cp),
|
'$get_cp'(Cp),
|
||||||
'$call_with_default_policy'(run_cleaners_without_handling(Cp)),
|
run_cleaners_without_handling(Cp),
|
||||||
'$fail'.
|
'$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 :-
|
||||||
'$get_scc_cleaner'(C),
|
'$get_scc_cleaner'(C),
|
||||||
'$get_level'(B),
|
'$get_level'(B),
|
||||||
'$call_with_default_policy'(catch(C, _, true)),
|
catch(C, _, true),
|
||||||
'$set_cp_by_default'(B),
|
'$set_cp_by_default'(B),
|
||||||
'$call_with_default_policy'(run_cleaners_with_handling).
|
run_cleaners_with_handling.
|
||||||
run_cleaners_with_handling :-
|
run_cleaners_with_handling :-
|
||||||
'$restore_cut_policy'.
|
'$restore_cut_policy'.
|
||||||
|
|
||||||
:- 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_scc_cleaner'(C),
|
||||||
'$get_level'(B),
|
'$get_level'(B),
|
||||||
call(C),
|
call(C),
|
||||||
'$set_cp_by_default'(B),
|
'$set_cp_by_default'(B),
|
||||||
'$call_with_default_policy'(run_cleaners_without_handling(Cp)).
|
run_cleaners_without_handling(Cp).
|
||||||
run_cleaners_without_handling(Cp) :-
|
run_cleaners_without_handling(Cp) :-
|
||||||
'$set_cp_by_default'(Cp),
|
'$set_cp_by_default'(Cp),
|
||||||
'$restore_cut_policy'.
|
'$restore_cut_policy'.
|
||||||
@@ -120,6 +121,7 @@ run_cleaners_without_handling(Cp) :-
|
|||||||
% call_with_inference_limit
|
% call_with_inference_limit
|
||||||
|
|
||||||
:- non_counted_backtracking end_block/4.
|
:- non_counted_backtracking end_block/4.
|
||||||
|
|
||||||
end_block(_, Bb, NBb, _L) :-
|
end_block(_, Bb, NBb, _L) :-
|
||||||
'$clean_up_block'(NBb),
|
'$clean_up_block'(NBb),
|
||||||
'$reset_block'(Bb).
|
'$reset_block'(Bb).
|
||||||
@@ -129,13 +131,19 @@ end_block(B, _Bb, NBb, L) :-
|
|||||||
'$fail'.
|
'$fail'.
|
||||||
|
|
||||||
:- non_counted_backtracking handle_ile/3.
|
:- non_counted_backtracking handle_ile/3.
|
||||||
handle_ile(B, inference_limit_exceeded(B), inference_limit_exceeded) :- !.
|
|
||||||
handle_ile(B, E, _) :-
|
handle_ile(B, inference_limit_exceeded(B), inference_limit_exceeded) :-
|
||||||
|
!,
|
||||||
|
'$pop_ball_stack'.
|
||||||
|
handle_ile(B, _, _) :-
|
||||||
'$remove_call_policy_check'(B),
|
'$remove_call_policy_check'(B),
|
||||||
'$call_with_default_policy'(throw(E)).
|
'$pop_from_ball_stack',
|
||||||
|
'$unwind_stack'.
|
||||||
|
|
||||||
:- meta_predicate(call_with_inference_limit(0, ?, ?)).
|
:- meta_predicate(call_with_inference_limit(0, ?, ?)).
|
||||||
|
|
||||||
|
:- non_counted_backtracking call_with_inference_limit/3.
|
||||||
|
|
||||||
call_with_inference_limit(G, L, R) :-
|
call_with_inference_limit(G, L, R) :-
|
||||||
( integer(L) ->
|
( integer(L) ->
|
||||||
( L < 0 ->
|
( L < 0 ->
|
||||||
@@ -148,7 +156,7 @@ call_with_inference_limit(G, L, R) :-
|
|||||||
),
|
),
|
||||||
'$get_current_block'(Bb),
|
'$get_current_block'(Bb),
|
||||||
'$get_b_value'(B),
|
'$get_b_value'(B),
|
||||||
'$call_with_default_policy'(call_with_inference_limit(G, L, R, Bb, B)),
|
call_with_inference_limit(G, L, R, Bb, B),
|
||||||
'$remove_call_policy_check'(B).
|
'$remove_call_policy_check'(B).
|
||||||
|
|
||||||
install_inference_counter(B, L, Count0) :-
|
install_inference_counter(B, L, Count0) :-
|
||||||
@@ -161,22 +169,22 @@ install_inference_counter(B, L, Count0) :-
|
|||||||
call_with_inference_limit(G, L, R, Bb, B) :-
|
call_with_inference_limit(G, L, R, Bb, B) :-
|
||||||
'$install_new_block'(NBb),
|
'$install_new_block'(NBb),
|
||||||
'$install_inference_counter'(B, L, Count0),
|
'$install_inference_counter'(B, L, Count0),
|
||||||
'$call'(G),
|
'$call_with_inference_counting'(call(G)),
|
||||||
'$inference_level'(R, B),
|
'$inference_level'(R, B),
|
||||||
'$remove_inference_counter'(B, Count1),
|
'$remove_inference_counter'(B, Count1),
|
||||||
'$call_with_default_policy'(is(Diff, L - (Count1 - Count0))),
|
Diff is L - (Count1 - Count0),
|
||||||
'$call_with_default_policy'(end_block(B, Bb, NBb, Diff)).
|
end_block(B, Bb, NBb, Diff).
|
||||||
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_ball'(Ball),
|
||||||
|
'$push_ball_stack',
|
||||||
'$get_level'(Cp),
|
'$get_level'(Cp),
|
||||||
'$set_cp_by_default'(Cp)
|
'$set_cp_by_default'(Cp)
|
||||||
; '$remove_call_policy_check'(B),
|
; '$remove_call_policy_check'(B),
|
||||||
'$fail'
|
'$fail'
|
||||||
),
|
),
|
||||||
'$erase_ball',
|
handle_ile(B, Ball, R).
|
||||||
'$call_with_default_policy'(handle_ile(B, Ball, R)).
|
|
||||||
|
|
||||||
partial_string(String, L, L0) :-
|
partial_string(String, L, L0) :-
|
||||||
( String == [] ->
|
( String == [] ->
|
||||||
@@ -203,33 +211,55 @@ partial_string_tail(String, Tail) :-
|
|||||||
|
|
||||||
call_nth(Goal, N) :-
|
call_nth(Goal, N) :-
|
||||||
can_be(integer, N),
|
can_be(integer, N),
|
||||||
( integer(N), N =< 0,
|
( integer(N) ->
|
||||||
domain_error(positive_integer, N, call_nth/2)
|
( N < 0 ->
|
||||||
|
domain_error(not_less_than_zero, N, call_nth/2)
|
||||||
|
; N > 0
|
||||||
|
)
|
||||||
; true
|
; true
|
||||||
),
|
),
|
||||||
setup_call_cleanup(call_nth_nesting(ID),
|
setup_call_cleanup(call_nth_nesting(C, ID),
|
||||||
( Goal,
|
( Goal,
|
||||||
retract(i_call_nth_nesting(ID,N0)),
|
bb_get(ID, N0),
|
||||||
N1 is N0 + 1,
|
N1 is N0 + 1,
|
||||||
asserta(i_call_nth_nesting(ID,N1)),
|
bb_put(ID, N1),
|
||||||
( integer(N) ->
|
( integer(N) ->
|
||||||
N = N1,
|
N = N1,
|
||||||
!
|
!
|
||||||
; N = N1
|
; N = N1
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
( retract(i_call_nth_nesting(ID,_)),
|
( bb_get(i_call_nth_counter, C) ->
|
||||||
retract(i_call_nth_counter(ID))
|
C1 is C - 1,
|
||||||
|
bb_put(i_call_nth_counter, C1)
|
||||||
|
; true
|
||||||
)).
|
)).
|
||||||
|
|
||||||
call_nth_nesting(ID) :-
|
call_nth_nesting(C, ID) :-
|
||||||
( i_call_nth_counter(ID0) ->
|
( bb_get(i_call_nth_counter, C0) ->
|
||||||
ID is ID0 + 1
|
C is C0 + 1
|
||||||
; ID = 0
|
; C = 0
|
||||||
),
|
),
|
||||||
asserta(i_call_nth_nesting(ID, 0)),
|
number_chars(C, Cs),
|
||||||
asserta(i_call_nth_counter(ID)).
|
atom_chars(Atom, Cs),
|
||||||
|
atom_concat(i_call_nth_nesting_, Atom, ID),
|
||||||
|
bb_put(ID, 0),
|
||||||
|
bb_put(i_call_nth_counter, C).
|
||||||
|
|
||||||
|
|
||||||
copy_term_nat(Source, Dest) :-
|
copy_term_nat(Source, Dest) :-
|
||||||
'$copy_term_without_attr_vars'(Source, Dest).
|
'$copy_term_without_attr_vars'(Source, Dest).
|
||||||
|
|
||||||
|
|
||||||
|
asserta(Module, (Head :- Body)) :-
|
||||||
|
!,
|
||||||
|
'$asserta'(Module, Head, Body).
|
||||||
|
asserta(Module, Fact) :-
|
||||||
|
'$asserta'(Module, Fact, true).
|
||||||
|
|
||||||
|
assertz(Module, (Head :- Body)) :-
|
||||||
|
!,
|
||||||
|
'$assertz'(Module, Head, Body).
|
||||||
|
assertz(Module, Fact) :-
|
||||||
|
'$assertz'(Module, Fact, true).
|
||||||
|
|
||||||
|
|||||||
125
src/lib/lists.pl
125
src/lib/lists.pl
@@ -1,7 +1,7 @@
|
|||||||
:- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5,
|
:- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5,
|
||||||
memberchk/2, reverse/2, length/2, maplist/2,
|
memberchk/2, reverse/2, length/2, maplist/2,
|
||||||
maplist/3, maplist/4, maplist/5, maplist/6,
|
maplist/3, maplist/4, maplist/5, maplist/6,
|
||||||
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
|
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3, nth0/4, nth1/3, nth1/4,
|
||||||
sum_list/2, transpose/2, list_to_set/2, list_max/2,
|
sum_list/2, transpose/2, list_to_set/2, list_max/2,
|
||||||
list_min/2, permutation/2]).
|
list_min/2, permutation/2]).
|
||||||
|
|
||||||
@@ -50,13 +50,20 @@
|
|||||||
:- meta_predicate foldl(3, ?, ?, ?).
|
:- meta_predicate foldl(3, ?, ?, ?).
|
||||||
:- meta_predicate foldl(4, ?, ?, ?, ?).
|
:- meta_predicate foldl(4, ?, ?, ?, ?).
|
||||||
|
|
||||||
|
:- use_module(library(error)).
|
||||||
|
|
||||||
|
:- meta_predicate(resource_error(+,:)).
|
||||||
|
|
||||||
|
resource_error(Resource, Context) :-
|
||||||
|
throw(error(resource_error(Resource), Context)).
|
||||||
|
|
||||||
length(Xs0, N) :-
|
length(Xs0, N) :-
|
||||||
'$skip_max_list'(M, N, Xs0,Xs),
|
'$skip_max_list'(M, N, Xs0,Xs),
|
||||||
!,
|
!,
|
||||||
( Xs == [] -> N = M
|
( Xs == [] -> N = M
|
||||||
; nonvar(Xs) -> var(N), Xs = [_|_], throw(error(resource_error(finite_memory),length/2))
|
; nonvar(Xs) -> var(N), Xs = [_|_], resource_error(finite_memory,length/2)
|
||||||
; nonvar(N) -> R is N-M, length_rundown(Xs, R)
|
; nonvar(N) -> R is N-M, length_rundown(Xs, R)
|
||||||
; N == Xs -> throw(error(resource_error(finite_memory),length/2))
|
; N == Xs -> failingvarskip(Xs), resource_error(finite_memory,length/2)
|
||||||
; length_addendum(Xs, N, M)
|
; length_addendum(Xs, N, M)
|
||||||
).
|
).
|
||||||
length(_, N) :-
|
length(_, N) :-
|
||||||
@@ -65,16 +72,29 @@ length(_, N) :-
|
|||||||
length(_, N) :-
|
length(_, N) :-
|
||||||
type_error(integer, N, length/2).
|
type_error(integer, N, length/2).
|
||||||
|
|
||||||
|
length_rundown(Xs, 0) :- !, Xs = [].
|
||||||
|
length_rundown(Vs, N) :-
|
||||||
|
\+ \+ '$project_atts':copy_term(Vs,Vs,[]), % unconstrained
|
||||||
|
!,
|
||||||
|
'$det_length_rundown'(Vs, N).
|
||||||
|
length_rundown([_|Xs], N) :- % force unification
|
||||||
|
N1 is N-1,
|
||||||
|
length(Xs, N1). % maybe some new info on Xs
|
||||||
|
|
||||||
|
failingvarskip(Xs) :-
|
||||||
|
\+ \+ '$project_atts':copy_term(Xs,Xs,[]), % unconstrained
|
||||||
|
!.
|
||||||
|
failingvarskip([_|Xs0]) :- % force unification
|
||||||
|
'$skip_max_list'(_, _, Xs0,Xs),
|
||||||
|
( nonvar(Xs) -> Xs = [_|_]
|
||||||
|
; failingvarskip(Xs)
|
||||||
|
).
|
||||||
|
|
||||||
length_addendum([], N, N).
|
length_addendum([], N, N).
|
||||||
length_addendum([_|Xs], N, M) :-
|
length_addendum([_|Xs], N, M) :-
|
||||||
M1 is M + 1,
|
M1 is M + 1,
|
||||||
length_addendum(Xs, N, M1).
|
length_addendum(Xs, N, M1).
|
||||||
|
|
||||||
length_rundown(Xs, 0) :- !, Xs = [].
|
|
||||||
length_rundown([_|Xs], N) :-
|
|
||||||
N1 is N-1,
|
|
||||||
length_rundown(Xs, N1).
|
|
||||||
|
|
||||||
|
|
||||||
member(X, [X|_]).
|
member(X, [X|_]).
|
||||||
member(X, [_|Xs]) :- member(X, Xs).
|
member(X, [_|Xs]) :- member(X, Xs).
|
||||||
@@ -223,27 +243,82 @@ unify_same(E-V, Prev-Var, E-V) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
nth0(N, Es, E) :-
|
nth0(N, Es0, E) :-
|
||||||
can_be(integer, N),
|
nonvar(N),
|
||||||
can_be(list, Es),
|
'$skip_max_list'(Skip, N, Es0,Es1),
|
||||||
( integer(N) ->
|
!,
|
||||||
nth0_index(N, Es, E)
|
( Skip == N
|
||||||
; nth0_search(N, Es, E)
|
-> Es1 = [E|_]
|
||||||
|
; ( var(Es1) ; Es1 = [_|_] ) % a partial or infinite list
|
||||||
|
-> R is N-Skip,
|
||||||
|
skipn(R,Es1,Es2),
|
||||||
|
Es2 = [E|_]
|
||||||
).
|
).
|
||||||
|
nth0(N, Es0, E) :-
|
||||||
|
can_be(not_less_than_zero, N),
|
||||||
|
Es0 = [E0|Es1],
|
||||||
|
nth0_el(0,N, E0,E, Es1).
|
||||||
|
|
||||||
nth0_index(0, [E|_], E) :- !.
|
skipn(N0, Es0,Es) :-
|
||||||
nth0_index(N, [_|Es], E) :-
|
N0>0,
|
||||||
N > 0,
|
!, % should not be necessary #1028
|
||||||
N1 is N - 1,
|
N1 is N0-1,
|
||||||
nth0_index(N1, Es, E).
|
Es0 = [_|Es1],
|
||||||
|
skipn(N1, Es1,Es).
|
||||||
|
skipn(0, Es,Es).
|
||||||
|
|
||||||
nth0_search(N, Es, E) :-
|
nth0_el(N0,N, E0,E, Es0) :-
|
||||||
nth0_search(0, N, Es, E).
|
Es0 == [],
|
||||||
|
!, % indexing
|
||||||
|
N0 = N,
|
||||||
|
E0 = E.
|
||||||
|
nth0_el(N,N, E,E, _).
|
||||||
|
nth0_el(N0,N, _,E, [E0|Es0]) :-
|
||||||
|
N1 is N0+1,
|
||||||
|
nth0_el(N1,N, E0,E, Es0).
|
||||||
|
|
||||||
nth0_search(N, N, [E|_], E).
|
nth1(N, Es0, E) :-
|
||||||
nth0_search(N0, N, [_|Es], E) :-
|
N \== 0,
|
||||||
N1 is N0 + 1,
|
nth0(N, [_|Es0], E),
|
||||||
nth0_search(N1, N, Es, E).
|
N \== 0.
|
||||||
|
|
||||||
|
skipn(N0, Es0,Es, Xs0,Xs) :-
|
||||||
|
N0>0,
|
||||||
|
!, % should not be necessary #1028
|
||||||
|
N1 is N0-1,
|
||||||
|
Es0 = [E|Es1],
|
||||||
|
Xs0 = [E|Xs1],
|
||||||
|
skipn(N1, Es1,Es, Xs1,Xs).
|
||||||
|
skipn(0, Es,Es, Xs,Xs).
|
||||||
|
|
||||||
|
nth0(N, Es0, E, Es) :-
|
||||||
|
integer(N),
|
||||||
|
N >= 0,
|
||||||
|
!,
|
||||||
|
skipn(N, Es0,Es1, Es,Es2),
|
||||||
|
Es1 = [E|Es2].
|
||||||
|
nth0(N, Es0, E, Es) :-
|
||||||
|
can_be(not_less_than_zero, N),
|
||||||
|
Es0 = [E0|Es1],
|
||||||
|
nth0_elx(0,N, E0,E, Es1, Es).
|
||||||
|
|
||||||
|
nth0_elx(N0,N, E0,E, Es0, Es) :-
|
||||||
|
Es0 == [],
|
||||||
|
!,
|
||||||
|
N0 = N,
|
||||||
|
E0 = E,
|
||||||
|
Es0 = Es.
|
||||||
|
nth0_elx(N,N, E,E, Es, Es).
|
||||||
|
nth0_elx(N0,N, E0,E, [E1|Es0], [E0|Es]) :-
|
||||||
|
N1 is N0+1,
|
||||||
|
nth0_elx(N1,N, E1,E, Es0, Es).
|
||||||
|
|
||||||
|
% p.p.8.5
|
||||||
|
|
||||||
|
nth1(N, Es0, E, Es) :-
|
||||||
|
N \== 0,
|
||||||
|
nth0(N, [_|Es0], E, [_|Es]),
|
||||||
|
N \== 0.
|
||||||
|
|
||||||
|
|
||||||
list_max([N|Ns], Max) :-
|
list_max([N|Ns], Max) :-
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
map_list_to_pairs/3]).
|
map_list_to_pairs/3]).
|
||||||
|
|
||||||
|
|
||||||
:- meta_predicate map_list_to_pairs(0, ?, ?).
|
:- meta_predicate map_list_to_pairs(2, ?, ?).
|
||||||
|
|
||||||
pairs_keys_values([], [], []).
|
pairs_keys_values([], [], []).
|
||||||
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
|
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
Our goal is to encourage the use of definite clause grammars (DCGs)
|
Our goal is to encourage the use of definite clause grammars (DCGs)
|
||||||
for describing strings. The predicates phrase_from_file/[2,3],
|
for describing strings. The predicates phrase_from_file/[2,3],
|
||||||
phrase_to_file/2 and phrase_to_stream/2 let us apply DCGs transparently
|
phrase_to_file/[2,3] and phrase_to_stream/2 let us apply DCGs
|
||||||
to files and streams, and therefore decouple side-effects from
|
transparently to files and streams, and therefore decouple side-effects
|
||||||
declarative descriptions.
|
from declarative descriptions.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
:- module(pio, [phrase_from_file/2,
|
:- module(pio, [phrase_from_file/2,
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
:- meta_predicate(phrase_from_file(2, ?)).
|
:- meta_predicate(phrase_from_file(2, ?)).
|
||||||
:- meta_predicate(phrase_from_file(2, ?, ?)).
|
:- meta_predicate(phrase_from_file(2, ?, ?)).
|
||||||
:- meta_predicate(phrase_to_file(2, ?)).
|
:- meta_predicate(phrase_to_file(2, ?)).
|
||||||
|
:- meta_predicate(phrase_to_file(2, ?, ?)).
|
||||||
:- meta_predicate(phrase_to_stream(2, ?)).
|
:- meta_predicate(phrase_to_stream(2, ?)).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
@@ -90,7 +91,7 @@ phrase_to_stream(GRBody, Stream) :-
|
|||||||
must_be(chars, Cs),
|
must_be(chars, Cs),
|
||||||
( stream_property(Stream, type(binary)) ->
|
( stream_property(Stream, type(binary)) ->
|
||||||
( '$first_non_octet'(Cs, N) ->
|
( '$first_non_octet'(Cs, N) ->
|
||||||
domain_error(byte_char, N, phrase_to_stream/2)
|
domain_error(octet_character, N, phrase_to_stream/2)
|
||||||
; true
|
; true
|
||||||
)
|
)
|
||||||
; true
|
; true
|
||||||
|
|||||||
@@ -30,13 +30,10 @@ non(false, true).
|
|||||||
|
|
||||||
:- meta_predicate(tfilter(2, ?, ?)).
|
:- meta_predicate(tfilter(2, ?, ?)).
|
||||||
|
|
||||||
tfilter(C_2, Es, Fs) :-
|
tfilter(_, [], []).
|
||||||
i_tfilter(Es, C_2, Fs).
|
tfilter(C_2, [E|Es], Fs0) :-
|
||||||
|
|
||||||
i_tfilter([], _, []).
|
|
||||||
i_tfilter([E|Es], C_2, Fs0) :-
|
|
||||||
if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs),
|
if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs),
|
||||||
i_tfilter(Es, C_2, Fs).
|
tfilter(C_2, Es, Fs).
|
||||||
|
|
||||||
:- meta_predicate(tpartition(2, ?, ?, ?)).
|
:- meta_predicate(tpartition(2, ?, ?, ?)).
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Predicates for parsing HTML and XML documents.
|
Predicates for parsing HTML and XML documents.
|
||||||
Written June 2020 by Markus Triska (triska@metalevel.at)
|
Written 2020-2022 by Markus Triska (triska@metalevel.at)
|
||||||
Part of Scryer Prolog.
|
Part of Scryer Prolog.
|
||||||
|
|
||||||
Currently, two predicates are provided:
|
Currently, two predicates are provided:
|
||||||
@@ -10,16 +10,18 @@
|
|||||||
|
|
||||||
These predicates parse HTML and XML documents, respectively.
|
These predicates parse HTML and XML documents, respectively.
|
||||||
|
|
||||||
Source must be a stream, specified as stream(S), or a file,
|
Source must be one of:
|
||||||
specified as file(Name), where Name is a list of characters, or a
|
|
||||||
list of characters with the document contents.
|
- a list of characters with the document contents
|
||||||
|
- stream(S), specifying a stream S from which to read the content
|
||||||
|
- file(Name), where Name is a list of characters specifying a file name.
|
||||||
|
|
||||||
Es is unified with the abstract syntax tree of the parsed document,
|
Es is unified with the abstract syntax tree of the parsed document,
|
||||||
represented as a list of elements where each is of the form:
|
represented as a list of elements where each is of the form:
|
||||||
|
|
||||||
* a list of characters, representing text
|
* a list of characters, representing text
|
||||||
* element(Name, Attrs, Children)
|
* element(Name, Attrs, Children)
|
||||||
- Name is the name of the tag
|
- Name, an atom, is the name of the tag
|
||||||
- Attrs is a list of Key=Value pairs:
|
- Attrs is a list of Key=Value pairs:
|
||||||
Key is an atom, and Value is a list of characters
|
Key is an atom, and Value is a list of characters
|
||||||
- Children is a list of elements as specified here.
|
- Children is a list of elements as specified here.
|
||||||
@@ -61,21 +63,32 @@
|
|||||||
:- use_module(library(charsio)).
|
:- use_module(library(charsio)).
|
||||||
|
|
||||||
load_html(Source, Es, Options) :-
|
load_html(Source, Es, Options) :-
|
||||||
|
must_be_source(Source, load_html/3),
|
||||||
|
must_be(list, Options),
|
||||||
load_structure_(Source, Es, Options, html).
|
load_structure_(Source, Es, Options, html).
|
||||||
load_xml(Source, Es, Options) :-
|
load_xml(Source, Es, Options) :-
|
||||||
|
must_be_source(Source, load_xml/3),
|
||||||
|
must_be(list, Options),
|
||||||
load_structure_(Source, Es, Options, xml).
|
load_structure_(Source, Es, Options, xml).
|
||||||
|
|
||||||
|
must_be_source(Source, Context) :-
|
||||||
|
( var(Source) -> instantiation_error(Context)
|
||||||
|
; is_sgml_source(Source) -> true
|
||||||
|
; domain_error(sgml_source, Source, Context)
|
||||||
|
).
|
||||||
|
|
||||||
|
is_sgml_source(file(Fs)) :- must_be(chars, Fs).
|
||||||
|
is_sgml_source(stream(_)).
|
||||||
|
is_sgml_source([]).
|
||||||
|
is_sgml_source([C|Cs]) :- must_be(chars, [C|Cs]).
|
||||||
|
|
||||||
load_structure_([], [], _, _).
|
load_structure_([], [], _, _).
|
||||||
load_structure_([C|Cs], [E], Options, What) :-
|
load_structure_([C|Cs], [E], Options, What) :-
|
||||||
load_(What, [C|Cs], E, Options).
|
load_(What, [C|Cs], E, Options).
|
||||||
load_structure_(file(Fs), [E], Options, What) :-
|
load_structure_(file(Fs), [E], Options, What) :-
|
||||||
must_be(list, Options),
|
once(phrase_from_file(seq(Cs), Fs)),
|
||||||
must_be(list, Fs),
|
|
||||||
atom_chars(File, Fs),
|
|
||||||
once(phrase_from_file(seq(Cs), File)),
|
|
||||||
load_(What, Cs, E, Options).
|
load_(What, Cs, E, Options).
|
||||||
load_structure_(stream(Stream), [E], Options, What) :-
|
load_structure_(stream(Stream), [E], Options, What) :-
|
||||||
must_be(list, Options),
|
|
||||||
get_n_chars(Stream, _, Cs),
|
get_n_chars(Stream, _, Cs),
|
||||||
load_(What, Cs, E, Options).
|
load_(What, Cs, E, Options).
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,8 @@
|
|||||||
:- module(si, [atom_si/1,
|
:- module(si, [atom_si/1,
|
||||||
integer_si/1,
|
integer_si/1,
|
||||||
atomic_si/1,
|
atomic_si/1,
|
||||||
list_si/1]).
|
list_si/1,
|
||||||
|
chars_si/1]).
|
||||||
|
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
|
|
||||||
@@ -42,6 +43,16 @@ integer_si(I) :-
|
|||||||
atomic_si(AC) :-
|
atomic_si(AC) :-
|
||||||
functor(AC,_,0).
|
functor(AC,_,0).
|
||||||
|
|
||||||
list_si(L) :-
|
% list_si(L) :-
|
||||||
\+ \+ length(L, _),
|
% \+ \+ length(L, _),
|
||||||
sort(L, _).
|
% sort(L, _).
|
||||||
|
|
||||||
|
list_si(L0) :-
|
||||||
|
'$skip_max_list'(_,_, L0,L),
|
||||||
|
( nonvar(L) -> L = []
|
||||||
|
; throw(error(instantiation_error, list_si/1))
|
||||||
|
).
|
||||||
|
|
||||||
|
chars_si(Cs) :-
|
||||||
|
list_si(Cs),
|
||||||
|
'$is_partial_string'(Cs).
|
||||||
|
|||||||
1379
src/lib/simplex.pl
Normal file
1379
src/lib/simplex.pl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -67,7 +67,7 @@ table_and_status_for_variant(V,T,S) :-
|
|||||||
tbd_table_status(T,S).
|
tbd_table_status(T,S).
|
||||||
|
|
||||||
|
|
||||||
:- meta_predicate start_tabling(?, 0).
|
:- meta_predicate start_tabling(?, :).
|
||||||
|
|
||||||
start_tabling(Wrapper,Worker) :-
|
start_tabling(Wrapper,Worker) :-
|
||||||
put_new_trie_table_link,
|
put_new_trie_table_link,
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ report_time(ID) :-
|
|||||||
time_state(ID, T0),
|
time_state(ID, T0),
|
||||||
'$cpu_now'(T),
|
'$cpu_now'(T),
|
||||||
Time is T - T0,
|
Time is T - T0,
|
||||||
( bb_get('$first_answer', true) ->
|
( bb_get('$answer_count', 0) ->
|
||||||
Pre = " ", Post = ""
|
Pre = " ", Post = ""
|
||||||
; Pre = "", Post = " "
|
; Pre = "", Post = " "
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -26,22 +26,22 @@
|
|||||||
|
|
||||||
:- use_module(library(http/http_open)).
|
:- use_module(library(http/http_open)).
|
||||||
:- use_module(library(sgml)).
|
:- use_module(library(sgml)).
|
||||||
:- use_module(library(lists)).
|
|
||||||
:- use_module(library(xpath)).
|
:- use_module(library(xpath)).
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
|
||||||
link_to_pl_file(File) :-
|
link_to_pl_file(File) :-
|
||||||
http_open("https://github.com/mthom/scryer-prolog", S, []),
|
http_open("https://github.com/mthom/scryer-prolog", S, []),
|
||||||
load_html(stream(S), DOM, []),
|
load_html(stream(S), DOM, []),
|
||||||
xpath(DOM, //a(@href), File),
|
xpath(DOM, //a(@href), File),
|
||||||
append(_, ".pl", File).
|
phrase((...,".pl"), File).
|
||||||
|
|
||||||
Yielding:
|
Yielding:
|
||||||
|
|
||||||
?- link_to_pl_file(File).
|
?- link_to_pl_file(File).
|
||||||
%@ File = "/mthom/scryer-prolog/blob/master/src/lib/tabling.pl"
|
%@ File = "/mthom/scryer-prolog/blob/master/src/lib/dcgs.pl"
|
||||||
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/dif.pl"
|
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/pio.pl"
|
||||||
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/freeze.pl"
|
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/tabling.pl"
|
||||||
%@ ; ...
|
%@ ; ... .
|
||||||
|
|
||||||
Parts of the original functionality may not yet work. Please
|
Parts of the original functionality may not yet work. Please
|
||||||
consider such parts opportunities for improvements, and file
|
consider such parts opportunities for improvements, and file
|
||||||
|
|||||||
1829
src/loader.pl
1829
src/loader.pl
File diff suppressed because it is too large
Load Diff
16
src/machine/args.rs
Normal file
16
src/machine/args.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
use std::collections::BTreeSet;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MachineArgs {
|
||||||
|
pub add_history: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MachineArgs {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let args: BTreeSet<String> = env::args().collect();
|
||||||
|
Self {
|
||||||
|
add_history: !args.contains("--no-add-history"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -82,16 +82,6 @@ fn numerical_type_error(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sign(n: Number) -> Number {
|
|
||||||
if n.is_positive() {
|
|
||||||
Number::Fixnum(Fixnum::build_with(1))
|
|
||||||
} else if n.is_negative() {
|
|
||||||
Number::Fixnum(Fixnum::build_with(-1))
|
|
||||||
} else {
|
|
||||||
Number::Fixnum(Fixnum::build_with(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn isize_gcd(n1: isize, n2: isize) -> Option<isize> {
|
fn isize_gcd(n1: isize, n2: isize) -> Option<isize> {
|
||||||
if n1 == 0 {
|
if n1 == 0 {
|
||||||
return n2.checked_abs().map(|n| n as isize);
|
return n2.checked_abs().map(|n| n as isize);
|
||||||
@@ -291,8 +281,8 @@ pub(crate) fn div(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn float_pow(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
|
pub(crate) fn float_pow(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
|
||||||
let f1 = result_f(&n1, rnd_f);
|
let f1 = result_f(&n1);
|
||||||
let f2 = result_f(&n2, rnd_f);
|
let f2 = result_f(&n2);
|
||||||
|
|
||||||
let stub_gen = || {
|
let stub_gen = || {
|
||||||
let pow_atom = atom!("**");
|
let pow_atom = atom!("**");
|
||||||
@@ -302,7 +292,7 @@ pub(crate) fn float_pow(n1: Number, n2: Number) -> Result<Number, MachineStubGen
|
|||||||
let f1 = try_numeric_result!(f1, stub_gen)?;
|
let f1 = try_numeric_result!(f1, stub_gen)?;
|
||||||
let f2 = try_numeric_result!(f2, stub_gen)?;
|
let f2 = try_numeric_result!(f2, stub_gen)?;
|
||||||
|
|
||||||
let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f);
|
let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))));
|
||||||
|
|
||||||
Ok(Number::Float(OrderedFloat(try_numeric_result!(
|
Ok(Number::Float(OrderedFloat(try_numeric_result!(
|
||||||
result, stub_gen
|
result, stub_gen
|
||||||
@@ -400,7 +390,6 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
|
|||||||
pub(crate) fn pow(n1: Number, n2: Number, culprit: Atom) -> Result<Number, MachineStubGen> {
|
pub(crate) fn pow(n1: Number, n2: Number, culprit: Atom) -> Result<Number, MachineStubGen> {
|
||||||
if n2.is_negative() && n1.is_zero() {
|
if n2.is_negative() && n1.is_zero() {
|
||||||
let stub_gen = move || functor_stub(culprit, 2);
|
let stub_gen = move || functor_stub(culprit, 2);
|
||||||
|
|
||||||
return Err(undefined_eval_error(stub_gen));
|
return Err(undefined_eval_error(stub_gen));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +403,7 @@ pub(crate) fn float(n: Number) -> Result<f64, MachineStubGen> {
|
|||||||
functor_stub(is_atom, 2)
|
functor_stub(is_atom, 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
try_numeric_result!(result_f(&n, rnd_f), stub_gen)
|
try_numeric_result!(result_f(&n), stub_gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -430,8 +419,8 @@ where
|
|||||||
functor_stub(is_atom, 2)
|
functor_stub(is_atom, 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?;
|
let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
|
||||||
let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f);
|
let f1 = result_f(&Number::Float(OrderedFloat(f(f1))));
|
||||||
|
|
||||||
try_numeric_result!(f1, stub_gen)
|
try_numeric_result!(f1, stub_gen)
|
||||||
}
|
}
|
||||||
@@ -472,8 +461,8 @@ pub(crate) fn max(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
|
|||||||
functor_stub(max_atom, 2)
|
functor_stub(max_atom, 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?;
|
let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
|
||||||
let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?;
|
let f2 = try_numeric_result!(result_f(&n2), stub_gen)?;
|
||||||
|
|
||||||
Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2))))
|
Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2))))
|
||||||
}
|
}
|
||||||
@@ -516,8 +505,8 @@ pub(crate) fn min(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
|
|||||||
functor_stub(min_atom, 2)
|
functor_stub(min_atom, 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?;
|
let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
|
||||||
let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?;
|
let f2 = try_numeric_result!(result_f(&n2), stub_gen)?;
|
||||||
|
|
||||||
Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2))))
|
Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2))))
|
||||||
}
|
}
|
||||||
@@ -803,7 +792,8 @@ pub(crate) fn xor(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
|
|||||||
(Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
|
(Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
|
||||||
Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
|
Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
|
||||||
}
|
}
|
||||||
_ => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
|
(n1, Number::Integer(_)) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
|
||||||
|
_ => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1108,35 +1098,43 @@ impl MachineState {
|
|||||||
|
|
||||||
pub(crate) fn arith_eval_by_metacall(&mut self, value: HeapCellValue) -> Result<Number, MachineStub> {
|
pub(crate) fn arith_eval_by_metacall(&mut self, value: HeapCellValue) -> Result<Number, MachineStub> {
|
||||||
let stub_gen = || functor_stub(atom!("is"), 2);
|
let stub_gen = || functor_stub(atom!("is"), 2);
|
||||||
let mut iter = stackless_post_order_iter(&mut self.heap, value);
|
let mut iter = stackful_post_order_iter(&mut self.heap, value);
|
||||||
|
|
||||||
while let Some(value) = iter.next() {
|
while let Some(value) = iter.next() {
|
||||||
if value.is_forwarded() {
|
if value.get_forwarding_bit() {
|
||||||
|
std::mem::drop(iter);
|
||||||
|
|
||||||
let (name, arity) = read_heap_cell!(value,
|
let (name, arity) = read_heap_cell!(value,
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
(name, arity)
|
(name, arity)
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Lis | HeapCellValueTag::PStr) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
cell_as_atom_cell!(self.heap[s]).get_name_and_arity()
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Lis | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset |
|
||||||
|
HeapCellValueTag::PStrLoc) => {
|
||||||
(atom!("."), 2)
|
(atom!("."), 2)
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
|
||||||
|
let err = self.instantiation_error();
|
||||||
|
return Err(self.error_form(err, stub_gen()));
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
std::mem::drop(iter);
|
|
||||||
|
|
||||||
let evaluable_error = self.evaluable_error(name, arity);
|
let evaluable_error = self.evaluable_error(name, arity);
|
||||||
let stub = stub_gen();
|
return Err(self.error_form(evaluable_error, stub_gen()));
|
||||||
|
|
||||||
return Err(self.error_form(evaluable_error, stub));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let value = unmark_cell_bits!(value);
|
||||||
|
|
||||||
read_heap_cell!(value,
|
read_heap_cell!(value,
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
if arity == 2 {
|
if arity == 2 {
|
||||||
let a1 = self.interms.pop().unwrap();
|
|
||||||
let a2 = self.interms.pop().unwrap();
|
let a2 = self.interms.pop().unwrap();
|
||||||
|
let a1 = self.interms.pop().unwrap();
|
||||||
|
|
||||||
match name {
|
match name {
|
||||||
atom!("+") => self.interms.push(drop_iter_on_err!(
|
atom!("+") => self.interms.push(drop_iter_on_err!(
|
||||||
@@ -1184,7 +1182,7 @@ impl MachineState {
|
|||||||
|
|
||||||
let result = arena_alloc!(
|
let result = arena_alloc!(
|
||||||
drop_iter_on_err!(self, iter, rdiv(r1, r2)),
|
drop_iter_on_err!(self, iter, rdiv(r1, r2)),
|
||||||
self.arena
|
&mut self.arena
|
||||||
);
|
);
|
||||||
|
|
||||||
self.interms.push(Number::Rational(result));
|
self.interms.push(Number::Rational(result));
|
||||||
@@ -1278,7 +1276,7 @@ impl MachineState {
|
|||||||
atom!("\\") => self.interms.push(
|
atom!("\\") => self.interms.push(
|
||||||
drop_iter_on_err!(self, iter, bitwise_complement(a1, &mut self.arena))
|
drop_iter_on_err!(self, iter, bitwise_complement(a1, &mut self.arena))
|
||||||
),
|
),
|
||||||
atom!("sign") => self.interms.push(sign(a1)),
|
atom!("sign") => self.interms.push(a1.sign()),
|
||||||
_ => {
|
_ => {
|
||||||
let evaluable_stub = functor_stub(name, 1);
|
let evaluable_stub = functor_stub(name, 1);
|
||||||
std::mem::drop(iter);
|
std::mem::drop(iter);
|
||||||
@@ -1324,7 +1322,7 @@ impl MachineState {
|
|||||||
self.interms.push(Number::Fixnum(n));
|
self.interms.push(Number::Fixnum(n));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::F64, fl) => {
|
(HeapCellValueTag::F64, fl) => {
|
||||||
self.interms.push(Number::Float(**fl));
|
self.interms.push(Number::Float(*fl));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Cons, ptr) => {
|
(HeapCellValueTag::Cons, ptr) => {
|
||||||
match_untyped_arena_ptr!(ptr,
|
match_untyped_arena_ptr!(ptr,
|
||||||
@@ -1334,9 +1332,6 @@ impl MachineState {
|
|||||||
(ArenaHeaderTag::Rational, r) => {
|
(ArenaHeaderTag::Rational, r) => {
|
||||||
self.interms.push(Number::Rational(r));
|
self.interms.push(Number::Rational(r));
|
||||||
}
|
}
|
||||||
(ArenaHeaderTag::F64, fl) => {
|
|
||||||
self.interms.push(Number::Float(*fl));
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
std::mem::drop(iter);
|
std::mem::drop(iter);
|
||||||
|
|
||||||
|
|||||||
@@ -28,11 +28,13 @@ call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
|
|||||||
sort(Modules0, Modules),
|
sort(Modules0, Modules),
|
||||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||||
|
|
||||||
|
error_handler(M, evaluation_error((M:verify_attributes)/3), []).
|
||||||
|
% error_handler(_, existence_error(procedure, verify_attributes/3), []).
|
||||||
|
|
||||||
verify_attrs([Module|Modules], Var, Value, [Module-Goals|ListOfGoalLists]) :-
|
verify_attrs([Module|Modules], Var, Value, [Module-Goals|ListOfGoalLists]) :-
|
||||||
catch(Module:verify_attributes(Var, Value, Goals),
|
catch(Module:verify_attributes(Var, Value, Goals),
|
||||||
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
|
error(E, verify_attributes/3),
|
||||||
Goals = []),
|
error_handler(Module, E, Goals)),
|
||||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||||
verify_attrs([], _, _, []).
|
verify_attrs([], _, _, []).
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::codegen::*;
|
use crate::codegen::*;
|
||||||
use crate::debray_allocator::*;
|
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::indexing::{merge_clause_index, remove_index};
|
use crate::indexing::{merge_clause_index, remove_index};
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
@@ -12,8 +11,6 @@ use crate::machine::term_stream::*;
|
|||||||
use crate::machine::*;
|
use crate::machine::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
|
|
||||||
use slice_deque::{sdeq, SliceDeque};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -49,13 +46,13 @@ pub(super) fn bootstrapping_compile(
|
|||||||
|
|
||||||
// throw errors if declaration or query found.
|
// throw errors if declaration or query found.
|
||||||
pub(super) fn compile_relation(
|
pub(super) fn compile_relation(
|
||||||
cg: &mut CodeGenerator<DebrayAllocator>,
|
cg: &mut CodeGenerator,
|
||||||
tl: &TopLevel,
|
tl: &TopLevel,
|
||||||
) -> Result<Code, CompilationError> {
|
) -> Result<Code, CompilationError> {
|
||||||
match tl {
|
match tl {
|
||||||
&TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
|
&TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
|
||||||
&TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses),
|
&TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses),
|
||||||
&TopLevel::Fact(ref fact, ..) => Ok(cg.compile_fact(fact)),
|
&TopLevel::Fact(ref fact, ..) => cg.compile_fact(fact),
|
||||||
&TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
|
&TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +86,7 @@ pub(super) fn compile_appendix(
|
|||||||
non_counted_bt,
|
non_counted_bt,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl, settings);
|
let mut cg = CodeGenerator::new(atom_tbl, settings);
|
||||||
|
|
||||||
let tl = queue.pop_front().unwrap();
|
let tl = queue.pop_front().unwrap();
|
||||||
let decl_code = compile_relation(&mut cg, &tl)?;
|
let decl_code = compile_relation(&mut cg, &tl)?;
|
||||||
@@ -409,7 +406,7 @@ fn merge_indexed_subsequences(
|
|||||||
|
|
||||||
*o = 0;
|
*o = 0;
|
||||||
|
|
||||||
return Some(IndexPtr::Index(outer_threaded_choice_instr_loc + 1));
|
return Some(IndexPtr::index(outer_threaded_choice_instr_loc + 1));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
@@ -425,8 +422,8 @@ fn delete_from_skeleton(
|
|||||||
target_pos: usize,
|
target_pos: usize,
|
||||||
retraction_info: &mut RetractionInfo,
|
retraction_info: &mut RetractionInfo,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let clause_index_info = skeleton.clauses.remove(target_pos);
|
let clause_index_info = skeleton.clauses.remove(target_pos).unwrap();
|
||||||
let clause_clause_loc = skeleton.core.clause_clause_locs.remove(target_pos);
|
let clause_clause_loc = skeleton.core.clause_clause_locs.remove(target_pos).unwrap();
|
||||||
|
|
||||||
if target_pos < skeleton.core.clause_assert_margin {
|
if target_pos < skeleton.core.clause_assert_margin {
|
||||||
skeleton.core.clause_assert_margin -= 1;
|
skeleton.core.clause_assert_margin -= 1;
|
||||||
@@ -788,7 +785,7 @@ fn remove_non_leading_clause(
|
|||||||
|
|
||||||
*o = 0;
|
*o = 0;
|
||||||
|
|
||||||
Some(IndexPtr::Index(preceding_choice_instr_loc + 1))
|
Some(IndexPtr::index(preceding_choice_instr_loc + 1))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
@@ -823,7 +820,7 @@ fn finalize_retract(
|
|||||||
retraction_info,
|
retraction_info,
|
||||||
&compilation_target,
|
&compilation_target,
|
||||||
key,
|
key,
|
||||||
&code_index,
|
code_index,
|
||||||
index_ptr,
|
index_ptr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -852,9 +849,9 @@ fn remove_leading_unindexed_clause(
|
|||||||
retraction_info,
|
retraction_info,
|
||||||
);
|
);
|
||||||
|
|
||||||
Some(IndexPtr::Index(index_ptr))
|
Some(IndexPtr::index(index_ptr))
|
||||||
} else {
|
} else {
|
||||||
Some(IndexPtr::DynamicUndefined)
|
Some(IndexPtr::dynamic_undefined())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -887,7 +884,7 @@ fn prepend_compiled_clause(
|
|||||||
global_clock_tick: usize,
|
global_clock_tick: usize,
|
||||||
) -> IndexPtr {
|
) -> IndexPtr {
|
||||||
let clause_loc = code.len();
|
let clause_loc = code.len();
|
||||||
let mut prepend_queue = sdeq![];
|
let mut prepend_queue = VecDeque::new();
|
||||||
|
|
||||||
let target_arg_num = skeleton.clauses[0].opt_arg_index_key.arg_num();
|
let target_arg_num = skeleton.clauses[0].opt_arg_index_key.arg_num();
|
||||||
let head_arg_num = skeleton.clauses[1].opt_arg_index_key.arg_num();
|
let head_arg_num = skeleton.clauses[1].opt_arg_index_key.arg_num();
|
||||||
@@ -995,7 +992,7 @@ fn prepend_compiled_clause(
|
|||||||
|
|
||||||
merge_clause_index(
|
merge_clause_index(
|
||||||
target_indexing_line,
|
target_indexing_line,
|
||||||
&mut skeleton.clauses,
|
skeleton.clauses.make_contiguous(),
|
||||||
&skeleton.core.retracted_dynamic_clauses,
|
&skeleton.core.retracted_dynamic_clauses,
|
||||||
clause_loc + 2, // == skeleton.clauses[0].clause_start
|
clause_loc + 2, // == skeleton.clauses[0].clause_start
|
||||||
AppendOrPrepend::Prepend,
|
AppendOrPrepend::Prepend,
|
||||||
@@ -1134,9 +1131,9 @@ fn prepend_compiled_clause(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if skeleton.core.is_dynamic {
|
if skeleton.core.is_dynamic {
|
||||||
IndexPtr::DynamicIndex(clause_loc)
|
IndexPtr::dynamic_index(clause_loc)
|
||||||
} else {
|
} else {
|
||||||
IndexPtr::Index(clause_loc)
|
IndexPtr::index(clause_loc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1189,7 +1186,7 @@ fn append_compiled_clause(
|
|||||||
|
|
||||||
merge_clause_index(
|
merge_clause_index(
|
||||||
target_indexing_line,
|
target_indexing_line,
|
||||||
&mut skeleton.clauses[lower_bound..],
|
&mut skeleton.clauses.make_contiguous()[lower_bound..],
|
||||||
&skeleton.core.retracted_dynamic_clauses,
|
&skeleton.core.retracted_dynamic_clauses,
|
||||||
clause_loc,
|
clause_loc,
|
||||||
AppendOrPrepend::Append,
|
AppendOrPrepend::Append,
|
||||||
@@ -1212,7 +1209,11 @@ fn append_compiled_clause(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if lower_bound == 0 && !skeleton.core.is_dynamic {
|
if lower_bound == 0 && !skeleton.core.is_dynamic {
|
||||||
code_ptr_opt = Some(target_pos_clause_start);
|
code_ptr_opt = Some(if index_loc < target_pos_clause_start {
|
||||||
|
index_loc
|
||||||
|
} else {
|
||||||
|
target_pos_clause_start
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1267,9 +1268,9 @@ fn append_compiled_clause(
|
|||||||
|
|
||||||
code_ptr_opt.map(|p| {
|
code_ptr_opt.map(|p| {
|
||||||
if skeleton.core.is_dynamic {
|
if skeleton.core.is_dynamic {
|
||||||
IndexPtr::DynamicIndex(p)
|
IndexPtr::dynamic_index(p)
|
||||||
} else {
|
} else {
|
||||||
IndexPtr::Index(p)
|
IndexPtr::index(p)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1305,8 +1306,8 @@ fn print_overwrite_warning(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match code_ptr {
|
match code_ptr.tag() {
|
||||||
IndexPtr::DynamicUndefined | IndexPtr::Undefined => return,
|
IndexPtrTag::DynamicUndefined | IndexPtrTag::Undefined => return,
|
||||||
_ if is_dynamic => return,
|
_ if is_dynamic => return,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -1338,12 +1339,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
term: Term,
|
term: Term,
|
||||||
settings: CodeGenSettings,
|
settings: CodeGenSettings,
|
||||||
) -> Result<StandaloneCompileResult, SessionError> {
|
) -> Result<StandaloneCompileResult, SessionError> {
|
||||||
let mut preprocessor = Preprocessor::new();
|
let mut preprocessor = Preprocessor::new(settings);
|
||||||
|
|
||||||
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
|
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
|
||||||
let queue = preprocessor.parse_queue(self)?;
|
let queue = preprocessor.parse_queue(self)?;
|
||||||
|
|
||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new(
|
let mut cg = CodeGenerator::new(
|
||||||
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
||||||
settings,
|
settings,
|
||||||
);
|
);
|
||||||
@@ -1378,7 +1379,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
let mut code_ptr = code_len;
|
let mut code_ptr = code_len;
|
||||||
|
|
||||||
let mut clauses = vec![];
|
let mut clauses = vec![];
|
||||||
let mut preprocessor = Preprocessor::new();
|
let mut preprocessor = Preprocessor::new(settings);
|
||||||
|
|
||||||
for term in predicates.predicates.drain(0..) {
|
for term in predicates.predicates.drain(0..) {
|
||||||
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
|
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
|
||||||
@@ -1386,7 +1387,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
let queue = preprocessor.parse_queue(self)?;
|
let queue = preprocessor.parse_queue(self)?;
|
||||||
|
|
||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new(
|
let mut cg = CodeGenerator::new(
|
||||||
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
||||||
settings,
|
settings,
|
||||||
);
|
);
|
||||||
@@ -1402,7 +1403,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
if settings.is_extensible {
|
if settings.is_extensible {
|
||||||
let mut clause_clause_locs = sdeq![];
|
let mut clause_clause_locs = VecDeque::new();
|
||||||
|
|
||||||
for clause_index_info in cg.skeleton.clauses.iter_mut() {
|
for clause_index_info in cg.skeleton.clauses.iter_mut() {
|
||||||
clause_index_info.clause_start += code_len;
|
clause_index_info.clause_start += code_len;
|
||||||
@@ -1430,7 +1431,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
skeleton
|
skeleton
|
||||||
.core
|
.core
|
||||||
.clause_clause_locs
|
.clause_clause_locs
|
||||||
.extend_from_slice(&clause_clause_locs[0..]);
|
.extend(&clause_clause_locs.make_contiguous()[0..]);
|
||||||
|
|
||||||
self.payload.retraction_info
|
self.payload.retraction_info
|
||||||
.push_record(RetractionRecord::SkeletonClauseTruncateBack(
|
.push_record(RetractionRecord::SkeletonClauseTruncateBack(
|
||||||
@@ -1443,7 +1444,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
cg.skeleton
|
cg.skeleton
|
||||||
.core
|
.core
|
||||||
.clause_clause_locs
|
.clause_clause_locs
|
||||||
.extend_from_slice(&clause_clause_locs[0..]);
|
.extend(&clause_clause_locs.make_contiguous()[0..]);
|
||||||
|
|
||||||
let skeleton = cg.skeleton;
|
let skeleton = cg.skeleton;
|
||||||
|
|
||||||
@@ -1470,16 +1471,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let index_ptr = if settings.is_dynamic() {
|
let index_ptr = if settings.is_dynamic() {
|
||||||
IndexPtr::DynamicIndex(code_ptr)
|
IndexPtr::dynamic_index(code_ptr)
|
||||||
} else {
|
} else {
|
||||||
IndexPtr::Index(code_ptr)
|
IndexPtr::index(code_ptr)
|
||||||
};
|
};
|
||||||
|
|
||||||
set_code_index(
|
set_code_index(
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload.retraction_info,
|
||||||
&predicates.compilation_target,
|
&predicates.compilation_target,
|
||||||
key,
|
key,
|
||||||
&code_index,
|
code_index,
|
||||||
index_ptr,
|
index_ptr,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1491,7 +1492,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
compilation_target: &CompilationTarget,
|
compilation_target: &CompilationTarget,
|
||||||
key: &PredicateKey,
|
key: &PredicateKey,
|
||||||
clause_clause_locs: SliceDeque<usize>,
|
mut clause_clause_locs: VecDeque<usize>,
|
||||||
) {
|
) {
|
||||||
let listing_src_file_name = self.listing_src_file_name();
|
let listing_src_file_name = self.listing_src_file_name();
|
||||||
|
|
||||||
@@ -1515,7 +1516,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
skeleton
|
skeleton
|
||||||
.clause_clause_locs
|
.clause_clause_locs
|
||||||
.extend_from_slice(&clause_clause_locs[0..]);
|
.extend(&clause_clause_locs.make_contiguous()[0..]);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let mut skeleton = LocalPredicateSkeleton::new();
|
let mut skeleton = LocalPredicateSkeleton::new();
|
||||||
@@ -1703,7 +1704,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
&mut self.payload.retraction_info,
|
&mut self.payload.retraction_info,
|
||||||
&compilation_target,
|
&compilation_target,
|
||||||
key,
|
key,
|
||||||
&code_index,
|
code_index,
|
||||||
new_code_ptr,
|
new_code_ptr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1744,7 +1745,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
&mut self.payload.retraction_info,
|
&mut self.payload.retraction_info,
|
||||||
&compilation_target,
|
&compilation_target,
|
||||||
key,
|
key,
|
||||||
&code_index,
|
code_index,
|
||||||
new_code_ptr,
|
new_code_ptr,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1869,7 +1870,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
skeleton.clauses[target_pos].clause_start;
|
skeleton.clauses[target_pos].clause_start;
|
||||||
|
|
||||||
let index_ptr_opt = if target_pos == 0 {
|
let index_ptr_opt = if target_pos == 0 {
|
||||||
Some(IndexPtr::Index(clause_loc))
|
Some(IndexPtr::index(clause_loc))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@@ -1968,7 +1969,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
code,
|
code,
|
||||||
later_indexing_loc,
|
later_indexing_loc,
|
||||||
0..target_pos - lower_bound,
|
0..target_pos - lower_bound,
|
||||||
&mut skeleton.clauses[lower_bound..],
|
&mut skeleton.clauses.make_contiguous()[lower_bound..],
|
||||||
&skeleton.core.retracted_dynamic_clauses,
|
&skeleton.core.retracted_dynamic_clauses,
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload.retraction_info,
|
||||||
);
|
);
|
||||||
@@ -1993,7 +1994,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
code,
|
code,
|
||||||
target_indexing_loc,
|
target_indexing_loc,
|
||||||
target_pos + 1 - lower_bound..skeleton.clauses.len() - lower_bound,
|
target_pos + 1 - lower_bound..skeleton.clauses.len() - lower_bound,
|
||||||
&mut skeleton.clauses[lower_bound..],
|
&mut skeleton.clauses.make_contiguous()[lower_bound..],
|
||||||
&skeleton.core.retracted_dynamic_clauses,
|
&skeleton.core.retracted_dynamic_clauses,
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload.retraction_info,
|
||||||
);
|
);
|
||||||
@@ -2192,15 +2193,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
{
|
{
|
||||||
Some(skeleton) if append_or_prepend.is_append() => {
|
Some(skeleton) if append_or_prepend.is_append() => {
|
||||||
let tail_num = skeleton.core.clause_clause_locs.len() - num_clause_predicates;
|
let tail_num = skeleton.core.clause_clause_locs.len() - num_clause_predicates;
|
||||||
skeleton.core.clause_clause_locs[tail_num..]
|
skeleton.core.clause_clause_locs.make_contiguous()[tail_num..]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
Some(skeleton) => skeleton.core.clause_clause_locs[0..num_clause_predicates]
|
Some(skeleton) => {
|
||||||
|
skeleton.core.clause_clause_locs.make_contiguous()[0..num_clause_predicates]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect()
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@@ -2381,13 +2384,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
match self.wam_prelude.indices.modules.get_mut(&filename) {
|
match self.wam_prelude.indices.modules.get_mut(&filename) {
|
||||||
Some(ref mut module) => {
|
Some(ref mut module) => {
|
||||||
let index_ptr = code_index.get();
|
let index_ptr = code_index.get();
|
||||||
let code_index = module.code_dir.entry(key).or_insert(code_index);
|
let code_index = module.code_dir.entry(key)
|
||||||
|
.or_insert(code_index)
|
||||||
|
.clone();
|
||||||
|
|
||||||
set_code_index(
|
set_code_index(
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload.retraction_info,
|
||||||
&CompilationTarget::Module(filename),
|
&CompilationTarget::Module(filename),
|
||||||
key,
|
key,
|
||||||
&code_index,
|
code_index,
|
||||||
index_ptr,
|
index_ptr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2415,3 +2420,54 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// standalone functions for compiling auxiliary goals used by expand_goal.
|
||||||
|
impl Machine {
|
||||||
|
pub(crate) fn get_or_insert_qualified_code_index(
|
||||||
|
&mut self,
|
||||||
|
module_name: HeapCellValue,
|
||||||
|
key: PredicateKey,
|
||||||
|
) -> CodeIndex {
|
||||||
|
let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(
|
||||||
|
self,
|
||||||
|
InlineTermStream {},
|
||||||
|
);
|
||||||
|
|
||||||
|
let module_name = if module_name.get_tag() == HeapCellValueTag::Atom {
|
||||||
|
cell_as_atom!(module_name)
|
||||||
|
} else {
|
||||||
|
atom!("user")
|
||||||
|
};
|
||||||
|
|
||||||
|
loader.get_or_insert_qualified_code_index(module_name, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn compile_standalone_clause(
|
||||||
|
&mut self,
|
||||||
|
term_loc: RegType,
|
||||||
|
vars: &[Term],
|
||||||
|
) -> Result<(), SessionError> {
|
||||||
|
let mut compile = || {
|
||||||
|
let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(
|
||||||
|
self,
|
||||||
|
InlineTermStream {},
|
||||||
|
);
|
||||||
|
|
||||||
|
let term = loader.read_term_from_heap(term_loc)?;
|
||||||
|
let clause = build_rule_body(vars, term);
|
||||||
|
|
||||||
|
let settings = CodeGenSettings {
|
||||||
|
global_clock_tick: None,
|
||||||
|
is_extensible: false,
|
||||||
|
non_counted_bt: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
loader.compile_standalone_clause(clause, settings)
|
||||||
|
};
|
||||||
|
|
||||||
|
let StandaloneCompileResult { clause_code, .. } = compile()?;
|
||||||
|
self.code.extend(clause_code.into_iter());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
|
use crate::machine::get_structure_index;
|
||||||
use crate::machine::stack::*;
|
use crate::machine::stack::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
@@ -248,6 +249,14 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
let hcv = self.target[addr + 1 + i];
|
let hcv = self.target[addr + 1 + i];
|
||||||
self.target.push(hcv);
|
self.target.push(hcv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let index_cell = self.target[addr + 1 + arity];
|
||||||
|
|
||||||
|
if get_structure_index(index_cell).is_some() {
|
||||||
|
// copy the index pointer trailing this
|
||||||
|
// inlined or expanded goal.
|
||||||
|
self.target.push(index_cell);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str, h) => {
|
(HeapCellValueTag::Str, h) => {
|
||||||
*self.value_at_scan() = str_loc_as_cell!(h);
|
*self.value_at_scan() = str_loc_as_cell!(h);
|
||||||
|
|||||||
@@ -57,19 +57,28 @@ impl MachineState {
|
|||||||
let a2 = self.registers[2];
|
let a2 = self.registers[2];
|
||||||
let a3 = self.registers[3];
|
let a3 = self.registers[3];
|
||||||
|
|
||||||
|
let check_atom = |machine_st: &mut MachineState, name: Atom, arity: usize| -> Result<(), MachineStub> {
|
||||||
|
match name {
|
||||||
|
atom!(">") | atom!("<") | atom!("=") if arity == 0 => {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let err = machine_st.domain_error(DomainErrorType::Order, a1);
|
||||||
|
Err(machine_st.error_form(err, stub_gen()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
read_heap_cell!(a1,
|
read_heap_cell!(a1,
|
||||||
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
check_atom(self, name, arity)?;
|
||||||
|
}
|
||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
.get_name_and_arity();
|
.get_name_and_arity();
|
||||||
|
|
||||||
match name {
|
check_atom(self, name, arity)?;
|
||||||
atom!(">") | atom!("<") | atom!("=") if arity == 2 => {
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let err = self.domain_error(DomainErrorType::Order, a1);
|
|
||||||
return Err(self.error_form(err, stub_gen()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
|
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
|
||||||
}
|
}
|
||||||
@@ -164,8 +173,7 @@ impl MachineState {
|
|||||||
match self.get_number(&at)? {
|
match self.get_number(&at)? {
|
||||||
Number::Fixnum(n) => self.unify_fixnum(n, n1),
|
Number::Fixnum(n) => self.unify_fixnum(n, n1),
|
||||||
Number::Float(n) => {
|
Number::Float(n) => {
|
||||||
// TODO: argghh.. allocate floats to their own area.
|
let n = float_alloc!(n.into_inner(), self.arena);
|
||||||
let n = arena_alloc!(n, &mut self.arena);
|
|
||||||
self.unify_f64(n, n1)
|
self.unify_f64(n, n1)
|
||||||
}
|
}
|
||||||
Number::Integer(n) => self.unify_big_int(n, n1),
|
Number::Integer(n) => self.unify_big_int(n, n1),
|
||||||
@@ -190,7 +198,7 @@ impl Machine {
|
|||||||
let value = self.machine_st.registers[2];
|
let value = self.machine_st.registers[2];
|
||||||
unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc));
|
unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc));
|
||||||
}
|
}
|
||||||
Err(ParserError::UnexpectedEOF) => {
|
Err(CompilationError::ParserError(ParserError::UnexpectedEOF)) => {
|
||||||
let value = self.machine_st.registers[2];
|
let value = self.machine_st.registers[2];
|
||||||
self.machine_st.unify_atom(atom!("end_of_file"), value);
|
self.machine_st.unify_atom(atom!("end_of_file"), value);
|
||||||
}
|
}
|
||||||
@@ -362,13 +370,19 @@ impl Machine {
|
|||||||
debug_assert!(arity == 0);
|
debug_assert!(arity == 0);
|
||||||
c
|
c
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str) => {
|
(HeapCellValueTag::Str, st) => {
|
||||||
s
|
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[st])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
match (name, arity) {
|
||||||
|
(atom!("."), 2) => l,
|
||||||
|
(_, 0) => c,
|
||||||
|
_ => s,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Cons, ptr) => {
|
(HeapCellValueTag::Cons, ptr) => {
|
||||||
match ptr.get_tag() {
|
match ptr.get_tag() {
|
||||||
ArenaHeaderTag::Rational | ArenaHeaderTag::Integer |
|
ArenaHeaderTag::Rational | ArenaHeaderTag::Integer => {
|
||||||
ArenaHeaderTag::F64 => {
|
|
||||||
c
|
c
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -418,20 +432,20 @@ impl Machine {
|
|||||||
Literal::Fixnum(n)
|
Literal::Fixnum(n)
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::F64, f) => {
|
(HeapCellValueTag::F64, f) => {
|
||||||
Literal::Float(f)
|
Literal::Float(f.as_offset())
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Atom, (atom, arity)) => {
|
(HeapCellValueTag::Atom, (atom, arity)) => {
|
||||||
debug_assert_eq!(arity, 0);
|
debug_assert_eq!(arity, 0);
|
||||||
Literal::Atom(atom)
|
Literal::Atom(atom)
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
Literal::Atom(cell_as_atom_cell!(self.machine_st.heap[s]).get_name())
|
||||||
|
}
|
||||||
(HeapCellValueTag::Cons, cons_ptr) => {
|
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||||
match_untyped_arena_ptr!(cons_ptr,
|
match_untyped_arena_ptr!(cons_ptr,
|
||||||
(ArenaHeaderTag::Rational, r) => {
|
(ArenaHeaderTag::Rational, r) => {
|
||||||
Literal::Rational(r)
|
Literal::Rational(r)
|
||||||
}
|
}
|
||||||
(ArenaHeaderTag::F64, f) => {
|
|
||||||
Literal::Float(F64Ptr(f))
|
|
||||||
}
|
|
||||||
(ArenaHeaderTag::Integer, n) => {
|
(ArenaHeaderTag::Integer, n) => {
|
||||||
Literal::Integer(n)
|
Literal::Integer(n)
|
||||||
}
|
}
|
||||||
@@ -603,6 +617,7 @@ impl Machine {
|
|||||||
&mut self.machine_st,
|
&mut self.machine_st,
|
||||||
try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen)
|
try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen)
|
||||||
);
|
);
|
||||||
|
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
}
|
}
|
||||||
&Instruction::Mul(ref a1, ref a2, t) => {
|
&Instruction::Mul(ref a1, ref a2, t) => {
|
||||||
@@ -681,7 +696,7 @@ impl Machine {
|
|||||||
|
|
||||||
self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!(
|
self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!(
|
||||||
try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)),
|
try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)),
|
||||||
self.machine_st.arena
|
&mut self.machine_st.arena
|
||||||
));
|
));
|
||||||
|
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
@@ -694,6 +709,7 @@ impl Machine {
|
|||||||
&mut self.machine_st,
|
&mut self.machine_st,
|
||||||
int_floor_div(n1, n2, &mut self.machine_st.arena)
|
int_floor_div(n1, n2, &mut self.machine_st.arena)
|
||||||
);
|
);
|
||||||
|
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
}
|
}
|
||||||
&Instruction::IDiv(ref a1, ref a2, t) => {
|
&Instruction::IDiv(ref a1, ref a2, t) => {
|
||||||
@@ -704,6 +720,7 @@ impl Machine {
|
|||||||
&mut self.machine_st,
|
&mut self.machine_st,
|
||||||
idiv(n1, n2, &mut self.machine_st.arena)
|
idiv(n1, n2, &mut self.machine_st.arena)
|
||||||
);
|
);
|
||||||
|
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
}
|
}
|
||||||
&Instruction::Abs(ref a1, t) => {
|
&Instruction::Abs(ref a1, t) => {
|
||||||
@@ -715,7 +732,7 @@ impl Machine {
|
|||||||
&Instruction::Sign(ref a1, t) => {
|
&Instruction::Sign(ref a1, t) => {
|
||||||
let n = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
|
let n = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
|
||||||
|
|
||||||
self.machine_st.interms[t - 1] = sign(n);
|
self.machine_st.interms[t - 1] = n.sign();
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
}
|
}
|
||||||
&Instruction::Neg(ref a1, t) => {
|
&Instruction::Neg(ref a1, t) => {
|
||||||
@@ -1004,23 +1021,14 @@ impl Machine {
|
|||||||
match self.find_living_dynamic_else(p + next_i) {
|
match self.find_living_dynamic_else(p + next_i) {
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
self.retry_me_else(next_i);
|
self.retry_me_else(next_i);
|
||||||
|
|
||||||
try_or_throw!(
|
|
||||||
self.machine_st,
|
|
||||||
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.trust_me();
|
self.trust_me();
|
||||||
|
|
||||||
try_or_throw!(
|
|
||||||
self.machine_st,
|
|
||||||
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.trust_me();
|
self.trust_me();
|
||||||
|
}
|
||||||
|
|
||||||
try_or_throw!(
|
try_or_throw!(
|
||||||
self.machine_st,
|
self.machine_st,
|
||||||
@@ -1029,7 +1037,6 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
}
|
}
|
||||||
@@ -1085,23 +1092,14 @@ impl Machine {
|
|||||||
match self.find_living_dynamic_else(p + next_i) {
|
match self.find_living_dynamic_else(p + next_i) {
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
self.retry_me_else(next_i);
|
self.retry_me_else(next_i);
|
||||||
|
|
||||||
try_or_throw!(
|
|
||||||
self.machine_st,
|
|
||||||
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.trust_me();
|
self.trust_me();
|
||||||
|
|
||||||
try_or_throw!(
|
|
||||||
self.machine_st,
|
|
||||||
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.trust_me();
|
self.trust_me();
|
||||||
|
}
|
||||||
|
|
||||||
try_or_throw!(
|
try_or_throw!(
|
||||||
self.machine_st,
|
self.machine_st,
|
||||||
@@ -1110,7 +1108,6 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
}
|
}
|
||||||
@@ -1148,17 +1145,7 @@ impl Machine {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
&Instruction::NeckCut => {
|
&Instruction::NeckCut => {
|
||||||
let b = self.machine_st.b;
|
self.machine_st.neck_cut();
|
||||||
let b0 = self.machine_st.b0;
|
|
||||||
|
|
||||||
if b > b0 {
|
|
||||||
self.machine_st.b = b0;
|
|
||||||
|
|
||||||
if b > self.machine_st.e {
|
|
||||||
self.machine_st.stack.truncate(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
}
|
}
|
||||||
&Instruction::GetLevel(r) => {
|
&Instruction::GetLevel(r) => {
|
||||||
@@ -1324,7 +1311,6 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
&Instruction::DefaultCallRead(_) => {
|
&Instruction::DefaultCallRead(_) => {
|
||||||
try_or_throw!(self.machine_st, self.read());
|
try_or_throw!(self.machine_st, self.read());
|
||||||
|
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
}
|
}
|
||||||
&Instruction::DefaultExecuteRead(_) => {
|
&Instruction::DefaultExecuteRead(_) => {
|
||||||
@@ -2380,6 +2366,16 @@ impl Machine {
|
|||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
|
||||||
|
.get_arity();
|
||||||
|
|
||||||
|
if arity == 0 {
|
||||||
|
self.machine_st.p += 1;
|
||||||
|
} else {
|
||||||
|
self.machine_st.backtrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
(HeapCellValueTag::Char) => {
|
(HeapCellValueTag::Char) => {
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
}
|
}
|
||||||
@@ -2399,6 +2395,16 @@ impl Machine {
|
|||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
|
||||||
|
.get_arity();
|
||||||
|
|
||||||
|
if arity == 0 {
|
||||||
|
self.machine_st.p = self.machine_st.cp;
|
||||||
|
} else {
|
||||||
|
self.machine_st.backtrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
(HeapCellValueTag::Char) => {
|
(HeapCellValueTag::Char) => {
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
}
|
}
|
||||||
@@ -2422,6 +2428,16 @@ impl Machine {
|
|||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
|
||||||
|
.get_arity();
|
||||||
|
|
||||||
|
if arity == 0 {
|
||||||
|
self.machine_st.p += 1;
|
||||||
|
} else {
|
||||||
|
self.machine_st.backtrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
}
|
}
|
||||||
@@ -2442,6 +2458,16 @@ impl Machine {
|
|||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
|
||||||
|
.get_arity();
|
||||||
|
|
||||||
|
if arity == 0 {
|
||||||
|
self.machine_st.p = self.machine_st.cp;
|
||||||
|
} else {
|
||||||
|
self.machine_st.backtrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
}
|
}
|
||||||
@@ -2451,10 +2477,21 @@ impl Machine {
|
|||||||
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
|
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
|
||||||
|
|
||||||
read_heap_cell!(d,
|
read_heap_cell!(d,
|
||||||
(HeapCellValueTag::Str | HeapCellValueTag::Lis |
|
(HeapCellValueTag::Lis |
|
||||||
HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
|
HeapCellValueTag::PStrLoc |
|
||||||
|
HeapCellValueTag::CStr) => {
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
|
||||||
|
.get_arity();
|
||||||
|
|
||||||
|
if arity > 0 {
|
||||||
|
self.machine_st.p += 1;
|
||||||
|
} else {
|
||||||
|
self.machine_st.backtrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
(HeapCellValueTag::Atom, (_name, arity)) => {
|
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||||
if arity > 0 {
|
if arity > 0 {
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
@@ -2471,10 +2508,21 @@ impl Machine {
|
|||||||
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
|
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
|
||||||
|
|
||||||
read_heap_cell!(d,
|
read_heap_cell!(d,
|
||||||
(HeapCellValueTag::Str | HeapCellValueTag::Lis |
|
(HeapCellValueTag::Lis |
|
||||||
HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
|
HeapCellValueTag::PStrLoc |
|
||||||
|
HeapCellValueTag::CStr) => {
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
|
||||||
|
.get_arity();
|
||||||
|
|
||||||
|
if arity > 0 {
|
||||||
|
self.machine_st.p = self.machine_st.cp;
|
||||||
|
} else {
|
||||||
|
self.machine_st.backtrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
(HeapCellValueTag::Atom, (_name, arity)) => {
|
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||||
if arity > 0 {
|
if arity > 0 {
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
@@ -2529,16 +2577,9 @@ impl Machine {
|
|||||||
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
|
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
|
||||||
|
|
||||||
match Number::try_from(d) {
|
match Number::try_from(d) {
|
||||||
Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => {
|
Ok(_) => {
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
}
|
}
|
||||||
Ok(Number::Rational(n)) => {
|
|
||||||
if n.denom() == &1 {
|
|
||||||
self.machine_st.p += 1;
|
|
||||||
} else {
|
|
||||||
self.machine_st.backtrack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
}
|
}
|
||||||
@@ -2548,16 +2589,9 @@ impl Machine {
|
|||||||
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
|
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
|
||||||
|
|
||||||
match Number::try_from(d) {
|
match Number::try_from(d) {
|
||||||
Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => {
|
Ok(_) => {
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
}
|
}
|
||||||
Ok(Number::Rational(n)) => {
|
|
||||||
if n.denom() == &1 {
|
|
||||||
self.machine_st.p = self.machine_st.cp;
|
|
||||||
} else {
|
|
||||||
self.machine_st.backtrack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
}
|
}
|
||||||
@@ -2784,6 +2818,19 @@ impl Machine {
|
|||||||
self.machine_st.s_offset = 0;
|
self.machine_st.s_offset = 0;
|
||||||
self.machine_st.mode = MachineMode::Read;
|
self.machine_st.mode = MachineMode::Read;
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
if name == atom!(".") && arity == 2 {
|
||||||
|
self.machine_st.s = HeapPtr::HeapCell(s+1);
|
||||||
|
self.machine_st.s_offset = 0;
|
||||||
|
self.machine_st.mode = MachineMode::Read;
|
||||||
|
} else {
|
||||||
|
self.machine_st.backtrack();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
(HeapCellValueTag::Lis, l) => {
|
(HeapCellValueTag::Lis, l) => {
|
||||||
self.machine_st.s = HeapPtr::HeapCell(l);
|
self.machine_st.s = HeapPtr::HeapCell(l);
|
||||||
self.machine_st.s_offset = 0;
|
self.machine_st.s_offset = 0;
|
||||||
@@ -2810,12 +2857,25 @@ impl Machine {
|
|||||||
let store_v = self.machine_st.store(deref_v);
|
let store_v = self.machine_st.store(deref_v);
|
||||||
|
|
||||||
read_heap_cell!(store_v,
|
read_heap_cell!(store_v,
|
||||||
(HeapCellValueTag::Str | HeapCellValueTag::Lis |
|
(HeapCellValueTag::Str |
|
||||||
HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar |
|
HeapCellValueTag::Lis |
|
||||||
HeapCellValueTag::StackVar | HeapCellValueTag::Var |
|
HeapCellValueTag::PStrLoc |
|
||||||
HeapCellValueTag::CStr) => {
|
HeapCellValueTag::CStr) => {
|
||||||
self.machine_st.match_partial_string(store_v, string, has_tail);
|
self.machine_st.match_partial_string(store_v, string, has_tail);
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::AttrVar |
|
||||||
|
HeapCellValueTag::StackVar |
|
||||||
|
HeapCellValueTag::Var) => {
|
||||||
|
let target_cell = self.machine_st.push_str_to_heap(
|
||||||
|
string.as_str(),
|
||||||
|
has_tail,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.machine_st.bind(
|
||||||
|
store_v.as_var().unwrap(),
|
||||||
|
target_cell,
|
||||||
|
);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
continue;
|
continue;
|
||||||
@@ -3527,7 +3587,10 @@ impl Machine {
|
|||||||
self.dynamic_module_resolution(arity - 2)
|
self.dynamic_module_resolution(arity - 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
try_or_throw!(self.machine_st, self.call_clause(module_name, key));
|
try_or_throw!(
|
||||||
|
self.machine_st,
|
||||||
|
self.call_clause(module_name, key)
|
||||||
|
);
|
||||||
|
|
||||||
if self.machine_st.fail {
|
if self.machine_st.fail {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
@@ -3539,7 +3602,10 @@ impl Machine {
|
|||||||
self.dynamic_module_resolution(arity - 2)
|
self.dynamic_module_resolution(arity - 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
try_or_throw!(self.machine_st, self.execute_clause(module_name, key));
|
try_or_throw!(
|
||||||
|
self.machine_st,
|
||||||
|
self.execute_clause(module_name, key)
|
||||||
|
);
|
||||||
|
|
||||||
if self.machine_st.fail {
|
if self.machine_st.fail {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
@@ -4059,14 +4125,6 @@ impl Machine {
|
|||||||
self.clean_up_block();
|
self.clean_up_block();
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
}
|
}
|
||||||
&Instruction::CallEraseBall(_) => {
|
|
||||||
self.erase_ball();
|
|
||||||
self.machine_st.p += 1;
|
|
||||||
}
|
|
||||||
&Instruction::ExecuteEraseBall(_) => {
|
|
||||||
self.erase_ball();
|
|
||||||
self.machine_st.p = self.machine_st.cp;
|
|
||||||
}
|
|
||||||
&Instruction::CallFail(_) | &Instruction::ExecuteFail(_) => {
|
&Instruction::CallFail(_) | &Instruction::ExecuteFail(_) => {
|
||||||
self.machine_st.backtrack();
|
self.machine_st.backtrack();
|
||||||
}
|
}
|
||||||
@@ -4134,6 +4192,46 @@ impl Machine {
|
|||||||
self.cpu_now();
|
self.cpu_now();
|
||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
}
|
}
|
||||||
|
&Instruction::CallDeterministicLengthRundown(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.det_length_rundown());
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteDeterministicLengthRundown(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.det_length_rundown());
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
|
&Instruction::CallHttpOpen(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.http_open());
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteHttpOpen(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.http_open());
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
|
&Instruction::CallHttpListen(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.http_listen());
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteHttpListen(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.http_listen());
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
|
&Instruction::CallHttpAccept(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.http_accept());
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteHttpAccept(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.http_accept());
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
|
&Instruction::CallHttpAnswer(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.http_answer());
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteHttpAnswer(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.http_answer());
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
&Instruction::CallCurrentTime(_) => {
|
&Instruction::CallCurrentTime(_) => {
|
||||||
self.current_time();
|
self.current_time();
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
@@ -4178,6 +4276,30 @@ impl Machine {
|
|||||||
self.set_ball();
|
self.set_ball();
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
}
|
}
|
||||||
|
&Instruction::CallPushBallStack(_) => {
|
||||||
|
self.push_ball_stack();
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecutePushBallStack(_) => {
|
||||||
|
self.push_ball_stack();
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
|
&Instruction::CallPopBallStack(_) => {
|
||||||
|
self.pop_ball_stack();
|
||||||
|
self.machine_st.p += 1;
|
||||||
|
}
|
||||||
|
&Instruction::ExecutePopBallStack(_) => {
|
||||||
|
self.pop_ball_stack();
|
||||||
|
self.machine_st.p = self.machine_st.cp;
|
||||||
|
}
|
||||||
|
&Instruction::CallPopFromBallStack(_) => {
|
||||||
|
self.pop_from_ball_stack();
|
||||||
|
self.machine_st.p += 1;
|
||||||
|
}
|
||||||
|
&Instruction::ExecutePopFromBallStack(_) => {
|
||||||
|
self.pop_from_ball_stack();
|
||||||
|
self.machine_st.p = self.machine_st.cp;
|
||||||
|
}
|
||||||
&Instruction::CallSetCutPointByDefault(r, _) => {
|
&Instruction::CallSetCutPointByDefault(r, _) => {
|
||||||
self.set_cut_point_by_default(r);
|
self.set_cut_point_by_default(r);
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
@@ -4703,11 +4825,11 @@ impl Machine {
|
|||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
}
|
}
|
||||||
&Instruction::CallLoadContextModule(_) => {
|
&Instruction::CallLoadContextModule(_) => {
|
||||||
self.load_context_module();
|
self.load_context_module(self.machine_st.registers[1]);
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
}
|
}
|
||||||
&Instruction::ExecuteLoadContextModule(_) => {
|
&Instruction::ExecuteLoadContextModule(_) => {
|
||||||
self.load_context_module();
|
self.load_context_module(self.machine_st.registers[1]);
|
||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
}
|
}
|
||||||
&Instruction::CallLoadContextStream(_) => {
|
&Instruction::CallLoadContextStream(_) => {
|
||||||
@@ -4862,6 +4984,118 @@ impl Machine {
|
|||||||
try_or_throw!(self.machine_st, self.add_non_counted_backtracking());
|
try_or_throw!(self.machine_st, self.add_non_counted_backtracking());
|
||||||
self.machine_st.p = self.machine_st.cp;
|
self.machine_st.p = self.machine_st.cp;
|
||||||
}
|
}
|
||||||
|
&Instruction::CallPredicateDefined(_) => {
|
||||||
|
self.machine_st.fail = !self.predicate_defined();
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecutePredicateDefined(_) => {
|
||||||
|
self.machine_st.fail = !self.predicate_defined();
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
|
&Instruction::CallStripModule(_) => {
|
||||||
|
let (module_loc, qualified_goal) = self.machine_st.strip_module(
|
||||||
|
self.machine_st.registers[1],
|
||||||
|
self.machine_st.registers[2],
|
||||||
|
);
|
||||||
|
|
||||||
|
let target_module_loc = self.machine_st.registers[2];
|
||||||
|
|
||||||
|
unify_fn!(
|
||||||
|
&mut self.machine_st,
|
||||||
|
module_loc,
|
||||||
|
target_module_loc
|
||||||
|
);
|
||||||
|
|
||||||
|
let target_qualified_goal = self.machine_st.registers[3];
|
||||||
|
|
||||||
|
unify_fn!(
|
||||||
|
&mut self.machine_st,
|
||||||
|
qualified_goal,
|
||||||
|
target_qualified_goal
|
||||||
|
);
|
||||||
|
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteStripModule(_) => {
|
||||||
|
let (module_loc, qualified_goal) = self.machine_st.strip_module(
|
||||||
|
self.machine_st.registers[1],
|
||||||
|
self.machine_st.registers[2],
|
||||||
|
);
|
||||||
|
|
||||||
|
let target_module_loc = self.machine_st.registers[2];
|
||||||
|
|
||||||
|
unify_fn!(
|
||||||
|
&mut self.machine_st,
|
||||||
|
module_loc,
|
||||||
|
target_module_loc
|
||||||
|
);
|
||||||
|
|
||||||
|
let target_qualified_goal = self.machine_st.registers[3];
|
||||||
|
|
||||||
|
unify_fn!(
|
||||||
|
&mut self.machine_st,
|
||||||
|
qualified_goal,
|
||||||
|
target_qualified_goal
|
||||||
|
);
|
||||||
|
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
|
&Instruction::CallPrepareCallClause(arity, _) => {
|
||||||
|
try_or_throw!(self.machine_st, self.prepare_call_clause(arity));
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecutePrepareCallClause(arity, _) => {
|
||||||
|
try_or_throw!(self.machine_st, self.prepare_call_clause(arity));
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
|
&Instruction::CallCompileInlineOrExpandedGoal(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.compile_inline_or_expanded_goal());
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteCompileInlineOrExpandedGoal(_) => {
|
||||||
|
try_or_throw!(self.machine_st, self.compile_inline_or_expanded_goal());
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
|
&Instruction::CallIsExpandedOrInlined(_) => {
|
||||||
|
self.machine_st.fail = !self.is_expanded_or_inlined();
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteIsExpandedOrInlined(_) => {
|
||||||
|
self.machine_st.fail = !self.is_expanded_or_inlined();
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
|
&Instruction::CallInlineCallN(arity, _) => {
|
||||||
|
let call_at_index = |wam: &mut Machine, name, arity, ptr| {
|
||||||
|
wam.try_call(name, arity, ptr)
|
||||||
|
};
|
||||||
|
|
||||||
|
try_or_throw!(self.machine_st, self.call_inline(arity, call_at_index));
|
||||||
|
|
||||||
|
if self.machine_st.fail {
|
||||||
|
self.machine_st.backtrack();
|
||||||
|
} else {
|
||||||
|
try_or_throw!(
|
||||||
|
self.machine_st,
|
||||||
|
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteInlineCallN(arity, _) => {
|
||||||
|
let call_at_index = |wam: &mut Machine, name, arity, ptr| {
|
||||||
|
wam.try_execute(name, arity, ptr)
|
||||||
|
};
|
||||||
|
|
||||||
|
try_or_throw!(self.machine_st, self.call_inline(arity, call_at_index));
|
||||||
|
|
||||||
|
if self.machine_st.fail {
|
||||||
|
self.machine_st.backtrack();
|
||||||
|
} else {
|
||||||
|
try_or_throw!(
|
||||||
|
self.machine_st,
|
||||||
|
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ use crate::atom_table::*;
|
|||||||
use crate::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use crate::heap_iter::FocusedHeapIter;
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
pub(crate) trait UnmarkPolicy {
|
pub(crate) trait UnmarkPolicy {
|
||||||
fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool;
|
fn unmark(heap: &mut [HeapCellValue], current: usize);
|
||||||
fn mark(heap: &mut [HeapCellValue], current: usize);
|
fn mark(heap: &mut [HeapCellValue], current: usize);
|
||||||
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue>
|
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue>
|
||||||
where
|
where
|
||||||
@@ -16,9 +19,8 @@ pub(crate) struct IteratorUMP;
|
|||||||
|
|
||||||
impl UnmarkPolicy for IteratorUMP {
|
impl UnmarkPolicy for IteratorUMP {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool {
|
fn unmark(heap: &mut [HeapCellValue], current: usize) {
|
||||||
heap[current].set_mark_bit(false);
|
heap[current].set_mark_bit(false);
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -34,7 +36,7 @@ struct MarkerUMP {}
|
|||||||
|
|
||||||
impl UnmarkPolicy for MarkerUMP {
|
impl UnmarkPolicy for MarkerUMP {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn unmark(_heap: &mut [HeapCellValue], _current: usize) -> bool { true }
|
fn unmark(_heap: &mut [HeapCellValue], _current: usize) {}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn mark(heap: &mut [HeapCellValue], current: usize) {
|
fn mark(heap: &mut [HeapCellValue], current: usize) {
|
||||||
@@ -43,7 +45,7 @@ impl UnmarkPolicy for MarkerUMP {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> {
|
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> {
|
||||||
if iter.heap[iter.current + 1].get_mark_bit() {
|
if iter.heap[iter.current + 1].get_forwarding_bit() {
|
||||||
return iter.forward_var();
|
return iter.forward_var();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,10 +55,9 @@ impl UnmarkPolicy for MarkerUMP {
|
|||||||
iter.current += 1;
|
iter.current += 1;
|
||||||
|
|
||||||
iter.next = iter.heap[iter.current].get_value();
|
iter.next = iter.heap[iter.current].get_value();
|
||||||
|
|
||||||
iter.heap[iter.current].set_value(temp);
|
iter.heap[iter.current].set_value(temp);
|
||||||
iter.heap[iter.current].set_mark_bit(true);
|
|
||||||
|
|
||||||
|
iter.heap[iter.current].set_forwarding_bit(true); // forward the attr vars list.
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,6 +72,14 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
|
|||||||
_marker: PhantomData<UMP>,
|
_marker: PhantomData<UMP>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
|
||||||
|
#[inline]
|
||||||
|
fn focus(&self) -> usize {
|
||||||
|
self.current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> {
|
impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.current == self.start {
|
if self.current == self.start {
|
||||||
@@ -84,15 +93,14 @@ impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> {
|
||||||
pub(crate) fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
|
pub(crate) fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
|
||||||
let orig_heap_len = heap.len();
|
let orig_heap_len = heap.len();
|
||||||
let start = orig_heap_len + 1;
|
let start = orig_heap_len;
|
||||||
|
|
||||||
heap.push(cell);
|
heap.push(cell);
|
||||||
heap.push(heap_loc_as_cell!(orig_heap_len));
|
|
||||||
|
|
||||||
heap[start].set_mark_bit(true);
|
heap[start].set_forwarding_bit(true);
|
||||||
let next = heap[start].get_value();
|
let next = heap[start].get_value();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@@ -104,11 +112,39 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
|||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> {
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
|
||||||
|
let orig_heap_len = heap.len();
|
||||||
|
let start = orig_heap_len + 1;
|
||||||
|
|
||||||
|
heap.push(cell);
|
||||||
|
heap.push(heap_loc_as_cell!(orig_heap_len));
|
||||||
|
|
||||||
|
heap[start].set_forwarding_bit(true);
|
||||||
|
let next = heap[start].get_value();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
heap,
|
||||||
|
orig_heap_len,
|
||||||
|
start,
|
||||||
|
current: start,
|
||||||
|
next,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
||||||
fn backward_and_return(&mut self) -> Option<HeapCellValue> {
|
fn backward_and_return(&mut self) -> Option<HeapCellValue> {
|
||||||
let current = self.current;
|
let current = self.current;
|
||||||
|
|
||||||
if self.backward() {
|
if self.backward() {
|
||||||
|
// set the f and m bits on the heap cell at start
|
||||||
|
// so we invoke backward() and return None next call.
|
||||||
|
|
||||||
self.heap[self.current].set_forwarding_bit(true);
|
self.heap[self.current].set_forwarding_bit(true);
|
||||||
self.heap[self.current].set_mark_bit(true);
|
self.heap[self.current].set_mark_bit(true);
|
||||||
}
|
}
|
||||||
@@ -117,13 +153,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn forward_var(&mut self) -> Option<HeapCellValue> {
|
fn forward_var(&mut self) -> Option<HeapCellValue> {
|
||||||
if self.heap[self.next].get_mark_bit() {
|
if self.heap[self.next].get_forwarding_bit() {
|
||||||
return self.backward_and_return();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.heap[self.current].set_forwarding_bit(true);
|
|
||||||
|
|
||||||
if self.heap[self.next].get_forwarding_bit() == Some(true) {
|
|
||||||
return self.backward_and_return();
|
return self.backward_and_return();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,29 +168,36 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
|||||||
|
|
||||||
fn forward(&mut self) -> Option<HeapCellValue> {
|
fn forward(&mut self) -> Option<HeapCellValue> {
|
||||||
loop {
|
loop {
|
||||||
if self.heap[self.current].get_forwarding_bit() != Some(true) {
|
if !self.heap[self.current].get_mark_bit() {
|
||||||
|
self.heap[self.current].set_mark_bit(true);
|
||||||
|
|
||||||
match self.heap[self.current].get_tag() {
|
match self.heap[self.current].get_tag() {
|
||||||
HeapCellValueTag::AttrVar => {
|
HeapCellValueTag::AttrVar => {
|
||||||
if let Some(cell) = UMP::forward_attr_var(self) { return Some(cell); }
|
if let Some(cell) = UMP::forward_attr_var(self) { return Some(cell); }
|
||||||
|
|
||||||
|
if self.heap[self.next].get_mark_bit() {
|
||||||
|
return Some(attr_var_as_cell!(self.current));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
HeapCellValueTag::Var => {
|
HeapCellValueTag::Var => {
|
||||||
if let Some(cell) = self.forward_var() { return Some(cell); }
|
if let Some(cell) = self.forward_var() { return Some(cell); }
|
||||||
|
|
||||||
|
if self.heap[self.next].get_mark_bit() {
|
||||||
|
return Some(heap_loc_as_cell!(self.current));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
HeapCellValueTag::Str => {
|
HeapCellValueTag::Str => {
|
||||||
if self.heap[self.next + 1].get_mark_bit() {
|
if self.heap[self.next + 1].get_forwarding_bit() {
|
||||||
return self.backward_and_return();
|
return self.backward_and_return();
|
||||||
}
|
}
|
||||||
|
|
||||||
let h = self.next;
|
let h = self.next;
|
||||||
let cell = self.heap[h];
|
let cell = self.heap[h];
|
||||||
|
|
||||||
self.heap[h].set_forwarding_bit(true);
|
|
||||||
self.heap[self.current].set_forwarding_bit(true);
|
|
||||||
|
|
||||||
let arity = cell_as_atom_cell!(self.heap[h]).get_arity();
|
let arity = cell_as_atom_cell!(self.heap[h]).get_arity();
|
||||||
|
|
||||||
for cell in &mut self.heap[h + 1 .. h + arity + 1] {
|
for cell in &mut self.heap[h + 1 .. h + arity + 1] {
|
||||||
cell.set_mark_bit(true);
|
cell.set_forwarding_bit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let last_cell_loc = h + arity;
|
let last_cell_loc = h + arity;
|
||||||
@@ -172,14 +209,13 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
|||||||
return Some(cell);
|
return Some(cell);
|
||||||
}
|
}
|
||||||
HeapCellValueTag::Lis => {
|
HeapCellValueTag::Lis => {
|
||||||
if self.heap[self.next + 1].get_mark_bit() {
|
let last_cell_loc = self.next + 1;
|
||||||
|
|
||||||
|
if self.heap[last_cell_loc].get_forwarding_bit() {
|
||||||
return self.backward_and_return();
|
return self.backward_and_return();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.heap[self.current].set_forwarding_bit(true);
|
self.heap[last_cell_loc].set_forwarding_bit(true);
|
||||||
self.heap[self.next+1].set_mark_bit(true);
|
|
||||||
|
|
||||||
let last_cell_loc = self.next + 1;
|
|
||||||
|
|
||||||
self.next = self.heap[last_cell_loc].get_value();
|
self.next = self.heap[last_cell_loc].get_value();
|
||||||
self.heap[last_cell_loc].set_value(self.current);
|
self.heap[last_cell_loc].set_value(self.current);
|
||||||
@@ -191,20 +227,17 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
|||||||
let h = self.next;
|
let h = self.next;
|
||||||
let cell = self.heap[h];
|
let cell = self.heap[h];
|
||||||
|
|
||||||
self.heap[self.current].set_forwarding_bit(true);
|
if self.heap[h+1].get_forwarding_bit() {
|
||||||
|
|
||||||
if self.heap[h+1].get_mark_bit() {
|
|
||||||
return self.backward_and_return();
|
return self.backward_and_return();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.heap[h].get_tag() == HeapCellValueTag::PStr {
|
if self.heap[h].get_tag() == HeapCellValueTag::PStr {
|
||||||
self.heap[h+1].set_mark_bit(true);
|
let last_cell_loc = h+1;
|
||||||
|
self.heap[last_cell_loc].set_forwarding_bit(true);
|
||||||
|
|
||||||
self.next = self.heap[h+1].get_value();
|
self.next = self.heap[last_cell_loc].get_value();
|
||||||
self.heap[h+1].set_value(self.current);
|
self.heap[last_cell_loc].set_value(self.current);
|
||||||
self.heap[h].set_forwarding_bit(true);
|
self.current = last_cell_loc;
|
||||||
|
|
||||||
self.current = h+1;
|
|
||||||
} else {
|
} else {
|
||||||
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset);
|
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset);
|
||||||
|
|
||||||
@@ -212,7 +245,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
|||||||
self.heap[h].set_value(self.current);
|
self.heap[h].set_value(self.current);
|
||||||
self.current = h;
|
self.current = h;
|
||||||
|
|
||||||
if self.heap[h].get_forwarding_bit() == Some(true) {
|
if self.heap[h].get_mark_bit() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,20 +254,23 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
|||||||
}
|
}
|
||||||
HeapCellValueTag::PStrOffset => {
|
HeapCellValueTag::PStrOffset => {
|
||||||
let h = self.next;
|
let h = self.next;
|
||||||
|
let cell = self.heap[h];
|
||||||
|
|
||||||
|
// mark the Fixnum offset.
|
||||||
UMP::mark(self.heap, self.current+1);
|
UMP::mark(self.heap, self.current+1);
|
||||||
|
|
||||||
if self.heap[h].get_tag() == HeapCellValueTag::PStr {
|
let last_cell_loc = h+1;
|
||||||
if self.heap[h+1].get_mark_bit() {
|
|
||||||
|
if self.heap[last_cell_loc].get_forwarding_bit() {
|
||||||
return self.backward_and_return();
|
return self.backward_and_return();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.heap[h+1].set_mark_bit(true);
|
if self.heap[h].get_tag() == HeapCellValueTag::PStr {
|
||||||
self.heap[self.current].set_forwarding_bit(true);
|
self.heap[last_cell_loc].set_forwarding_bit(true);
|
||||||
|
|
||||||
self.next = self.heap[h+1].get_value();
|
self.next = self.heap[last_cell_loc].get_value();
|
||||||
self.heap[h+1].set_value(self.current);
|
self.heap[last_cell_loc].set_value(self.current);
|
||||||
self.current = h+1;
|
self.current = last_cell_loc;
|
||||||
} else {
|
} else {
|
||||||
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr);
|
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr);
|
||||||
|
|
||||||
@@ -242,23 +278,25 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
|||||||
self.heap[h].set_value(self.current);
|
self.heap[h].set_value(self.current);
|
||||||
self.current = h;
|
self.current = h;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
HeapCellValueTag::StackVar => {
|
|
||||||
let cell = self.heap[self.current];
|
|
||||||
self.heap[self.current].set_forwarding_bit(true);
|
|
||||||
return Some(cell);
|
return Some(cell);
|
||||||
}
|
}
|
||||||
_ => {
|
tag @ HeapCellValueTag::Atom => {
|
||||||
if self.heap[self.current].get_mark_bit() {
|
let cell = HeapCellValue::build_with(tag, self.next as u64);
|
||||||
let current = self.current;
|
let arity = AtomCell::from_bytes(cell.into_bytes()).get_arity();
|
||||||
|
|
||||||
|
if arity == 0 {
|
||||||
|
return self.backward_and_return();
|
||||||
|
} else if self.backward() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HeapCellValueTag::PStr => {
|
||||||
if self.backward() {
|
if self.backward() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(self.heap[current]);
|
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
return self.backward_and_return();
|
return self.backward_and_return();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,42 +309,23 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn backward(&mut self) -> bool {
|
fn backward(&mut self) -> bool {
|
||||||
while !self.heap[self.current].get_mark_bit() {
|
while !self.heap[self.current].get_forwarding_bit() {
|
||||||
let temp = self.heap[self.current].get_value();
|
let temp = self.heap[self.current].get_value();
|
||||||
|
|
||||||
UMP::mark(self.heap, self.current);
|
UMP::unmark(self.heap, self.current);
|
||||||
|
|
||||||
self.heap[self.current].set_forwarding_bit(false);
|
|
||||||
self.heap[self.current].set_value(self.next);
|
self.heap[self.current].set_value(self.next);
|
||||||
|
|
||||||
self.next = self.current;
|
self.next = self.current;
|
||||||
self.current = temp;
|
self.current = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.heap[self.current].set_forwarding_bit(false);
|
self.heap[self.current].set_forwarding_bit(false);
|
||||||
|
UMP::unmark(self.heap, self.current);
|
||||||
let unmark_is_no_op = UMP::unmark(self.heap, self.current);
|
|
||||||
|
|
||||||
if self.current == self.start {
|
if self.current == self.start {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if unmark_is_no_op { // if true, the marker is running.
|
|
||||||
let cell = self.heap[self.current];
|
|
||||||
|
|
||||||
// a cyclic root must be handled specially when marking.
|
|
||||||
if self.next >= self.orig_heap_len && cell.is_ref() {
|
|
||||||
debug_assert!(cell.get_tag() != HeapCellValueTag::PStrOffset);
|
|
||||||
|
|
||||||
self.heap[self.current].set_mark_bit(false);
|
|
||||||
let prev_current = self.heap[self.current].get_value();
|
|
||||||
|
|
||||||
if !self.heap[prev_current].is_forwarded() {
|
|
||||||
return self.backward();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.current -= 1;
|
self.current -= 1;
|
||||||
|
|
||||||
let temp = self.heap[self.current+1].get_value();
|
let temp = self.heap[self.current+1].get_value();
|
||||||
@@ -713,7 +732,7 @@ mod tests {
|
|||||||
assert!(wam.machine_st.heap[8].get_mark_bit());
|
assert!(wam.machine_st.heap[8].get_mark_bit());
|
||||||
|
|
||||||
for cell in &wam.machine_st.heap {
|
for cell in &wam.machine_st.heap {
|
||||||
assert!(cell.get_forwarding_bit() != Some(true));
|
assert!(!cell.get_forwarding_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
|
||||||
@@ -743,7 +762,7 @@ mod tests {
|
|||||||
assert!(wam.machine_st.heap[8].get_mark_bit());
|
assert!(wam.machine_st.heap[8].get_mark_bit());
|
||||||
|
|
||||||
for cell in &wam.machine_st.heap {
|
for cell in &wam.machine_st.heap {
|
||||||
assert!(cell.get_forwarding_bit() != Some(true));
|
assert!(!cell.get_forwarding_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
|
||||||
@@ -773,7 +792,7 @@ mod tests {
|
|||||||
assert!(wam.machine_st.heap[8].get_mark_bit());
|
assert!(wam.machine_st.heap[8].get_mark_bit());
|
||||||
|
|
||||||
for cell in &wam.machine_st.heap {
|
for cell in &wam.machine_st.heap {
|
||||||
assert!(cell.get_forwarding_bit() != Some(true));
|
assert!(!cell.get_forwarding_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
|
||||||
@@ -803,7 +822,7 @@ mod tests {
|
|||||||
assert!(wam.machine_st.heap[8].get_mark_bit());
|
assert!(wam.machine_st.heap[8].get_mark_bit());
|
||||||
|
|
||||||
for cell in &wam.machine_st.heap {
|
for cell in &wam.machine_st.heap {
|
||||||
assert!(cell.get_forwarding_bit() != Some(true));
|
assert!(!cell.get_forwarding_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
|
||||||
@@ -922,7 +941,6 @@ mod tests {
|
|||||||
wam.machine_st.heap.push(list_loc_as_cell!(9));
|
wam.machine_st.heap.push(list_loc_as_cell!(9));
|
||||||
wam.machine_st.heap.push(heap_loc_as_cell!(9));
|
wam.machine_st.heap.push(heap_loc_as_cell!(9));
|
||||||
wam.machine_st.heap.push(empty_list_as_cell!());
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
|
||||||
wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7.
|
wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7.
|
||||||
wam.machine_st.heap.push(heap_loc_as_cell!(12));
|
wam.machine_st.heap.push(heap_loc_as_cell!(12));
|
||||||
|
|
||||||
@@ -1096,5 +1114,88 @@ mod tests {
|
|||||||
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("f"), 2));
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("f"), 2));
|
||||||
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1));
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1));
|
||||||
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(1));
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(1));
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
// representation of one of the heap terms as in issue #1384.
|
||||||
|
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(1));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(0));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(0));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(2));
|
||||||
|
|
||||||
|
mark_cells(&mut wam.machine_st.heap, list_loc_as_cell!(5));
|
||||||
|
|
||||||
|
all_cells_marked_and_unforwarded(&wam.machine_st.heap);
|
||||||
|
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), empty_list_as_cell!());
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(0));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), heap_loc_as_cell!(0));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), empty_list_as_cell!());
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), heap_loc_as_cell!(2));
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
// representation of one of the heap terms as in issue #1384.
|
||||||
|
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(7));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(0));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(3)); // A = [B|[]].
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(5)); // B = [A|A].
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(2));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(2));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!()); // C = [[]|B].
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(3));
|
||||||
|
|
||||||
|
mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert!(wam.machine_st.heap[0].get_mark_bit());
|
||||||
|
assert!(!wam.machine_st.heap[1].get_mark_bit());
|
||||||
|
|
||||||
|
all_cells_marked_and_unforwarded(&wam.machine_st.heap[2 ..]);
|
||||||
|
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(7));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(0));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(5));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), empty_list_as_cell!());
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(2));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), heap_loc_as_cell!(2));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), empty_list_as_cell!());
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), heap_loc_as_cell!(3));
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
wam.machine_st.heap.push(str_loc_as_cell!(1));
|
||||||
|
wam.machine_st.heap.push(atom_as_cell!(atom!("+"), 2));
|
||||||
|
wam.machine_st.heap.push(str_loc_as_cell!(4));
|
||||||
|
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
wam.machine_st.heap.push(atom_as_cell!(atom!("-"), 2));
|
||||||
|
wam.machine_st.heap.push(str_loc_as_cell!(7));
|
||||||
|
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
wam.machine_st.heap.push(atom_as_cell!(atom!("+"), 2));
|
||||||
|
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(3)));
|
||||||
|
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(4)));
|
||||||
|
|
||||||
|
mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
all_cells_marked_and_unforwarded(&wam.machine_st.heap);
|
||||||
|
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), str_loc_as_cell!(1));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(atom!("+"), 2));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), str_loc_as_cell!(4));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(atom!("-"), 2));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), str_loc_as_cell!(7));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), atom_as_cell!(atom!("+"), 2));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(3)));
|
||||||
|
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), fixnum_as_cell!(Fixnum::build_with(4)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
|
use crate::machine::machine_indices::*;
|
||||||
use crate::machine::partial_string::*;
|
use crate::machine::partial_string::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use ordered_float::OrderedFloat;
|
use crate::parser::rug::{Integer, Rational};
|
||||||
use rug::{Integer, Rational};
|
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
@@ -18,6 +18,9 @@ impl From<Literal> for HeapCellValue {
|
|||||||
match literal {
|
match literal {
|
||||||
Literal::Atom(name) => atom_as_cell!(name),
|
Literal::Atom(name) => atom_as_cell!(name),
|
||||||
Literal::Char(c) => char_as_cell!(c),
|
Literal::Char(c) => char_as_cell!(c),
|
||||||
|
Literal::CodeIndex(ptr) => {
|
||||||
|
untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr))
|
||||||
|
}
|
||||||
Literal::Fixnum(n) => fixnum_as_cell!(n),
|
Literal::Fixnum(n) => fixnum_as_cell!(n),
|
||||||
Literal::Integer(bigint_ptr) => {
|
Literal::Integer(bigint_ptr) => {
|
||||||
typed_arena_ptr_as_cell!(bigint_ptr)
|
typed_arena_ptr_as_cell!(bigint_ptr)
|
||||||
@@ -25,7 +28,7 @@ impl From<Literal> for HeapCellValue {
|
|||||||
Literal::Rational(bigint_ptr) => {
|
Literal::Rational(bigint_ptr) => {
|
||||||
typed_arena_ptr_as_cell!(bigint_ptr)
|
typed_arena_ptr_as_cell!(bigint_ptr)
|
||||||
}
|
}
|
||||||
Literal::Float(f) => HeapCellValue::from(f),
|
Literal::Float(f) => HeapCellValue::from(f.as_ptr()),
|
||||||
Literal::String(s) => {
|
Literal::String(s) => {
|
||||||
if s == atom!("") {
|
if s == atom!("") {
|
||||||
empty_list_as_cell!()
|
empty_list_as_cell!()
|
||||||
@@ -56,7 +59,7 @@ impl TryFrom<HeapCellValue> for Literal {
|
|||||||
Ok(Literal::Fixnum(n))
|
Ok(Literal::Fixnum(n))
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::F64, f) => {
|
(HeapCellValueTag::F64, f) => {
|
||||||
Ok(Literal::Float(f))
|
Ok(Literal::Float(f.as_offset()))
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Cons, cons_ptr) => {
|
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||||
match_untyped_arena_ptr!(cons_ptr,
|
match_untyped_arena_ptr!(cons_ptr,
|
||||||
@@ -66,9 +69,8 @@ impl TryFrom<HeapCellValue> for Literal {
|
|||||||
(ArenaHeaderTag::Rational, n) => {
|
(ArenaHeaderTag::Rational, n) => {
|
||||||
Ok(Literal::Rational(n))
|
Ok(Literal::Rational(n))
|
||||||
}
|
}
|
||||||
(ArenaHeaderTag::F64, f) => {
|
(ArenaHeaderTag::IndexPtr, _ip) => {
|
||||||
// remove this redundancy.
|
Ok(Literal::CodeIndex(CodeIndex::from(cons_ptr)))
|
||||||
Ok(Literal::Float(F64Ptr(f)))
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
Err(())
|
Err(())
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ use crate::parser::ast::*;
|
|||||||
use fxhash::FxBuildHasher;
|
use fxhash::FxBuildHasher;
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use ref_thread_local::RefThreadLocal;
|
use ref_thread_local::RefThreadLocal;
|
||||||
use slice_deque::{sdeq, SliceDeque};
|
|
||||||
|
|
||||||
|
use std::collections::VecDeque;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
@@ -21,12 +21,12 @@ pub(super) fn set_code_index(
|
|||||||
retraction_info: &mut RetractionInfo,
|
retraction_info: &mut RetractionInfo,
|
||||||
compilation_target: &CompilationTarget,
|
compilation_target: &CompilationTarget,
|
||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
code_index: &CodeIndex,
|
mut code_index: CodeIndex,
|
||||||
code_ptr: IndexPtr,
|
code_ptr: IndexPtr,
|
||||||
) {
|
) {
|
||||||
let record = match compilation_target {
|
let record = match compilation_target {
|
||||||
CompilationTarget::User => {
|
CompilationTarget::User => {
|
||||||
if IndexPtr::Undefined == code_index.get() {
|
if IndexPtrTag::Undefined == code_index.get().tag() {
|
||||||
code_index.set(code_ptr);
|
code_index.set(code_ptr);
|
||||||
RetractionRecord::AddedUserPredicate(key)
|
RetractionRecord::AddedUserPredicate(key)
|
||||||
} else {
|
} else {
|
||||||
@@ -35,7 +35,7 @@ pub(super) fn set_code_index(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CompilationTarget::Module(ref module_name) => {
|
CompilationTarget::Module(ref module_name) => {
|
||||||
if IndexPtr::Undefined == code_index.get() {
|
if IndexPtrTag::Undefined == code_index.get().tag() {
|
||||||
code_index.set(code_ptr);
|
code_index.set(code_ptr);
|
||||||
RetractionRecord::AddedModulePredicate(*module_name, key)
|
RetractionRecord::AddedModulePredicate(*module_name, key)
|
||||||
} else {
|
} else {
|
||||||
@@ -48,12 +48,10 @@ pub(super) fn set_code_index(
|
|||||||
retraction_info.push_record(record);
|
retraction_info.push_record(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_op_decl_as_module_export(
|
fn add_op_decl_as_module_export<'a, LS: LoadState<'a>>(
|
||||||
|
payload: &mut LS::LoaderFieldType,
|
||||||
module_op_dir: &mut OpDir,
|
module_op_dir: &mut OpDir,
|
||||||
compilation_target: &CompilationTarget,
|
|
||||||
retraction_info: &mut RetractionInfo,
|
|
||||||
wam_op_dir: &mut OpDir,
|
wam_op_dir: &mut OpDir,
|
||||||
module_op_exports: &mut ModuleOpExports,
|
|
||||||
op_decl: &OpDecl,
|
op_decl: &OpDecl,
|
||||||
) {
|
) {
|
||||||
/*
|
/*
|
||||||
@@ -65,20 +63,21 @@ fn add_op_decl_as_module_export(
|
|||||||
|
|
||||||
match op_decl.insert_into_op_dir(wam_op_dir) {
|
match op_decl.insert_into_op_dir(wam_op_dir) {
|
||||||
Some(op_desc) => {
|
Some(op_desc) => {
|
||||||
retraction_info.push_record(RetractionRecord::ReplacedUserOp(
|
payload.retraction_info.push_record(RetractionRecord::ReplacedUserOp(
|
||||||
*op_decl,
|
*op_decl,
|
||||||
op_desc,
|
op_desc,
|
||||||
));
|
));
|
||||||
|
|
||||||
module_op_exports.push((*op_decl, Some(op_desc)));
|
payload.module_op_exports.push((*op_decl, Some(op_desc)));
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl));
|
payload.retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl));
|
||||||
module_op_exports.push((*op_decl, None));
|
payload.module_op_exports.push((*op_decl, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_op_decl(retraction_info, compilation_target, module_op_dir, op_decl);
|
let compilation_target = payload.compilation_target;
|
||||||
|
add_op_decl(&mut payload.retraction_info, &compilation_target, module_op_dir, op_decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn add_op_decl(
|
pub(super) fn add_op_decl(
|
||||||
@@ -117,8 +116,8 @@ pub(super) fn add_op_decl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn import_module_exports(
|
pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
|
||||||
retraction_info: &mut RetractionInfo,
|
payload: &mut LS::LoaderFieldType,
|
||||||
compilation_target: &CompilationTarget,
|
compilation_target: &CompilationTarget,
|
||||||
imported_module: &Module,
|
imported_module: &Module,
|
||||||
code_dir: &mut CodeDir,
|
code_dir: &mut CodeDir,
|
||||||
@@ -135,16 +134,18 @@ pub(super) fn import_module_exports(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
||||||
|
let arena = &mut LS::machine_st(payload).arena;
|
||||||
|
|
||||||
let target_code_index = code_dir
|
let target_code_index = code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
.or_insert_with(|| CodeIndex::default(arena))
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
set_code_index(
|
set_code_index(
|
||||||
retraction_info,
|
&mut payload.retraction_info,
|
||||||
compilation_target,
|
compilation_target,
|
||||||
key,
|
key,
|
||||||
&target_code_index,
|
target_code_index,
|
||||||
src_code_index.get(),
|
src_code_index.get(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -155,7 +156,7 @@ pub(super) fn import_module_exports(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ModuleExport::OpDecl(ref op_decl) => {
|
ModuleExport::OpDecl(ref op_decl) => {
|
||||||
add_op_decl(retraction_info, compilation_target, op_dir, op_decl);
|
add_op_decl(&mut payload.retraction_info, compilation_target, op_dir, op_decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,15 +164,14 @@ pub(super) fn import_module_exports(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_module_exports_into_module(
|
fn import_module_exports_into_module<'a, LS: LoadState<'a>>(
|
||||||
retraction_info: &mut RetractionInfo,
|
payload: &mut LS::LoaderFieldType,
|
||||||
compilation_target: &CompilationTarget,
|
compilation_target: &CompilationTarget,
|
||||||
imported_module: &Module,
|
imported_module: &Module,
|
||||||
code_dir: &mut CodeDir,
|
code_dir: &mut CodeDir,
|
||||||
op_dir: &mut OpDir,
|
op_dir: &mut OpDir,
|
||||||
meta_predicates: &mut MetaPredicateDir,
|
meta_predicates: &mut MetaPredicateDir,
|
||||||
wam_op_dir: &mut OpDir,
|
wam_op_dir: &mut OpDir,
|
||||||
module_op_exports: &mut ModuleOpExports,
|
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
for export in imported_module.module_decl.exports.iter() {
|
for export in imported_module.module_decl.exports.iter() {
|
||||||
match export {
|
match export {
|
||||||
@@ -183,16 +183,18 @@ fn import_module_exports_into_module(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
||||||
|
let arena = &mut LS::machine_st(payload).arena;
|
||||||
|
|
||||||
let target_code_index = code_dir
|
let target_code_index = code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
.or_insert_with(|| CodeIndex::default(arena))
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
set_code_index(
|
set_code_index(
|
||||||
retraction_info,
|
&mut payload.retraction_info,
|
||||||
compilation_target,
|
compilation_target,
|
||||||
key,
|
key,
|
||||||
&target_code_index,
|
target_code_index,
|
||||||
src_code_index.get(),
|
src_code_index.get(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -203,12 +205,10 @@ fn import_module_exports_into_module(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ModuleExport::OpDecl(ref op_decl) => {
|
ModuleExport::OpDecl(ref op_decl) => {
|
||||||
add_op_decl_as_module_export(
|
add_op_decl_as_module_export::<LS>(
|
||||||
|
payload,
|
||||||
op_dir,
|
op_dir,
|
||||||
compilation_target,
|
|
||||||
retraction_info,
|
|
||||||
wam_op_dir,
|
wam_op_dir,
|
||||||
module_op_exports,
|
|
||||||
op_decl,
|
op_decl,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -218,14 +218,12 @@ fn import_module_exports_into_module(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_qualified_module_exports(
|
fn import_qualified_module_exports<'a, LS: LoadState<'a>>(
|
||||||
retraction_info: &mut RetractionInfo,
|
payload: &mut LS::LoaderFieldType,
|
||||||
compilation_target: &CompilationTarget,
|
compilation_target: &CompilationTarget,
|
||||||
imported_module: &Module,
|
imported_module: &Module,
|
||||||
exports: &IndexSet<ModuleExport>,
|
exports: &IndexSet<ModuleExport>,
|
||||||
code_dir: &mut CodeDir,
|
wam_prelude: &mut MachinePreludeView,
|
||||||
op_dir: &mut OpDir,
|
|
||||||
meta_predicates: &mut MetaPredicateDir,
|
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
for export in imported_module.module_decl.exports.iter() {
|
for export in imported_module.module_decl.exports.iter() {
|
||||||
if !exports.contains(export) {
|
if !exports.contains(export) {
|
||||||
@@ -237,20 +235,22 @@ fn import_qualified_module_exports(
|
|||||||
let key = (*name, *arity);
|
let key = (*name, *arity);
|
||||||
|
|
||||||
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
|
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
|
||||||
meta_predicates.insert(key.clone(), meta_specs.clone());
|
wam_prelude.indices.meta_predicates.insert(key.clone(), meta_specs.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
||||||
let target_code_index = code_dir
|
let arena = &mut LS::machine_st(payload).arena;
|
||||||
|
|
||||||
|
let target_code_index = wam_prelude.indices.code_dir
|
||||||
.entry(key.clone())
|
.entry(key.clone())
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
set_code_index(
|
set_code_index(
|
||||||
retraction_info,
|
&mut payload.retraction_info,
|
||||||
compilation_target,
|
compilation_target,
|
||||||
key,
|
key,
|
||||||
&target_code_index,
|
target_code_index,
|
||||||
src_code_index.get(),
|
src_code_index.get(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -261,7 +261,12 @@ fn import_qualified_module_exports(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ModuleExport::OpDecl(ref op_decl) => {
|
ModuleExport::OpDecl(ref op_decl) => {
|
||||||
add_op_decl(retraction_info, compilation_target, op_dir, op_decl);
|
add_op_decl(
|
||||||
|
&mut payload.retraction_info,
|
||||||
|
compilation_target,
|
||||||
|
&mut wam_prelude.indices.op_dir,
|
||||||
|
op_decl,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,17 +274,17 @@ fn import_qualified_module_exports(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_qualified_module_exports_into_module(
|
fn import_qualified_module_exports_into_module<'a, LS: LoadState<'a>>(
|
||||||
retraction_info: &mut RetractionInfo,
|
payload: &mut LS::LoaderFieldType,
|
||||||
compilation_target: &CompilationTarget,
|
|
||||||
imported_module: &Module,
|
imported_module: &Module,
|
||||||
exports: &IndexSet<ModuleExport>,
|
exports: &IndexSet<ModuleExport>,
|
||||||
code_dir: &mut CodeDir,
|
code_dir: &mut CodeDir,
|
||||||
op_dir: &mut OpDir,
|
op_dir: &mut OpDir,
|
||||||
meta_predicates: &mut MetaPredicateDir,
|
meta_predicates: &mut MetaPredicateDir,
|
||||||
wam_op_dir: &mut OpDir,
|
wam_op_dir: &mut OpDir,
|
||||||
module_op_exports: &mut ModuleOpExports,
|
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
|
let payload_compilation_target = payload.compilation_target;
|
||||||
|
|
||||||
for export in imported_module.module_decl.exports.iter() {
|
for export in imported_module.module_decl.exports.iter() {
|
||||||
if !exports.contains(export) {
|
if !exports.contains(export) {
|
||||||
continue;
|
continue;
|
||||||
@@ -294,16 +299,18 @@ fn import_qualified_module_exports_into_module(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
||||||
|
let arena = &mut LS::machine_st(payload).arena;
|
||||||
|
|
||||||
let target_code_index = code_dir
|
let target_code_index = code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
set_code_index(
|
set_code_index(
|
||||||
retraction_info,
|
&mut payload.retraction_info,
|
||||||
compilation_target,
|
&payload_compilation_target,
|
||||||
key,
|
key,
|
||||||
&target_code_index,
|
target_code_index,
|
||||||
src_code_index.get(),
|
src_code_index.get(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -314,12 +321,10 @@ fn import_qualified_module_exports_into_module(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ModuleExport::OpDecl(ref op_decl) => {
|
ModuleExport::OpDecl(ref op_decl) => {
|
||||||
add_op_decl_as_module_export(
|
add_op_decl_as_module_export::<LS>(
|
||||||
|
payload,
|
||||||
op_dir,
|
op_dir,
|
||||||
compilation_target,
|
|
||||||
retraction_info,
|
|
||||||
wam_op_dir,
|
wam_op_dir,
|
||||||
module_op_exports,
|
|
||||||
op_decl,
|
op_decl,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -334,12 +339,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
compilation_target: CompilationTarget,
|
compilation_target: CompilationTarget,
|
||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
clause_locs: &SliceDeque<usize>,
|
clause_locs: &VecDeque<usize>,
|
||||||
) {
|
) {
|
||||||
let result_opt = self
|
let result_opt = self
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_skeleton(&compilation_target, &key)
|
.get_predicate_skeleton_mut(&compilation_target, &key)
|
||||||
.map(|skeleton| {
|
.map(|skeleton| {
|
||||||
(
|
(
|
||||||
clause_locs
|
clause_locs
|
||||||
@@ -396,7 +401,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
pub(super) fn retract_local_clause_clauses(
|
pub(super) fn retract_local_clause_clauses(
|
||||||
&mut self,
|
&mut self,
|
||||||
clause_clause_compilation_target: CompilationTarget,
|
clause_clause_compilation_target: CompilationTarget,
|
||||||
clause_locs: &SliceDeque<usize>,
|
clause_locs: &VecDeque<usize>,
|
||||||
) {
|
) {
|
||||||
let key = (atom!("$clause"), 2);
|
let key = (atom!("$clause"), 2);
|
||||||
let listing_src_file_name = self.listing_src_file_name();
|
let listing_src_file_name = self.listing_src_file_name();
|
||||||
@@ -415,7 +420,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
payload_compilation_target,
|
payload_compilation_target,
|
||||||
clause_clause_compilation_target,
|
clause_clause_compilation_target,
|
||||||
key,
|
key,
|
||||||
mem::replace(&mut skeleton.clause_clause_locs, sdeq![]),
|
mem::replace(&mut skeleton.clause_clause_locs, VecDeque::new()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -464,7 +469,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (key, code_index) in &removed_module.code_dir {
|
for (key, code_index) in removed_module.code_dir.iter_mut() {
|
||||||
match removed_module
|
match removed_module
|
||||||
.local_extensible_predicates
|
.local_extensible_predicates
|
||||||
.get(&(CompilationTarget::User, *key))
|
.get(&(CompilationTarget::User, *key))
|
||||||
@@ -473,7 +478,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_index_ptr = code_index.replace(IndexPtr::Undefined);
|
let old_index_ptr = code_index.replace(IndexPtr::undefined());
|
||||||
|
|
||||||
self.payload.retraction_info
|
self.payload.retraction_info
|
||||||
.push_record(RetractionRecord::ReplacedModulePredicate(
|
.push_record(RetractionRecord::ReplacedModulePredicate(
|
||||||
@@ -512,11 +517,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
for export in removed_module.module_decl.exports.iter() {
|
for export in removed_module.module_decl.exports.iter() {
|
||||||
match export {
|
match export {
|
||||||
ModuleExport::PredicateKey(ref key) => {
|
ModuleExport::PredicateKey(ref key) => {
|
||||||
match (removed_module.code_dir.get(key), code_dir.get(key)) {
|
match (removed_module.code_dir.get(key), code_dir.get_mut(key)) {
|
||||||
(Some(module_code_index), Some(target_code_index))
|
(Some(module_code_index), Some(target_code_index))
|
||||||
if module_code_index.get() == target_code_index.get() =>
|
if module_code_index.get() == target_code_index.get() =>
|
||||||
{
|
{
|
||||||
let old_index_ptr = target_code_index.replace(IndexPtr::Undefined);
|
let old_index_ptr = target_code_index.replace(IndexPtr::undefined());
|
||||||
retraction_info.push_record(predicate_retractor(*key, old_index_ptr));
|
retraction_info.push_record(predicate_retractor(*key, old_index_ptr));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -584,7 +589,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
Some(ref mut module) => module
|
Some(ref mut module) => module
|
||||||
.code_dir
|
.code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
.or_insert_with(|| CodeIndex::new(
|
||||||
|
IndexPtr::undefined(),
|
||||||
|
&mut LS::machine_st(&mut self.payload).arena,
|
||||||
|
))
|
||||||
.clone(),
|
.clone(),
|
||||||
None => {
|
None => {
|
||||||
self.add_dynamically_generated_module(module_name);
|
self.add_dynamically_generated_module(module_name);
|
||||||
@@ -593,7 +601,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
Some(ref mut module) => module
|
Some(ref mut module) => module
|
||||||
.code_dir
|
.code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
.or_insert_with(|| CodeIndex::new(
|
||||||
|
IndexPtr::undefined(),
|
||||||
|
&mut LS::machine_st(&mut self.payload).arena,
|
||||||
|
))
|
||||||
.clone(),
|
.clone(),
|
||||||
None => {
|
None => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -608,13 +619,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
compilation_target: CompilationTarget,
|
compilation_target: CompilationTarget,
|
||||||
) -> CodeIndex {
|
) -> CodeIndex {
|
||||||
|
let arena = &mut LS::machine_st(&mut self.payload).arena;
|
||||||
|
|
||||||
match compilation_target {
|
match compilation_target {
|
||||||
CompilationTarget::User => self
|
CompilationTarget::User => self
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
.code_dir
|
.code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
|
||||||
.clone(),
|
.clone(),
|
||||||
CompilationTarget::Module(module_name) => {
|
CompilationTarget::Module(module_name) => {
|
||||||
self.get_or_insert_local_code_index(module_name, key)
|
self.get_or_insert_local_code_index(module_name, key)
|
||||||
@@ -627,13 +640,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
module_name: Atom,
|
module_name: Atom,
|
||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
) -> CodeIndex {
|
) -> CodeIndex {
|
||||||
|
let arena = &mut LS::machine_st(&mut self.payload).arena;
|
||||||
|
|
||||||
if module_name == atom!("user") {
|
if module_name == atom!("user") {
|
||||||
return self
|
return self
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
.code_dir
|
.code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
|
||||||
.clone();
|
.clone();
|
||||||
} else {
|
} else {
|
||||||
self.get_or_insert_local_code_index(module_name, key)
|
self.get_or_insert_local_code_index(module_name, key)
|
||||||
@@ -732,14 +747,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
CompilationTarget::Module(ref module_name) => {
|
CompilationTarget::Module(ref module_name) => {
|
||||||
match self.wam_prelude.indices.modules.get_mut(module_name) {
|
match self.wam_prelude.indices.modules.get_mut(module_name) {
|
||||||
Some(ref mut module) => {
|
Some(ref mut module) => {
|
||||||
let payload: &mut LoadStatePayload<_> = &mut self.payload;
|
add_op_decl_as_module_export::<LS>(
|
||||||
|
&mut self.payload,
|
||||||
add_op_decl_as_module_export(
|
|
||||||
&mut module.op_dir,
|
&mut module.op_dir,
|
||||||
&payload.compilation_target,
|
|
||||||
&mut payload.retraction_info,
|
|
||||||
&mut self.wam_prelude.indices.op_dir,
|
&mut self.wam_prelude.indices.op_dir,
|
||||||
&mut payload.module_op_exports,
|
|
||||||
op_decl,
|
op_decl,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -752,7 +763,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType {
|
pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType {
|
||||||
match ClauseType::from(name, arity) {
|
let arena = &mut LS::machine_st(&mut self.payload).arena;
|
||||||
|
|
||||||
|
match ClauseType::from(name, arity, arena) {
|
||||||
ClauseType::Named(arity, name, _) => {
|
ClauseType::Named(arity, name, _) => {
|
||||||
let payload_compilation_target = self.payload.compilation_target;
|
let payload_compilation_target = self.payload.compilation_target;
|
||||||
|
|
||||||
@@ -773,7 +786,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
name: Atom,
|
name: Atom,
|
||||||
arity: usize,
|
arity: usize,
|
||||||
) -> ClauseType {
|
) -> ClauseType {
|
||||||
match ClauseType::from(name, arity) {
|
let arena = &mut LS::machine_st(&mut self.payload).arena;
|
||||||
|
|
||||||
|
match ClauseType::from(name, arity, arena) {
|
||||||
ClauseType::Named(arity, name, _) => {
|
ClauseType::Named(arity, name, _) => {
|
||||||
let key = (name, arity);
|
let key = (name, arity);
|
||||||
let idx = self.get_or_insert_qualified_code_index(module_name, key);
|
let idx = self.get_or_insert_qualified_code_index(module_name, key);
|
||||||
@@ -784,6 +799,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn get_meta_specs(&self, name: Atom, arity: usize) -> Option<&Vec<MetaSpec>> {
|
||||||
|
self.wam_prelude
|
||||||
|
.indices
|
||||||
|
.get_meta_predicate_spec(
|
||||||
|
name,
|
||||||
|
arity,
|
||||||
|
&self.payload.compilation_target,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn add_meta_predicate_record(
|
pub(super) fn add_meta_predicate_record(
|
||||||
&mut self,
|
&mut self,
|
||||||
module_name: Atom,
|
module_name: Atom,
|
||||||
@@ -894,8 +919,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
import_module_exports(
|
import_module_exports::<LS>(
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload,
|
||||||
&module_compilation_target,
|
&module_compilation_target,
|
||||||
builtins,
|
builtins,
|
||||||
code_dir,
|
code_dir,
|
||||||
@@ -992,14 +1017,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
for export in &module.module_decl.exports {
|
for export in &module.module_decl.exports {
|
||||||
if let ModuleExport::OpDecl(ref op_decl) = export {
|
if let ModuleExport::OpDecl(ref op_decl) = export {
|
||||||
let payload: &mut LoadStatePayload<_> = &mut self.payload;
|
add_op_decl_as_module_export::<LS>(
|
||||||
|
&mut self.payload,
|
||||||
add_op_decl_as_module_export(
|
|
||||||
&mut module.op_dir,
|
&mut module.op_dir,
|
||||||
&payload.compilation_target, // this is a Module.
|
|
||||||
&mut payload.retraction_info,
|
|
||||||
&mut self.wam_prelude.indices.op_dir,
|
&mut self.wam_prelude.indices.op_dir,
|
||||||
&mut payload.module_op_exports,
|
|
||||||
op_decl,
|
op_decl,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1018,8 +1039,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
match &payload_compilation_target {
|
match &payload_compilation_target {
|
||||||
CompilationTarget::User => {
|
CompilationTarget::User => {
|
||||||
import_module_exports(
|
import_module_exports::<LS>(
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload,
|
||||||
&payload_compilation_target,
|
&payload_compilation_target,
|
||||||
&module,
|
&module,
|
||||||
&mut self.wam_prelude.indices.code_dir,
|
&mut self.wam_prelude.indices.code_dir,
|
||||||
@@ -1030,17 +1051,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
CompilationTarget::Module(ref defining_module_name) => {
|
CompilationTarget::Module(ref defining_module_name) => {
|
||||||
match self.wam_prelude.indices.modules.get_mut(defining_module_name) {
|
match self.wam_prelude.indices.modules.get_mut(defining_module_name) {
|
||||||
Some(ref mut target_module) => {
|
Some(ref mut target_module) => {
|
||||||
let payload: &mut LoadStatePayload<_> = &mut self.payload;
|
import_module_exports_into_module::<LS>(
|
||||||
|
&mut self.payload,
|
||||||
import_module_exports_into_module(
|
|
||||||
&mut payload.retraction_info,
|
|
||||||
&payload_compilation_target,
|
&payload_compilation_target,
|
||||||
&module,
|
&module,
|
||||||
&mut target_module.code_dir,
|
&mut target_module.code_dir,
|
||||||
&mut target_module.op_dir,
|
&mut target_module.op_dir,
|
||||||
&mut target_module.meta_predicates,
|
&mut target_module.meta_predicates,
|
||||||
&mut self.wam_prelude.indices.op_dir,
|
&mut self.wam_prelude.indices.op_dir,
|
||||||
&mut payload.module_op_exports,
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@@ -1070,47 +1088,38 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) {
|
if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) {
|
||||||
let payload_compilation_target = self.payload.compilation_target;
|
let payload_compilation_target = self.payload.compilation_target;
|
||||||
|
|
||||||
match &payload_compilation_target {
|
let result = match &payload_compilation_target {
|
||||||
CompilationTarget::User => {
|
CompilationTarget::User => {
|
||||||
import_qualified_module_exports(
|
import_qualified_module_exports::<LS>(
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload,
|
||||||
&payload_compilation_target,
|
&payload_compilation_target,
|
||||||
&module,
|
&module,
|
||||||
&exports,
|
&exports,
|
||||||
&mut self.wam_prelude.indices.code_dir,
|
&mut self.wam_prelude,
|
||||||
&mut self.wam_prelude.indices.op_dir,
|
)
|
||||||
&mut self.wam_prelude.indices.meta_predicates,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
CompilationTarget::Module(ref defining_module_name) => {
|
CompilationTarget::Module(ref defining_module_name) => {
|
||||||
match self.wam_prelude.indices.modules.get_mut(defining_module_name) {
|
match self.wam_prelude.indices.modules.get_mut(defining_module_name) {
|
||||||
Some(ref mut target_module) => {
|
Some(ref mut target_module) => {
|
||||||
let payload: &mut LoadStatePayload<_> = &mut self.payload;
|
import_qualified_module_exports_into_module::<LS>(
|
||||||
|
&mut self.payload,
|
||||||
import_qualified_module_exports_into_module(
|
|
||||||
&mut payload.retraction_info,
|
|
||||||
&payload_compilation_target,
|
|
||||||
&module,
|
&module,
|
||||||
&exports,
|
&exports,
|
||||||
&mut target_module.code_dir,
|
&mut target_module.code_dir,
|
||||||
&mut target_module.op_dir,
|
&mut target_module.op_dir,
|
||||||
&mut target_module.meta_predicates,
|
&mut target_module.meta_predicates,
|
||||||
&mut self.wam_prelude.indices.op_dir,
|
&mut self.wam_prelude.indices.op_dir,
|
||||||
&mut payload.module_op_exports,
|
)
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// we find ourselves here because we're trying to import
|
Err(SessionError::ModuleCannotImportSelf(module_name))
|
||||||
// a module into itself as it is being defined.
|
|
||||||
self.wam_prelude.indices.modules.insert(module_name, module);
|
|
||||||
return Err(SessionError::ModuleCannotImportSelf(module_name));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
self.wam_prelude.indices.modules.insert(module_name, module);
|
self.wam_prelude.indices.modules.insert(module_name, module);
|
||||||
Ok(())
|
result
|
||||||
} else {
|
} else {
|
||||||
Err(SessionError::ExistenceError(ExistenceError::Module(module_name)))
|
Err(SessionError::ExistenceError(ExistenceError::Module(module_name)))
|
||||||
}
|
}
|
||||||
@@ -1168,7 +1177,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
indices: self.wam_prelude.indices,
|
indices: self.wam_prelude.indices,
|
||||||
code: self.wam_prelude.code,
|
code: self.wam_prelude.code,
|
||||||
load_contexts: self.wam_prelude.load_contexts,
|
load_contexts: self.wam_prelude.load_contexts,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
subloader.load()?
|
subloader.load()?
|
||||||
@@ -1231,7 +1240,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
indices: self.wam_prelude.indices,
|
indices: self.wam_prelude.indices,
|
||||||
code: self.wam_prelude.code,
|
code: self.wam_prelude.code,
|
||||||
load_contexts: self.wam_prelude.load_contexts,
|
load_contexts: self.wam_prelude.load_contexts,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
subloader.load()?
|
subloader.load()?
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ use crate::parser::ast::*;
|
|||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use slice_deque::{sdeq, SliceDeque};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::collections::VecDeque;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -96,7 +96,7 @@ pub(crate) enum RetractionRecord {
|
|||||||
CompilationTarget,
|
CompilationTarget,
|
||||||
CompilationTarget,
|
CompilationTarget,
|
||||||
PredicateKey,
|
PredicateKey,
|
||||||
SliceDeque<usize>,
|
VecDeque<usize>,
|
||||||
),
|
),
|
||||||
RemovedSkeleton(CompilationTarget, PredicateKey, PredicateSkeleton),
|
RemovedSkeleton(CompilationTarget, PredicateKey, PredicateSkeleton),
|
||||||
ReplacedDynamicElseOffset(usize, usize),
|
ReplacedDynamicElseOffset(usize, usize),
|
||||||
@@ -390,6 +390,64 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InlineLoadState<'a> {
|
||||||
|
machine_st: &'a mut MachineState,
|
||||||
|
pub payload: LoadStatePayload<InlineTermStream>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deref for InlineLoadState<'a> {
|
||||||
|
type Target = LoadStatePayload<InlineTermStream>;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DerefMut for InlineLoadState<'a> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LoadState<'a> for InlineLoadState<'a> {
|
||||||
|
type TS = InlineTermStream;
|
||||||
|
type LoaderFieldType = InlineLoadState<'a>;
|
||||||
|
type Evacuable = ();
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn new(machine_st: &'a mut MachineState, payload: LoadStatePayload<Self::TS>) -> Self::LoaderFieldType {
|
||||||
|
InlineLoadState { machine_st, payload }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn evacuate(_loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn should_drop_load_state(_loader: &Loader<'a, Self>) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn reset_machine(_loader: &mut Loader<'a, Self>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn machine_st(load_state: &mut Self::LoaderFieldType) -> &mut MachineState {
|
||||||
|
&mut load_state.machine_st
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn err_on_builtin_overwrite(
|
||||||
|
_loader: &Loader<'a, Self>,
|
||||||
|
_key: PredicateKey,
|
||||||
|
) -> Result<(), SessionError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Loader<'a, LS: LoadState<'a>> {
|
pub struct Loader<'a, LS: LoadState<'a>> {
|
||||||
pub(super) payload: LS::LoaderFieldType,
|
pub(super) payload: LS::LoaderFieldType,
|
||||||
pub(super) wam_prelude: MachinePreludeView<'a>,
|
pub(super) wam_prelude: MachinePreludeView<'a>,
|
||||||
@@ -485,10 +543,21 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
read_heap_cell!(addr,
|
read_heap_cell!(addr,
|
||||||
(HeapCellValueTag::Lis) => {
|
(HeapCellValueTag::Lis) => {
|
||||||
|
use crate::parser::parser::as_partial_string;
|
||||||
|
|
||||||
let tail = term_stack.pop().unwrap();
|
let tail = term_stack.pop().unwrap();
|
||||||
let head = term_stack.pop().unwrap();
|
let head = term_stack.pop().unwrap();
|
||||||
|
|
||||||
term_stack.push(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
|
match as_partial_string(head, tail) {
|
||||||
|
Ok((string, Some(tail))) => {
|
||||||
|
term_stack.push(Term::PartialString(Cell::default(), string, tail));
|
||||||
|
}
|
||||||
|
Ok((string, None)) => {
|
||||||
|
let atom = machine_st.atom_tbl.build_with(&string);
|
||||||
|
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
||||||
|
}
|
||||||
|
Err(cons_term) => term_stack.push(cons_term),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
|
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
|
||||||
let offset_string = format!("_{}", h);
|
let offset_string = format!("_{}", h);
|
||||||
@@ -499,6 +568,27 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
|
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
|
let h = iter.focus();
|
||||||
|
let mut arity = arity;
|
||||||
|
|
||||||
|
if iter.heap.len() > h + arity + 1 {
|
||||||
|
let value = iter.heap[h + arity + 1];
|
||||||
|
|
||||||
|
if let Some(idx) = get_structure_index(value) {
|
||||||
|
// in the second condition, arity == 0,
|
||||||
|
// meaning idx cannot pertain to this atom
|
||||||
|
// if it is the direct subterm of a larger
|
||||||
|
// structure.
|
||||||
|
if arity > 0 || !iter.direct_subterm_of_str(h) {
|
||||||
|
term_stack.push(
|
||||||
|
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
|
||||||
|
);
|
||||||
|
|
||||||
|
arity += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if arity == 0 {
|
if arity == 0 {
|
||||||
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
|
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
|
||||||
} else {
|
} else {
|
||||||
@@ -509,31 +599,27 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
term_stack.push(Term::Clause(Cell::default(), name, subterms));
|
term_stack.push(Term::Clause(Cell::default(), name, subterms));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStr, string) => {
|
(HeapCellValueTag::PStr, atom) => {
|
||||||
let tail = term_stack.pop().unwrap();
|
let tail = term_stack.pop().unwrap();
|
||||||
|
|
||||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
|
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
|
||||||
term_stack.push(Term::PartialString(
|
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
||||||
Cell::default(),
|
|
||||||
string,
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
} else {
|
} else {
|
||||||
term_stack.push(Term::PartialString(
|
term_stack.push(Term::PartialString(
|
||||||
Cell::default(),
|
Cell::default(),
|
||||||
string,
|
atom.as_str().to_owned(),
|
||||||
Some(Box::new(tail)),
|
Box::new(tail),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStrLoc, h) => {
|
(HeapCellValueTag::PStrLoc, h) => {
|
||||||
let string = cell_as_atom_cell!(iter.heap[h]).get_name();
|
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
|
||||||
let tail = term_stack.pop().unwrap();
|
let tail = term_stack.pop().unwrap();
|
||||||
|
|
||||||
term_stack.push(Term::PartialString(
|
term_stack.push(Term::PartialString(
|
||||||
Cell::default(),
|
Cell::default(),
|
||||||
string,
|
atom.as_str().to_owned(),
|
||||||
Some(Box::new(tail)),
|
Box::new(tail),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -701,7 +787,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
module
|
module
|
||||||
.code_dir
|
.code_dir
|
||||||
.get_mut(&key)
|
.get_mut(&key)
|
||||||
.map(|code_idx| code_idx.replace(old_code_idx));
|
.map(|code_idx| code_idx.set(old_code_idx));
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
@@ -726,10 +812,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.indices
|
.indices
|
||||||
.code_dir
|
.code_dir
|
||||||
.get_mut(&key)
|
.get_mut(&key)
|
||||||
.map(|code_idx| code_idx.replace(old_code_idx));
|
.map(|code_idx| code_idx.set(old_code_idx));
|
||||||
}
|
}
|
||||||
RetractionRecord::AddedIndex(index_key, clause_loc) => {
|
RetractionRecord::AddedIndex(index_key, clause_loc) => {
|
||||||
// WAS: inner_index_locs) => {
|
|
||||||
if let Some(index_loc) = index_key.switch_on_term_loc() {
|
if let Some(index_loc) = index_key.switch_on_term_loc() {
|
||||||
let indexing_code = match &mut self.wam_prelude.code[index_loc] {
|
let indexing_code = match &mut self.wam_prelude.code[index_loc] {
|
||||||
Instruction::IndexingCode(indexing_code) => indexing_code,
|
Instruction::IndexingCode(indexing_code) => indexing_code,
|
||||||
@@ -900,7 +985,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
key,
|
key,
|
||||||
) {
|
) {
|
||||||
Some(skeleton) => {
|
Some(skeleton) => {
|
||||||
skeleton.clause_clause_locs.truncate_back(len);
|
skeleton.clause_clause_locs.truncate(len);
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
@@ -912,8 +997,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.get_predicate_skeleton_mut(&compilation_target, &key)
|
.get_predicate_skeleton_mut(&compilation_target, &key)
|
||||||
{
|
{
|
||||||
Some(skeleton) => {
|
Some(skeleton) => {
|
||||||
skeleton.clauses.truncate_back(len);
|
skeleton.clauses.truncate(len);
|
||||||
skeleton.core.clause_clause_locs.truncate_back(len);
|
skeleton.core.clause_clause_locs.truncate(len);
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
@@ -1264,13 +1349,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
let code_index = self.get_or_insert_code_index(key, compilation_target);
|
let code_index = self.get_or_insert_code_index(key, compilation_target);
|
||||||
|
|
||||||
if let IndexPtr::Undefined = code_index.get() {
|
if code_index.is_undefined() {
|
||||||
set_code_index(
|
set_code_index(
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload.retraction_info,
|
||||||
&compilation_target,
|
&compilation_target,
|
||||||
key,
|
key,
|
||||||
&code_index,
|
code_index,
|
||||||
IndexPtr::DynamicUndefined,
|
IndexPtr::dynamic_undefined(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1358,7 +1443,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
*key,
|
*key,
|
||||||
) {
|
) {
|
||||||
Some(skeleton) if !skeleton.clause_clause_locs.is_empty() => {
|
Some(skeleton) if !skeleton.clause_clause_locs.is_empty() => {
|
||||||
mem::replace(&mut skeleton.clause_clause_locs, sdeq![])
|
mem::replace(&mut skeleton.clause_clause_locs, VecDeque::new())
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
@@ -1484,7 +1569,6 @@ impl Machine {
|
|||||||
let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
|
let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
|
||||||
|
|
||||||
let declare_module = || {
|
let declare_module = || {
|
||||||
// let export_list = export_list?;
|
|
||||||
let exports = loader.extract_module_export_list_from_heap(temp_v!(2))?;
|
let exports = loader.extract_module_export_list_from_heap(temp_v!(2))?;
|
||||||
|
|
||||||
let module_decl = ModuleDecl {
|
let module_decl = ModuleDecl {
|
||||||
@@ -1837,7 +1921,7 @@ impl Machine {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return self.load_context_module();
|
return self.load_context_module(self.machine_st.registers[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1859,9 +1943,9 @@ impl Machine {
|
|||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn load_context_module(&mut self) {
|
pub(crate) fn load_context_module(&mut self, target: HeapCellValue) {
|
||||||
if let Some(load_context) = self.load_contexts.last() {
|
if let Some(load_context) = self.load_contexts.last() {
|
||||||
self.machine_st.unify_atom(load_context.module, self.machine_st.registers[1]);
|
self.machine_st.unify_atom(load_context.module, target);
|
||||||
} else {
|
} else {
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
}
|
}
|
||||||
@@ -1878,13 +1962,10 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn compile_assert<'a>(&'a mut self, append_or_prepend: AppendOrPrepend) -> CallResult {
|
pub(crate) fn compile_assert(&mut self, append_or_prepend: AppendOrPrepend) -> CallResult
|
||||||
let key = self
|
{
|
||||||
.machine_st
|
|
||||||
.read_predicate_key(self.machine_st[temp_v!(3)], self.machine_st[temp_v!(4)]);
|
|
||||||
|
|
||||||
let module_name = cell_as_atom!(
|
let module_name = cell_as_atom!(
|
||||||
self.machine_st.store(self.machine_st.deref(self.machine_st.registers[5]))
|
self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
|
||||||
);
|
);
|
||||||
|
|
||||||
let compilation_target = match module_name {
|
let compilation_target = match module_name {
|
||||||
@@ -1892,14 +1973,62 @@ impl Machine {
|
|||||||
_ => CompilationTarget::Module(module_name),
|
_ => CompilationTarget::Module(module_name),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let stub_gen = || {
|
||||||
|
match append_or_prepend {
|
||||||
|
AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1),
|
||||||
|
AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut compile_assert = || {
|
let mut compile_assert = || {
|
||||||
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
|
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
|
||||||
Loader::new(self, LiveTermStream::new(ListingSource::User));
|
Loader::new(self, LiveTermStream::new(ListingSource::User));
|
||||||
|
|
||||||
loader.payload.compilation_target = compilation_target;
|
loader.payload.compilation_target = compilation_target;
|
||||||
|
|
||||||
let head = loader.read_term_from_heap(temp_v!(1))?;
|
let head = loader.read_term_from_heap(temp_v!(2))?;
|
||||||
let body = loader.read_term_from_heap(temp_v!(2))?;
|
|
||||||
|
let name = if let Some(name) = head.name() {
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
return Err(SessionError::from(CompilationError::InvalidRuleHead));
|
||||||
|
};
|
||||||
|
|
||||||
|
let arity = head.arity();
|
||||||
|
|
||||||
|
let is_dynamic_predicate = loader
|
||||||
|
.wam_prelude
|
||||||
|
.indices
|
||||||
|
.is_dynamic_predicate(
|
||||||
|
module_name,
|
||||||
|
(name, arity),
|
||||||
|
);
|
||||||
|
|
||||||
|
let no_such_predicate =
|
||||||
|
if !is_dynamic_predicate && !ClauseType::is_inbuilt(name, arity) {
|
||||||
|
let idx_tag = loader
|
||||||
|
.wam_prelude
|
||||||
|
.indices
|
||||||
|
.get_predicate_code_index(
|
||||||
|
name,
|
||||||
|
arity,
|
||||||
|
module_name,
|
||||||
|
)
|
||||||
|
.map(|code_idx| code_idx.get_tag())
|
||||||
|
.unwrap_or(IndexPtrTag::DynamicUndefined);
|
||||||
|
|
||||||
|
idx_tag == IndexPtrTag::DynamicUndefined ||
|
||||||
|
idx_tag == IndexPtrTag::Undefined
|
||||||
|
} else {
|
||||||
|
is_dynamic_predicate
|
||||||
|
};
|
||||||
|
|
||||||
|
if !no_such_predicate {
|
||||||
|
LiveLoadAndMachineState::machine_st(&mut loader.payload).fail = true;
|
||||||
|
return LiveLoadAndMachineState::evacuate(loader);
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = loader.read_term_from_heap(temp_v!(3))?;
|
||||||
|
|
||||||
let asserted_clause = Term::Clause(
|
let asserted_clause = Term::Clause(
|
||||||
Cell::default(),
|
Cell::default(),
|
||||||
@@ -1908,10 +2037,10 @@ impl Machine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// if a new predicate was just created, make it dynamic.
|
// if a new predicate was just created, make it dynamic.
|
||||||
loader.add_dynamic_predicate(compilation_target, key.0, key.1)?;
|
loader.add_dynamic_predicate(compilation_target, name, arity)?;
|
||||||
|
|
||||||
loader.incremental_compile_clause(
|
loader.incremental_compile_clause(
|
||||||
key,
|
(name, arity),
|
||||||
asserted_clause,
|
asserted_clause,
|
||||||
compilation_target,
|
compilation_target,
|
||||||
false,
|
false,
|
||||||
@@ -1922,7 +2051,7 @@ impl Machine {
|
|||||||
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
|
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
|
||||||
|
|
||||||
loader.compile_clause_clauses(
|
loader.compile_clause_clauses(
|
||||||
key,
|
(name, arity),
|
||||||
compilation_target,
|
compilation_target,
|
||||||
std::iter::once((head, body)),
|
std::iter::once((head, body)),
|
||||||
append_or_prepend,
|
append_or_prepend,
|
||||||
@@ -1933,14 +2062,30 @@ impl Machine {
|
|||||||
|
|
||||||
match compile_assert() {
|
match compile_assert() {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(e) => {
|
Err(SessionError::CompilationError(
|
||||||
let stub = match append_or_prepend {
|
CompilationError::InvalidRuleHead |
|
||||||
AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1),
|
CompilationError::InadmissibleFact
|
||||||
AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1),
|
)) => {
|
||||||
};
|
let err = self.machine_st.type_error(
|
||||||
let err = self.machine_st.session_error(e);
|
ValidType::Callable,
|
||||||
|
self.machine_st.registers[2],
|
||||||
|
);
|
||||||
|
|
||||||
Err(self.machine_st.error_form(err, stub))
|
Err(self.machine_st.error_form(err, stub_gen()))
|
||||||
|
}
|
||||||
|
Err(SessionError::CompilationError(
|
||||||
|
CompilationError::InadmissibleQueryTerm
|
||||||
|
)) => {
|
||||||
|
let err = self.machine_st.type_error(
|
||||||
|
ValidType::Callable,
|
||||||
|
self.machine_st.registers[3],
|
||||||
|
);
|
||||||
|
|
||||||
|
Err(self.machine_st.error_form(err, stub_gen()))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let err = self.machine_st.session_error(e);
|
||||||
|
Err(self.machine_st.error_form(err, stub_gen()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1973,18 +2118,17 @@ impl Machine {
|
|||||||
let mut clause_clause_target_poses: Vec<_> = loader
|
let mut clause_clause_target_poses: Vec<_> = loader
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_skeleton(&compilation_target, &key)
|
.remove_predicate_skeleton(&compilation_target, &key)
|
||||||
.map(|skeleton| {
|
.map(|skeleton| {
|
||||||
loader
|
let mut clause_clause_skeleton = loader
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_skeleton(
|
.remove_predicate_skeleton(
|
||||||
&clause_clause_compilation_target,
|
&clause_clause_compilation_target,
|
||||||
&(atom!("$clause"), 2),
|
&(atom!("$clause"), 2),
|
||||||
)
|
).unwrap();
|
||||||
.map(|clause_clause_skeleton| {
|
|
||||||
skeleton
|
let result = skeleton.core
|
||||||
.core
|
|
||||||
.clause_clause_locs
|
.clause_clause_locs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|clause_clause_loc| {
|
.map(|clause_clause_loc| {
|
||||||
@@ -1992,30 +2136,31 @@ impl Machine {
|
|||||||
.target_pos_of_clause_clause_loc(*clause_clause_loc)
|
.target_pos_of_clause_clause_loc(*clause_clause_loc)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect();
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
loader
|
loader.add_extensible_predicate(
|
||||||
.wam_prelude
|
key,
|
||||||
|
skeleton,
|
||||||
|
compilation_target,
|
||||||
|
);
|
||||||
|
|
||||||
|
loader.add_extensible_predicate(
|
||||||
|
(atom!("$clause"), 2),
|
||||||
|
clause_clause_skeleton,
|
||||||
|
clause_clause_compilation_target,
|
||||||
|
);
|
||||||
|
|
||||||
|
result
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
loader.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
.remove_predicate_skeleton(&compilation_target, &key);
|
.remove_predicate_skeleton(&compilation_target, &key);
|
||||||
|
|
||||||
let code_index = loader
|
let mut code_index = loader
|
||||||
.get_or_insert_code_index(key, compilation_target);
|
.get_or_insert_code_index(key, compilation_target);
|
||||||
|
|
||||||
code_index.set(IndexPtr::Undefined);
|
code_index.set(IndexPtr::undefined());
|
||||||
|
|
||||||
/*
|
|
||||||
loader
|
|
||||||
.wam_prelude
|
|
||||||
.indices
|
|
||||||
.get_predicate_skeleton_mut(&compilation_target, &key)
|
|
||||||
.map(|skeleton| skeleton.reset());
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
loader.payload.compilation_target = clause_clause_compilation_target;
|
loader.payload.compilation_target = clause_clause_compilation_target;
|
||||||
|
|
||||||
@@ -2076,7 +2221,7 @@ impl Machine {
|
|||||||
// the global clock is incremented after each retraction.
|
// the global clock is incremented after each retraction.
|
||||||
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
|
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
|
||||||
|
|
||||||
let target_pos = match loader.wam_prelude.indices.get_predicate_skeleton(
|
let target_pos = match loader.wam_prelude.indices.get_predicate_skeleton_mut(
|
||||||
&clause_clause_compilation_target,
|
&clause_clause_compilation_target,
|
||||||
&(atom!("$clause"), 2),
|
&(atom!("$clause"), 2),
|
||||||
) {
|
) {
|
||||||
@@ -2180,7 +2325,7 @@ impl Machine {
|
|||||||
|
|
||||||
let (predicate_name, arity) = self
|
let (predicate_name, arity) = self
|
||||||
.machine_st
|
.machine_st
|
||||||
.read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]);
|
.read_predicate_key(self.machine_st.registers[2], self.machine_st.registers[3]);
|
||||||
|
|
||||||
let compilation_target = match module_name {
|
let compilation_target = match module_name {
|
||||||
atom!("user") => CompilationTarget::User,
|
atom!("user") => CompilationTarget::User,
|
||||||
@@ -2192,21 +2337,25 @@ impl Machine {
|
|||||||
.get_meta_predicate_spec(predicate_name, arity, &compilation_target)
|
.get_meta_predicate_spec(predicate_name, arity, &compilation_target)
|
||||||
{
|
{
|
||||||
Some(meta_specs) => {
|
Some(meta_specs) => {
|
||||||
let list_loc = iter_to_heap_list(
|
let term_loc = self.machine_st.heap.len();
|
||||||
&mut self.machine_st.heap,
|
|
||||||
|
self.machine_st.heap.push(atom_as_cell!(predicate_name, arity));
|
||||||
|
self.machine_st.heap.extend(
|
||||||
meta_specs.iter().map(|meta_spec| match meta_spec {
|
meta_specs.iter().map(|meta_spec| match meta_spec {
|
||||||
MetaSpec::Minus => atom_as_cell!(atom!("+")),
|
MetaSpec::Minus => atom_as_cell!(atom!("+")),
|
||||||
MetaSpec::Plus => atom_as_cell!(atom!("-")),
|
MetaSpec::Plus => atom_as_cell!(atom!("-")),
|
||||||
MetaSpec::Either => atom_as_cell!(atom!("?")),
|
MetaSpec::Either => atom_as_cell!(atom!("?")),
|
||||||
|
MetaSpec::Colon => atom_as_cell!(atom!(":")),
|
||||||
MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
|
MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
|
||||||
fixnum_as_cell!(Fixnum::build_with(*arg_num as i64))
|
fixnum_as_cell!(Fixnum::build_with(*arg_num as i64))
|
||||||
}
|
}
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
let heap_loc = self.machine_st.heap.len();
|
let heap_loc = self.machine_st.heap.len();
|
||||||
|
|
||||||
self.machine_st.heap.push(atom_as_cell!(atom!("meta_predicate"), 1));
|
self.machine_st.heap.push(atom_as_cell!(atom!("meta_predicate"), 1));
|
||||||
self.machine_st.heap.push(heap_loc_as_cell!(list_loc));
|
self.machine_st.heap.push(str_loc_as_cell!(term_loc));
|
||||||
|
|
||||||
unify!(self.machine_st, str_loc_as_cell!(heap_loc), self.machine_st.registers[4]);
|
unify!(self.machine_st, str_loc_as_cell!(heap_loc), self.machine_st.registers[4]);
|
||||||
}
|
}
|
||||||
@@ -2298,22 +2447,16 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn builtin_property(&mut self) {
|
pub(crate) fn builtin_property(&mut self) {
|
||||||
let key = self
|
let (name, arity) = self
|
||||||
.machine_st
|
.machine_st
|
||||||
.read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]);
|
.read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]);
|
||||||
|
|
||||||
match ClauseType::from(key.0, key.1) {
|
if !ClauseType::is_inbuilt(name, arity) { // ClauseType::from(key.0, key.1, &mut self.machine_st.arena) {
|
||||||
ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN(_) => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ClauseType::Named(arity, name, _) => {
|
|
||||||
if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) {
|
if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) {
|
||||||
self.machine_st.fail = !module.code_dir.contains_key(&(name, arity));
|
self.machine_st.fail = !module.code_dir.contains_key(&(name, arity));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
}
|
}
|
||||||
@@ -2344,14 +2487,19 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn load_module(
|
pub(super) fn load_module(
|
||||||
|
machine_st: &mut MachineState,
|
||||||
code_dir: &mut CodeDir,
|
code_dir: &mut CodeDir,
|
||||||
op_dir: &mut OpDir,
|
op_dir: &mut OpDir,
|
||||||
meta_predicate_dir: &mut MetaPredicateDir,
|
meta_predicate_dir: &mut MetaPredicateDir,
|
||||||
compilation_target: &CompilationTarget,
|
compilation_target: &CompilationTarget,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
) {
|
) {
|
||||||
import_module_exports(
|
let ts = LiveTermStream::new(ListingSource::User);
|
||||||
&mut RetractionInfo::new(0),
|
let payload = LoadStatePayload::new(0, ts);
|
||||||
|
let mut payload = LiveLoadAndMachineState::new(machine_st, payload);
|
||||||
|
|
||||||
|
import_module_exports::<LiveLoadAndMachineState>(
|
||||||
|
&mut payload,
|
||||||
&compilation_target,
|
&compilation_target,
|
||||||
module,
|
module,
|
||||||
code_dir,
|
code_dir,
|
||||||
|
|||||||
@@ -257,6 +257,19 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn resource_error(&mut self, value: HeapCellValue) -> MachineError {
|
||||||
|
let stub = functor!(
|
||||||
|
atom!("resource_error"),
|
||||||
|
[atom(atom!("finite_memory")), cell(value)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn type_error<T: TypeError>(
|
pub(super) fn type_error<T: TypeError>(
|
||||||
&mut self,
|
&mut self,
|
||||||
valid_type: ValidType,
|
valid_type: ValidType,
|
||||||
@@ -439,6 +452,9 @@ impl MachineState {
|
|||||||
SessionError::OpIsInfixAndPostFix(op) => {
|
SessionError::OpIsInfixAndPostFix(op) => {
|
||||||
self.permission_error(Permission::Create, atom!("operator"), functor!(op))
|
self.permission_error(Permission::Create, atom!("operator"), functor!(op))
|
||||||
}
|
}
|
||||||
|
SessionError::CompilationError(CompilationError::ExceededMaxArity) => {
|
||||||
|
self.representation_error(RepFlag::MaxArity)
|
||||||
|
}
|
||||||
SessionError::CompilationError(err) => self.syntax_error(err),
|
SessionError::CompilationError(err) => self.syntax_error(err),
|
||||||
SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
|
SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
|
||||||
let functor_stub = functor_stub(key.0, key.1);
|
let functor_stub = functor_stub(key.0, key.1);
|
||||||
@@ -572,16 +588,12 @@ impl MachineError {
|
|||||||
pub enum CompilationError {
|
pub enum CompilationError {
|
||||||
Arithmetic(ArithmeticError),
|
Arithmetic(ArithmeticError),
|
||||||
ParserError(ParserError),
|
ParserError(ParserError),
|
||||||
// BadPendingByte,
|
|
||||||
CannotParseCyclicTerm,
|
CannotParseCyclicTerm,
|
||||||
// ExpandedTermsListNotAList,
|
ExceededMaxArity,
|
||||||
ExpectedRel,
|
ExpectedRel,
|
||||||
// ExpectedTopLevelTerm,
|
|
||||||
InadmissibleFact,
|
InadmissibleFact,
|
||||||
InadmissibleQueryTerm,
|
InadmissibleQueryTerm,
|
||||||
InconsistentEntry,
|
InconsistentEntry,
|
||||||
// InvalidDoubleQuotesDecl,
|
|
||||||
// InvalidHook,
|
|
||||||
InvalidMetaPredicateDecl,
|
InvalidMetaPredicateDecl,
|
||||||
InvalidModuleDecl,
|
InvalidModuleDecl,
|
||||||
InvalidModuleExport,
|
InvalidModuleExport,
|
||||||
@@ -618,31 +630,24 @@ impl CompilationError {
|
|||||||
&CompilationError::Arithmetic(..) => {
|
&CompilationError::Arithmetic(..) => {
|
||||||
functor!(atom!("arithmetic_error"))
|
functor!(atom!("arithmetic_error"))
|
||||||
}
|
}
|
||||||
// &CompilationError::BadPendingByte =>
|
|
||||||
// functor!(atom_from_ss!("bad_pending_byte"), atom_tbl),
|
|
||||||
&CompilationError::CannotParseCyclicTerm => {
|
&CompilationError::CannotParseCyclicTerm => {
|
||||||
functor!(atom!("cannot_parse_cyclic_term"))
|
functor!(atom!("cannot_parse_cyclic_term"))
|
||||||
}
|
}
|
||||||
// &CompilationError::ExpandedTermsListNotAList =>
|
&CompilationError::ExceededMaxArity => {
|
||||||
// functor!(atom_tbl.build_with_static_str("expanded_terms_list_is_not_a_list")),
|
functor!(atom!("exceeded_max_arity"))
|
||||||
|
}
|
||||||
&CompilationError::ExpectedRel => {
|
&CompilationError::ExpectedRel => {
|
||||||
functor!(atom!("expected_relation"))
|
functor!(atom!("expected_relation"))
|
||||||
}
|
}
|
||||||
// &CompilationError::ExpectedTopLevelTerm =>
|
&CompilationError::InadmissibleFact => { // TODO: type_error(callable, _).
|
||||||
// functor!(atom_from_ss!("expected_atom_or_cons_or_clause"), atom_tbl),
|
|
||||||
&CompilationError::InadmissibleFact => {
|
|
||||||
functor!(atom!("inadmissible_fact"))
|
functor!(atom!("inadmissible_fact"))
|
||||||
}
|
}
|
||||||
&CompilationError::InadmissibleQueryTerm => {
|
&CompilationError::InadmissibleQueryTerm => { // TODO: type_error(callable, _).
|
||||||
functor!(atom!("inadmissible_query_term"))
|
functor!(atom!("inadmissible_query_term"))
|
||||||
}
|
}
|
||||||
&CompilationError::InconsistentEntry => {
|
&CompilationError::InconsistentEntry => {
|
||||||
functor!(atom!("inconsistent_entry"))
|
functor!(atom!("inconsistent_entry"))
|
||||||
}
|
}
|
||||||
// &CompilationError::InvalidDoubleQuotesDecl =>
|
|
||||||
// functor!(atom_from_ss!("invalid_double_quotes_declaration"), atom_tbl),
|
|
||||||
// &CompilationError::InvalidHook =>
|
|
||||||
// functor!(atom_from_ss!("invalid_hook"), atom_tbl),
|
|
||||||
&CompilationError::InvalidMetaPredicateDecl => {
|
&CompilationError::InvalidMetaPredicateDecl => {
|
||||||
functor!(atom!("invalid_meta_predicate_decl"))
|
functor!(atom!("invalid_meta_predicate_decl"))
|
||||||
}
|
}
|
||||||
@@ -656,7 +661,8 @@ impl CompilationError {
|
|||||||
functor!(atom!("no_such_module"), [atom(module_name)])
|
functor!(atom!("no_such_module"), [atom(module_name)])
|
||||||
}
|
}
|
||||||
&CompilationError::InvalidRuleHead => {
|
&CompilationError::InvalidRuleHead => {
|
||||||
functor!(atom!("invalid_head_of_rule"))
|
|
||||||
|
functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
|
||||||
}
|
}
|
||||||
&CompilationError::InvalidUseModuleDecl => {
|
&CompilationError::InvalidUseModuleDecl => {
|
||||||
functor!(atom!("invalid_use_module_declaration"))
|
functor!(atom!("invalid_use_module_declaration"))
|
||||||
@@ -785,14 +791,14 @@ impl MachineState {
|
|||||||
let stub_gen = || functor_stub(atom!("sort"), 2);
|
let stub_gen = || functor_stub(atom!("sort"), 2);
|
||||||
|
|
||||||
let list = self.store(self.deref(self.registers[1]));
|
let list = self.store(self.deref(self.registers[1]));
|
||||||
let sorted = self.registers[2];
|
let sorted = self.store(self.deref(self.registers[2]));
|
||||||
|
|
||||||
match BrentAlgState::detect_cycles(&self.heap, list) {
|
match BrentAlgState::detect_cycles(&self.heap, list) {
|
||||||
CycleSearchResult::PartialList(..) => {
|
CycleSearchResult::PartialList(..) => {
|
||||||
let err = self.instantiation_error();
|
let err = self.instantiation_error();
|
||||||
return Err(self.error_form(err, stub_gen()))
|
return Err(self.error_form(err, stub_gen()))
|
||||||
}
|
}
|
||||||
CycleSearchResult::NotList(..) => {
|
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
|
||||||
let err = self.type_error(ValidType::List, list);
|
let err = self.type_error(ValidType::List, list);
|
||||||
return Err(self.error_form(err, stub_gen()));
|
return Err(self.error_form(err, stub_gen()));
|
||||||
}
|
}
|
||||||
@@ -800,7 +806,7 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match BrentAlgState::detect_cycles(&self.heap, sorted) {
|
match BrentAlgState::detect_cycles(&self.heap, sorted) {
|
||||||
CycleSearchResult::NotList(..) if !sorted.is_var() => {
|
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !sorted.is_var() => {
|
||||||
let err = self.type_error(ValidType::List, sorted);
|
let err = self.type_error(ValidType::List, sorted);
|
||||||
Err(self.error_form(err, stub_gen()))
|
Err(self.error_form(err, stub_gen()))
|
||||||
}
|
}
|
||||||
@@ -812,7 +818,7 @@ impl MachineState {
|
|||||||
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
||||||
|
|
||||||
match BrentAlgState::detect_cycles(&self.heap, list) {
|
match BrentAlgState::detect_cycles(&self.heap, list) {
|
||||||
CycleSearchResult::NotList(..) if !list.is_var() => {
|
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !list.is_var() => {
|
||||||
let err = self.type_error(ValidType::List, list);
|
let err = self.type_error(ValidType::List, list);
|
||||||
Err(self.error_form(err, stub_gen()))
|
Err(self.error_form(err, stub_gen()))
|
||||||
}
|
}
|
||||||
@@ -878,7 +884,7 @@ impl MachineState {
|
|||||||
let err = self.instantiation_error();
|
let err = self.instantiation_error();
|
||||||
Err(self.error_form(err, stub_gen()))
|
Err(self.error_form(err, stub_gen()))
|
||||||
}
|
}
|
||||||
CycleSearchResult::NotList(..) => {
|
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
|
||||||
let err = self.type_error(ValidType::List, pairs);
|
let err = self.type_error(ValidType::List, pairs);
|
||||||
Err(self.error_form(err, stub_gen()))
|
Err(self.error_form(err, stub_gen()))
|
||||||
}
|
}
|
||||||
@@ -902,9 +908,7 @@ pub enum ExistenceError {
|
|||||||
pub enum SessionError {
|
pub enum SessionError {
|
||||||
CompilationError(CompilationError),
|
CompilationError(CompilationError),
|
||||||
CannotOverwriteBuiltIn(PredicateKey),
|
CannotOverwriteBuiltIn(PredicateKey),
|
||||||
// CannotOverwriteImport(Atom),
|
|
||||||
ExistenceError(ExistenceError),
|
ExistenceError(ExistenceError),
|
||||||
// InvalidFileName(Atom),
|
|
||||||
ModuleDoesNotContainExport(Atom, PredicateKey),
|
ModuleDoesNotContainExport(Atom, PredicateKey),
|
||||||
ModuleCannotImportSelf(Atom),
|
ModuleCannotImportSelf(Atom),
|
||||||
NamelessEntry,
|
NamelessEntry,
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ use crate::arena::*;
|
|||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::fixtures::*;
|
use crate::fixtures::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::instructions::*;
|
|
||||||
use crate::machine::loader::*;
|
use crate::machine::loader::*;
|
||||||
use crate::machine::machine_state::*;
|
use crate::machine::machine_state::*;
|
||||||
use crate::machine::streams::Stream;
|
use crate::machine::streams::Stream;
|
||||||
|
|
||||||
use fxhash::FxBuildHasher;
|
use fxhash::FxBuildHasher;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use modular_bitfield::{BitfieldSpecifier, bitfield};
|
||||||
|
use modular_bitfield::specifiers::*;
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::ops::Deref;
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
@@ -59,9 +59,6 @@ impl PartialOrd<Ref> for HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => {
|
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => {
|
||||||
// _ if self.is_ref() => {
|
|
||||||
// let h1 = self.get_value();
|
|
||||||
|
|
||||||
match r.get_tag() {
|
match r.get_tag() {
|
||||||
RefTag::StackCell => Some(Ordering::Less),
|
RefTag::StackCell => Some(Ordering::Less),
|
||||||
_ => {
|
_ => {
|
||||||
@@ -77,52 +74,157 @@ impl PartialOrd<Ref> for HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum IndexPtr {
|
#[bits = 7]
|
||||||
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
pub enum IndexPtrTag {
|
||||||
DynamicIndex(usize),
|
DynamicUndefined = 0b1000101, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
||||||
Index(usize),
|
DynamicIndex = 0b1000110,
|
||||||
Undefined,
|
Index = 0b1000111,
|
||||||
|
Undefined = 0b1001000,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
#[bitfield]
|
||||||
pub struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>);
|
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
|
pub struct IndexPtr {
|
||||||
|
pub p: B56,
|
||||||
|
#[allow(unused)] m: bool,
|
||||||
|
pub tag: IndexPtrTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn dynamic_undefined() -> Self {
|
||||||
|
IndexPtr::new()
|
||||||
|
.with_p(0)
|
||||||
|
.with_m(false)
|
||||||
|
.with_tag(IndexPtrTag::DynamicUndefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn undefined() -> Self {
|
||||||
|
IndexPtr::new()
|
||||||
|
.with_p(0)
|
||||||
|
.with_m(false)
|
||||||
|
.with_tag(IndexPtrTag::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn dynamic_index(p: usize) -> Self {
|
||||||
|
IndexPtr::new()
|
||||||
|
.with_p(p as u64)
|
||||||
|
.with_m(false)
|
||||||
|
.with_tag(IndexPtrTag::DynamicIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn index(p: usize) -> Self {
|
||||||
|
IndexPtr::new()
|
||||||
|
.with_p(p as u64)
|
||||||
|
.with_m(false)
|
||||||
|
.with_tag(IndexPtrTag::Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn is_undefined(&self) -> bool {
|
||||||
|
match self.tag() {
|
||||||
|
IndexPtrTag::Undefined => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn is_dynamic_undefined(&self) -> bool {
|
||||||
|
match self.tag() {
|
||||||
|
IndexPtrTag::DynamicUndefined => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)]
|
||||||
|
pub struct CodeIndex(TypedArenaPtr<IndexPtr>);
|
||||||
|
|
||||||
|
const_assert!(std::mem::align_of::<CodeIndex>() == 8);
|
||||||
|
|
||||||
impl Deref for CodeIndex {
|
impl Deref for CodeIndex {
|
||||||
type Target = Cell<IndexPtr>;
|
type Target = TypedArenaPtr<IndexPtr>;
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &TypedArenaPtr<IndexPtr> {
|
||||||
self.0.deref()
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for CodeIndex {
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref_mut(&mut self) -> &mut TypedArenaPtr<IndexPtr> {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodeIndex> for UntypedArenaPtr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(ptr: CodeIndex) -> UntypedArenaPtr {
|
||||||
|
unsafe { std::mem::transmute(ptr.0.as_ptr()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UntypedArenaPtr> for CodeIndex {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(ptr: UntypedArenaPtr) -> CodeIndex {
|
||||||
|
CodeIndex(TypedArenaPtr::new(ptr.get_ptr() as *mut IndexPtr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TypedArenaPtr<IndexPtr>> for CodeIndex {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(ptr: TypedArenaPtr<IndexPtr>) -> CodeIndex {
|
||||||
|
CodeIndex(ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeIndex {
|
impl CodeIndex {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn new(ptr: IndexPtr) -> Self {
|
pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self {
|
||||||
CodeIndex(Rc::new(Cell::new(ptr)))
|
CodeIndex(arena_alloc!(ptr, arena))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub(crate) fn is_undefined(&self) -> bool {
|
pub(crate) fn default(arena: &mut Arena) -> Self {
|
||||||
match self.0.get() {
|
CodeIndex::new(IndexPtr::undefined(), arena)
|
||||||
IndexPtr::Undefined => true, // | &IndexPtr::DynamicUndefined => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn local(&self) -> Option<usize> {
|
pub(crate) fn local(&self) -> Option<usize> {
|
||||||
match self.0.get() {
|
match self.0.tag() {
|
||||||
IndexPtr::Index(i) => Some(i),
|
IndexPtrTag::Index => Some(self.0.p() as usize),
|
||||||
IndexPtr::DynamicIndex(i) => Some(i),
|
IndexPtrTag::DynamicIndex => Some(self.0.p() as usize),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for CodeIndex {
|
#[inline(always)]
|
||||||
fn default() -> Self {
|
pub(crate) fn get(&self) -> IndexPtr {
|
||||||
CodeIndex(Rc::new(Cell::new(IndexPtr::Undefined)))
|
*self.0.deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set(&mut self, value: IndexPtr) {
|
||||||
|
*self.0.deref_mut() = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn get_tag(self) -> IndexPtrTag {
|
||||||
|
self.0.tag()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn replace(&mut self, value: IndexPtr) -> IndexPtr {
|
||||||
|
std::mem::replace(self.0.deref_mut(), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn as_ptr(&self) -> *const IndexPtr {
|
||||||
|
self.0.as_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,19 +371,22 @@ impl IndexStore {
|
|||||||
module: Atom,
|
module: Atom,
|
||||||
) -> Option<CodeIndex> {
|
) -> Option<CodeIndex> {
|
||||||
if module == atom!("user") {
|
if module == atom!("user") {
|
||||||
match ClauseType::from(name, arity) {
|
/*match ClauseType::from(name, arity) {
|
||||||
ClauseType::Named(arity, name, _) => self.code_dir.get(&(name, arity)).cloned(),
|
ClauseType::Named(arity, name, _) => */
|
||||||
_ => None,
|
self.code_dir.get(&(name, arity)).cloned()
|
||||||
}
|
/* _ => None,
|
||||||
|
}*/
|
||||||
} else {
|
} else {
|
||||||
self.modules
|
self.modules
|
||||||
.get(&module)
|
.get(&module)
|
||||||
.and_then(|module| match ClauseType::from(name, arity) {
|
.and_then(|module|/* |module| match ClauseType::from(name, arity) {
|
||||||
ClauseType::Named(arity, name, _) => {
|
ClauseType::Named(arity, name, _) => { */
|
||||||
module.code_dir.get(&(name, arity)).cloned()
|
module.code_dir.get(&(name, arity)).cloned()
|
||||||
|
/*
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
} */
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ pub struct MachineState {
|
|||||||
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) ball_stack: Vec<Ball>, // save current ball before jumping via, e.g., verify_attr interrupt.
|
||||||
pub(super) lifted_heap: Heap,
|
pub(super) lifted_heap: Heap,
|
||||||
pub(super) interms: Vec<Number>, // intermediate numbers.
|
pub(super) interms: Vec<Number>, // intermediate numbers.
|
||||||
// locations of cleaners, cut points, the previous block. for setup_call_cleanup.
|
// locations of cleaners, cut points, the previous block. for setup_call_cleanup.
|
||||||
@@ -113,6 +114,7 @@ impl fmt::Debug for MachineState {
|
|||||||
.field("hb", &self.hb)
|
.field("hb", &self.hb)
|
||||||
.field("block", &self.block)
|
.field("block", &self.block)
|
||||||
.field("ball", &self.ball)
|
.field("ball", &self.ball)
|
||||||
|
.field("ball_stack", &self.ball_stack)
|
||||||
.field("lifted_heap", &self.lifted_heap)
|
.field("lifted_heap", &self.lifted_heap)
|
||||||
.field("interms", &self.interms)
|
.field("interms", &self.interms)
|
||||||
.field("flags", &self.flags)
|
.field("flags", &self.flags)
|
||||||
@@ -418,6 +420,17 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
if arity == 0 {
|
||||||
|
if let Some(c) = name.as_char() {
|
||||||
|
chars.push(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -454,6 +467,37 @@ impl MachineState {
|
|||||||
self.b0 = self.b;
|
self.b0 = self.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn neck_cut(&mut self) {
|
||||||
|
let b = self.b;
|
||||||
|
let b0 = self.b0;
|
||||||
|
|
||||||
|
if b > b0 {
|
||||||
|
self.b = b0;
|
||||||
|
|
||||||
|
if b > self.e {
|
||||||
|
self.stack.truncate(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safety: the atom_tbl lives for the lifetime of the machine, as does the helper, so the ptr
|
||||||
|
// will always be valid.
|
||||||
|
pub fn read_term_from_user_input(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
|
||||||
|
let atoms_ptr = (&self.atom_tbl.table) as *const indexmap::IndexSet<Atom>;
|
||||||
|
|
||||||
|
if let Stream::Readline(ptr) = stream {
|
||||||
|
unsafe {
|
||||||
|
let readline = ptr.as_ptr().as_mut().unwrap();
|
||||||
|
readline.set_atoms_for_completion(atoms_ptr);
|
||||||
|
let ret = self.read_term(stream, indices);
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!("Stream must be a Stream::Readline(_)")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
|
pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
|
||||||
fn push_var_eq_functors<'a>(
|
fn push_var_eq_functors<'a>(
|
||||||
heap: &mut Heap,
|
heap: &mut Heap,
|
||||||
@@ -494,7 +538,7 @@ impl MachineState {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
match self.read(stream, &indices.op_dir) {
|
match self.read(stream, &indices.op_dir) {
|
||||||
Ok(term_write_result) => {
|
Ok(mut term_write_result) => {
|
||||||
let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
|
let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
|
||||||
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
||||||
pstr_loc_as_cell!(term_write_result.heap_loc)
|
pstr_loc_as_cell!(term_write_result.heap_loc)
|
||||||
@@ -526,6 +570,10 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for var in term_write_result.var_dict.values_mut() {
|
||||||
|
*var = heap_bound_deref(&self.heap, *var);
|
||||||
|
}
|
||||||
|
|
||||||
let singleton_var_list = push_var_eq_functors(
|
let singleton_var_list = push_var_eq_functors(
|
||||||
&mut self.heap,
|
&mut self.heap,
|
||||||
term_write_result.var_dict.iter().filter(|(_, binding)| {
|
term_write_result.var_dict.iter().filter(|(_, binding)| {
|
||||||
@@ -585,7 +633,7 @@ impl MachineState {
|
|||||||
return Ok(unify_fn!(*self, var_names_offset, var_names_addr));
|
return Ok(unify_fn!(*self, var_names_offset, var_names_addr));
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if let ParserError::UnexpectedEOF = err {
|
if let CompilationError::ParserError(ParserError::UnexpectedEOF) = err {
|
||||||
self.eof_action(
|
self.eof_action(
|
||||||
self.registers[2],
|
self.registers[2],
|
||||||
stream,
|
stream,
|
||||||
@@ -641,7 +689,25 @@ impl MachineState {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var_names.insert(var, Rc::new(cell_as_atom!(atom).as_str().to_owned()));
|
read_heap_cell!(atom,
|
||||||
|
(HeapCellValueTag::Char, c) => {
|
||||||
|
var_names.insert(var, Rc::new(c.to_string()));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||||
|
debug_assert_eq!(_arity, 0);
|
||||||
|
var_names.insert(var, Rc::new(name.as_str().to_owned()));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
var_names.insert(var, Rc::new(name.as_str().to_owned()));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -649,34 +715,64 @@ impl MachineState {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ignore_ops = read_heap_cell!(ignore_ops,
|
||||||
|
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||||
|
name == atom!("true")
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
name == atom!("true")
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let numbervars = read_heap_cell!(numbervars,
|
||||||
|
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||||
|
name == atom!("true")
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
name == atom!("true")
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let quoted = read_heap_cell!(quoted,
|
||||||
|
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||||
|
name == atom!("true")
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
name == atom!("true")
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut self.heap,
|
&mut self.heap,
|
||||||
&mut self.arena,
|
|
||||||
op_dir,
|
op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
term_to_be_printed,
|
term_to_be_printed,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let HeapCellValueTag::Atom = ignore_ops.get_tag() {
|
printer.ignore_ops = ignore_ops;
|
||||||
let name = cell_as_atom!(ignore_ops);
|
printer.numbervars = numbervars;
|
||||||
printer.ignore_ops = name == atom!("true");
|
printer.quoted = quoted;
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let HeapCellValueTag::Atom = numbervars.get_tag() {
|
|
||||||
let name = cell_as_atom!(numbervars);
|
|
||||||
printer.numbervars = name == atom!("true");
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let HeapCellValueTag::Atom = quoted.get_tag() {
|
|
||||||
let name = cell_as_atom!(quoted);
|
|
||||||
printer.quoted = name == atom!("true");
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
|
|
||||||
match Number::try_from(max_depth) {
|
match Number::try_from(max_depth) {
|
||||||
Ok(Number::Fixnum(n)) => {
|
Ok(Number::Fixnum(n)) => {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -39,14 +39,14 @@ impl MockWAM {
|
|||||||
pub fn write_parsed_term_to_heap(
|
pub fn write_parsed_term_to_heap(
|
||||||
&mut self,
|
&mut self,
|
||||||
input_stream: Stream,
|
input_stream: Stream,
|
||||||
) -> Result<TermWriteResult, ParserError> {
|
) -> Result<TermWriteResult, CompilationError> {
|
||||||
self.machine_st.read(input_stream, &self.op_dir)
|
self.machine_st.read(input_stream, &self.op_dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_and_write_parsed_term_to_heap(
|
pub fn parse_and_write_parsed_term_to_heap(
|
||||||
&mut self,
|
&mut self,
|
||||||
term_string: &'static str,
|
term_string: &'static str,
|
||||||
) -> Result<TermWriteResult, ParserError> {
|
) -> Result<TermWriteResult, CompilationError> {
|
||||||
let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena);
|
let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena);
|
||||||
self.write_parsed_term_to_heap(stream)
|
self.write_parsed_term_to_heap(stream)
|
||||||
}
|
}
|
||||||
@@ -54,14 +54,13 @@ impl MockWAM {
|
|||||||
pub fn parse_and_print_term(
|
pub fn parse_and_print_term(
|
||||||
&mut self,
|
&mut self,
|
||||||
term_string: &'static str,
|
term_string: &'static str,
|
||||||
) -> Result<String, ParserError> {
|
) -> Result<String, CompilationError> {
|
||||||
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
|
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
|
||||||
|
|
||||||
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
|
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
|
||||||
|
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut self.machine_st.heap,
|
&mut self.machine_st.heap,
|
||||||
&mut self.machine_st.arena,
|
|
||||||
&self.op_dir,
|
&self.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(term_write_result.heap_loc),
|
heap_loc_as_cell!(term_write_result.heap_loc),
|
||||||
@@ -168,7 +167,7 @@ pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
|
|||||||
idx
|
idx
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
cell.get_forwarding_bit() != Some(true),
|
!cell.get_forwarding_bit(),
|
||||||
"cell {:?} at index {} is forwarded",
|
"cell {:?} at index {} is forwarded",
|
||||||
cell,
|
cell,
|
||||||
idx
|
idx
|
||||||
@@ -187,7 +186,7 @@ pub fn all_cells_unmarked(heap: &Heap) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
cell.get_forwarding_bit() != Some(true),
|
!cell.get_forwarding_bit(),
|
||||||
"cell {:?} at index {} is still forwarded",
|
"cell {:?} at index {} is still forwarded",
|
||||||
cell,
|
cell,
|
||||||
idx
|
idx
|
||||||
@@ -200,7 +199,7 @@ pub(crate) fn write_parsed_term_to_heap(
|
|||||||
machine_st: &mut MachineState,
|
machine_st: &mut MachineState,
|
||||||
input_stream: Stream,
|
input_stream: Stream,
|
||||||
op_dir: &OpDir,
|
op_dir: &OpDir,
|
||||||
) -> Result<TermWriteResult, ParserError> {
|
) -> Result<TermWriteResult, CompilationError> {
|
||||||
machine_st.read(input_stream, op_dir)
|
machine_st.read(input_stream, op_dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +208,7 @@ pub(crate) fn parse_and_write_parsed_term_to_heap(
|
|||||||
machine_st: &mut MachineState,
|
machine_st: &mut MachineState,
|
||||||
term_string: &'static str,
|
term_string: &'static str,
|
||||||
op_dir: &OpDir,
|
op_dir: &OpDir,
|
||||||
) -> Result<TermWriteResult, ParserError> {
|
) -> Result<TermWriteResult, CompilationError> {
|
||||||
let stream = Stream::from_static_string(term_string, &mut machine_st.arena);
|
let stream = Stream::from_static_string(term_string, &mut machine_st.arena);
|
||||||
write_parsed_term_to_heap(machine_st, stream, op_dir)
|
write_parsed_term_to_heap(machine_st, stream, op_dir)
|
||||||
}
|
}
|
||||||
@@ -224,6 +223,11 @@ impl Machine {
|
|||||||
let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena);
|
let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena);
|
||||||
let user_error = Stream::stderr(&mut machine_st.arena);
|
let user_error = Stream::stderr(&mut machine_st.arena);
|
||||||
|
|
||||||
|
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut wam = Machine {
|
let mut wam = Machine {
|
||||||
machine_st,
|
machine_st,
|
||||||
indices: IndexStore::new(),
|
indices: IndexStore::new(),
|
||||||
@@ -232,6 +236,7 @@ impl Machine {
|
|||||||
user_output,
|
user_output,
|
||||||
user_error,
|
user_error,
|
||||||
load_contexts: vec![],
|
load_contexts: vec![],
|
||||||
|
runtime
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut lib_path = current_dir();
|
let mut lib_path = current_dir();
|
||||||
@@ -266,6 +271,7 @@ impl Machine {
|
|||||||
|
|
||||||
if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
|
if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
|
||||||
load_module(
|
load_module(
|
||||||
|
&mut wam.machine_st,
|
||||||
&mut wam.indices.code_dir,
|
&mut wam.indices.code_dir,
|
||||||
&mut wam.indices.op_dir,
|
&mut wam.indices.op_dir,
|
||||||
&mut wam.indices.meta_predicates,
|
&mut wam.indices.meta_predicates,
|
||||||
@@ -291,6 +297,7 @@ impl Machine {
|
|||||||
|
|
||||||
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
|
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
|
||||||
load_module(
|
load_module(
|
||||||
|
&mut wam.machine_st,
|
||||||
&mut wam.indices.code_dir,
|
&mut wam.indices.code_dir,
|
||||||
&mut wam.indices.op_dir,
|
&mut wam.indices.op_dir,
|
||||||
&mut wam.indices.meta_predicates,
|
&mut wam.indices.meta_predicates,
|
||||||
@@ -603,7 +610,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_term_compare() {
|
fn test_term_compare() {
|
||||||
use ordered_float::OrderedFloat;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
let mut wam = MachineState::new();
|
let mut wam = MachineState::new();
|
||||||
@@ -771,9 +777,7 @@ mod tests {
|
|||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
);
|
);
|
||||||
|
|
||||||
let one_p_one = typed_arena_ptr_as_cell!(
|
let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena));
|
||||||
arena_alloc!(OrderedFloat(1.1), &mut wam.arena)
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(
|
compare_term_test!(
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pub mod args;
|
||||||
pub mod arithmetic_ops;
|
pub mod arithmetic_ops;
|
||||||
pub mod attributed_variables;
|
pub mod attributed_variables;
|
||||||
pub mod code_walker;
|
pub mod code_walker;
|
||||||
@@ -21,10 +22,12 @@ pub mod streams;
|
|||||||
pub mod system_calls;
|
pub mod system_calls;
|
||||||
pub mod term_stream;
|
pub mod term_stream;
|
||||||
|
|
||||||
|
use crate::arena::*;
|
||||||
use crate::arithmetic::*;
|
use crate::arithmetic::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
|
use crate::machine::args::*;
|
||||||
use crate::machine::compile::*;
|
use crate::machine::compile::*;
|
||||||
use crate::machine::copier::*;
|
use crate::machine::copier::*;
|
||||||
use crate::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
@@ -46,6 +49,7 @@ use std::cmp::Ordering;
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
|
pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
|
||||||
@@ -60,6 +64,7 @@ pub struct Machine {
|
|||||||
pub(super) user_output: Stream,
|
pub(super) user_output: Stream,
|
||||||
pub(super) user_error: Stream,
|
pub(super) user_error: Stream,
|
||||||
pub(super) load_contexts: Vec<LoadContext>,
|
pub(super) load_contexts: Vec<LoadContext>,
|
||||||
|
pub(super) runtime: Runtime,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -156,6 +161,24 @@ pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> {
|
||||||
|
read_heap_cell!(value,
|
||||||
|
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||||
|
match_untyped_arena_ptr!(cons_ptr,
|
||||||
|
(ArenaHeaderTag::IndexPtr, ip) => {
|
||||||
|
return Some(CodeIndex::from(ip));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
|
pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
|
||||||
@@ -216,6 +239,7 @@ impl Machine {
|
|||||||
|
|
||||||
if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) {
|
if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) {
|
||||||
load_module(
|
load_module(
|
||||||
|
&mut self.machine_st,
|
||||||
&mut self.indices.code_dir,
|
&mut self.indices.code_dir,
|
||||||
&mut self.indices.op_dir,
|
&mut self.indices.op_dir,
|
||||||
&mut self.indices.meta_predicates,
|
&mut self.indices.meta_predicates,
|
||||||
@@ -283,7 +307,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn configure_modules(&mut self) {
|
pub(crate) fn configure_modules(&mut self) {
|
||||||
fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir) {
|
fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir, arena: &mut Arena) {
|
||||||
for arity in 1..66 {
|
for arity in 1..66 {
|
||||||
let key = (atom!("call"), arity);
|
let key = (atom!("call"), arity);
|
||||||
|
|
||||||
@@ -291,7 +315,7 @@ impl Machine {
|
|||||||
Some(src_code_index) => {
|
Some(src_code_index) => {
|
||||||
let target_code_index = target_code_dir
|
let target_code_index = target_code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined));
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
|
||||||
|
|
||||||
target_code_index.set(src_code_index.get());
|
target_code_index.set(src_code_index.get());
|
||||||
}
|
}
|
||||||
@@ -307,6 +331,7 @@ impl Machine {
|
|||||||
// Import loader's exports into the builtins module so they will be
|
// Import loader's exports into the builtins module so they will be
|
||||||
// implicitly included in every further module.
|
// implicitly included in every further module.
|
||||||
load_module(
|
load_module(
|
||||||
|
&mut self.machine_st,
|
||||||
&mut builtins.code_dir,
|
&mut builtins.code_dir,
|
||||||
&mut builtins.op_dir,
|
&mut builtins.op_dir,
|
||||||
&mut builtins.meta_predicates,
|
&mut builtins.meta_predicates,
|
||||||
@@ -327,10 +352,10 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (_, target_module) in self.indices.modules.iter_mut() {
|
for (_, target_module) in self.indices.modules.iter_mut() {
|
||||||
update_call_n_indices(&loader, &mut target_module.code_dir);
|
update_call_n_indices(&loader, &mut target_module.code_dir, &mut self.machine_st.arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
update_call_n_indices(&loader, &mut self.indices.code_dir);
|
update_call_n_indices(&loader, &mut self.indices.code_dir, &mut self.machine_st.arena);
|
||||||
|
|
||||||
self.indices.modules.insert(atom!("loader"), loader);
|
self.indices.modules.insert(atom!("loader"), loader);
|
||||||
} else {
|
} else {
|
||||||
@@ -389,19 +414,26 @@ impl Machine {
|
|||||||
|
|
||||||
for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
|
for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
|
||||||
let key = instr.to_name_and_arity();
|
let key = instr.to_name_and_arity();
|
||||||
self.indices.code_dir.insert(key, CodeIndex::new(IndexPtr::Index(p + impls_offset)));
|
self.indices.code_dir.insert(
|
||||||
|
key,
|
||||||
|
CodeIndex::new(IndexPtr::index(p + impls_offset), &mut self.machine_st.arena),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
use ref_thread_local::RefThreadLocal;
|
use ref_thread_local::RefThreadLocal;
|
||||||
|
|
||||||
|
let args = MachineArgs::new();
|
||||||
let mut machine_st = MachineState::new();
|
let mut machine_st = MachineState::new();
|
||||||
|
|
||||||
let user_input = Stream::stdin(&mut machine_st.arena);
|
let user_input = Stream::stdin(&mut machine_st.arena, args.add_history);
|
||||||
let user_output = Stream::stdout(&mut machine_st.arena);
|
let user_output = Stream::stdout(&mut machine_st.arena);
|
||||||
let user_error = Stream::stderr(&mut machine_st.arena);
|
let user_error = Stream::stderr(&mut machine_st.arena);
|
||||||
|
|
||||||
|
let runtime = tokio::runtime::Runtime::new()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut wam = Machine {
|
let mut wam = Machine {
|
||||||
machine_st,
|
machine_st,
|
||||||
indices: IndexStore::new(),
|
indices: IndexStore::new(),
|
||||||
@@ -410,6 +442,7 @@ impl Machine {
|
|||||||
user_output,
|
user_output,
|
||||||
user_error,
|
user_error,
|
||||||
load_contexts: vec![],
|
load_contexts: vec![],
|
||||||
|
runtime,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut lib_path = current_dir();
|
let mut lib_path = current_dir();
|
||||||
@@ -444,6 +477,7 @@ impl Machine {
|
|||||||
|
|
||||||
if let Some(builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
|
if let Some(builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
|
||||||
load_module(
|
load_module(
|
||||||
|
&mut wam.machine_st,
|
||||||
&mut wam.indices.code_dir,
|
&mut wam.indices.code_dir,
|
||||||
&mut wam.indices.op_dir,
|
&mut wam.indices.op_dir,
|
||||||
&mut wam.indices.meta_predicates,
|
&mut wam.indices.meta_predicates,
|
||||||
@@ -469,6 +503,7 @@ impl Machine {
|
|||||||
|
|
||||||
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
|
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
|
||||||
load_module(
|
load_module(
|
||||||
|
&mut wam.machine_st,
|
||||||
&mut wam.indices.code_dir,
|
&mut wam.indices.code_dir,
|
||||||
&mut wam.indices.op_dir,
|
&mut wam.indices.op_dir,
|
||||||
&mut wam.indices.meta_predicates,
|
&mut wam.indices.meta_predicates,
|
||||||
@@ -655,18 +690,20 @@ impl Machine {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
||||||
match idx {
|
let compiled_tl_index = idx.p() as usize;
|
||||||
IndexPtr::DynamicUndefined => {
|
|
||||||
|
match idx.tag() {
|
||||||
|
IndexPtrTag::DynamicUndefined => {
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
}
|
}
|
||||||
IndexPtr::Undefined => {
|
IndexPtrTag::Undefined => {
|
||||||
return Err(self.machine_st.throw_undefined_error(name, arity));
|
return Err(self.machine_st.throw_undefined_error(name, arity));
|
||||||
}
|
}
|
||||||
IndexPtr::DynamicIndex(compiled_tl_index) => {
|
IndexPtrTag::DynamicIndex => {
|
||||||
self.machine_st.dynamic_mode = FirstOrNext::First;
|
self.machine_st.dynamic_mode = FirstOrNext::First;
|
||||||
self.machine_st.call_at_index(arity, compiled_tl_index);
|
self.machine_st.call_at_index(arity, compiled_tl_index);
|
||||||
}
|
}
|
||||||
IndexPtr::Index(compiled_tl_index) => {
|
IndexPtrTag::Index => {
|
||||||
self.machine_st.call_at_index(arity, compiled_tl_index);
|
self.machine_st.call_at_index(arity, compiled_tl_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -676,18 +713,20 @@ impl Machine {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
||||||
match idx {
|
let compiled_tl_index = idx.p() as usize;
|
||||||
IndexPtr::DynamicUndefined => {
|
|
||||||
|
match idx.tag() {
|
||||||
|
IndexPtrTag::DynamicUndefined => {
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
}
|
}
|
||||||
IndexPtr::Undefined => {
|
IndexPtrTag::Undefined => {
|
||||||
return Err(self.machine_st.throw_undefined_error(name, arity));
|
return Err(self.machine_st.throw_undefined_error(name, arity));
|
||||||
}
|
}
|
||||||
IndexPtr::DynamicIndex(compiled_tl_index) => {
|
IndexPtrTag::DynamicIndex => {
|
||||||
self.machine_st.dynamic_mode = FirstOrNext::First;
|
self.machine_st.dynamic_mode = FirstOrNext::First;
|
||||||
self.machine_st.execute_at_index(arity, compiled_tl_index);
|
self.machine_st.execute_at_index(arity, compiled_tl_index);
|
||||||
}
|
}
|
||||||
IndexPtr::Index(compiled_tl_index) => {
|
IndexPtrTag::Index => {
|
||||||
self.machine_st.execute_at_index(arity, compiled_tl_index)
|
self.machine_st.execute_at_index(arity, compiled_tl_index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -826,12 +865,12 @@ impl Machine {
|
|||||||
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
||||||
}
|
}
|
||||||
TrailEntryTag::TrailedAttrVarListLink => {
|
TrailEntryTag::TrailedAttrVarListLink => {
|
||||||
let value = HeapCellValue::from_bytes(
|
let l = self.machine_st.trail[i + 1].get_value() as usize;
|
||||||
self.machine_st.trail[i + 1].into_bytes()
|
|
||||||
);
|
|
||||||
|
|
||||||
if value.get_value() < self.machine_st.hb {
|
if l < self.machine_st.hb {
|
||||||
self.machine_st.heap[h] = value;
|
self.machine_st.heap[h] = list_loc_as_cell!(l);
|
||||||
|
} else {
|
||||||
|
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TrailEntryTag::TrailedBlackboardEntry => {
|
TrailEntryTag::TrailedBlackboardEntry => {
|
||||||
|
|||||||
@@ -109,6 +109,12 @@ impl<'a> HeapPStrIter<'a> {
|
|||||||
self.brent_st.num_steps()
|
self.brent_st.num_steps()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn chars(mut self) -> PStrCharsIter<'a> {
|
||||||
|
let item = self.next();
|
||||||
|
PStrCharsIter { iter: self, item }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn compare_pstr_to_string(&mut self, s: &str) -> Option<PStrPrefixCmpResult> {
|
pub fn compare_pstr_to_string(&mut self, s: &str) -> Option<PStrPrefixCmpResult> {
|
||||||
let mut result = PStrPrefixCmpResult {
|
let mut result = PStrPrefixCmpResult {
|
||||||
focus: self.brent_st.hare,
|
focus: self.brent_st.hare,
|
||||||
@@ -116,7 +122,12 @@ impl<'a> HeapPStrIter<'a> {
|
|||||||
prefix_len: 0,
|
prefix_len: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
while let Some(iteratee) = self.next() {
|
let mut final_result = None;
|
||||||
|
|
||||||
|
while let Some(PStrIterStep { iteratee, next_hare }) = self.step(self.brent_st.hare) {
|
||||||
|
self.brent_st.hare = next_hare;
|
||||||
|
self.focus = self.heap[iteratee.focus()];
|
||||||
|
|
||||||
result.focus = iteratee.focus();
|
result.focus = iteratee.focus();
|
||||||
result.offset = iteratee.offset();
|
result.offset = iteratee.offset();
|
||||||
|
|
||||||
@@ -130,7 +141,8 @@ impl<'a> HeapPStrIter<'a> {
|
|||||||
result.offset += c1.len_utf8();
|
result.offset += c1.len_utf8();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Some(result);
|
final_result = Some(result);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PStrIteratee::PStrSegment(_, pstr_atom, n) => {
|
PStrIteratee::PStrSegment(_, pstr_atom, n) => {
|
||||||
@@ -149,7 +161,8 @@ impl<'a> HeapPStrIter<'a> {
|
|||||||
result.prefix_len += s.len();
|
result.prefix_len += s.len();
|
||||||
result.offset += s.len();
|
result.offset += s.len();
|
||||||
|
|
||||||
return Some(result);
|
final_result = Some(result);
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -157,17 +170,27 @@ impl<'a> HeapPStrIter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if s.len() == result.prefix_len {
|
if s.len() == result.prefix_len {
|
||||||
return Some(result);
|
final_result = Some(result);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(result)
|
if let Some(result) = &final_result {
|
||||||
|
if self.at_string_terminator() {
|
||||||
|
self.focus = empty_list_as_cell!();
|
||||||
|
self.brent_st.hare = result.focus;
|
||||||
|
} else {
|
||||||
|
read_heap_cell!(self.heap[result.focus],
|
||||||
|
(HeapCellValueTag::Lis | HeapCellValueTag::Str) => {
|
||||||
|
self.focus = self.heap[self.brent_st.hare];
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
final_result
|
||||||
pub fn chars(mut self) -> PStrCharsIter<'a> {
|
|
||||||
let item = self.next();
|
|
||||||
PStrCharsIter { iter: self, item }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_hare_to_cycle_end(&mut self) {
|
fn walk_hare_to_cycle_end(&mut self) {
|
||||||
@@ -223,7 +246,13 @@ impl<'a> HeapPStrIter<'a> {
|
|||||||
return name == atom!(".") && arity == 2;
|
return name == atom!(".") && arity == 2;
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Lis, h) => {
|
(HeapCellValueTag::Lis, h) => {
|
||||||
return read_heap_cell!(self.heap[h],
|
let value = self.heap[h];
|
||||||
|
let value = heap_bound_store(
|
||||||
|
self.heap,
|
||||||
|
heap_bound_deref(self.heap, value),
|
||||||
|
);
|
||||||
|
|
||||||
|
return read_heap_cell!(value,
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
arity == 0 && name.as_char().is_some()
|
arity == 0 && name.as_char().is_some()
|
||||||
}
|
}
|
||||||
@@ -309,7 +338,7 @@ impl<'a> HeapPStrIter<'a> {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
@@ -362,7 +391,7 @@ impl<'a> HeapPStrIter<'a> {
|
|||||||
|
|
||||||
self.focus = self.heap[iteratee.focus()];
|
self.focus = self.heap[iteratee.focus()];
|
||||||
|
|
||||||
if self.focus.is_string_terminator(self.heap) {
|
if self.at_string_terminator() {
|
||||||
self.focus = empty_list_as_cell!();
|
self.focus = empty_list_as_cell!();
|
||||||
self.brent_st.hare = iteratee.focus();
|
self.brent_st.hare = iteratee.focus();
|
||||||
|
|
||||||
@@ -533,7 +562,6 @@ pub fn compare_pstr_prefixes<'a>(
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn step(iter: &mut HeapPStrIter, hare: usize) -> Option<PStrIterStep> {
|
fn step(iter: &mut HeapPStrIter, hare: usize) -> Option<PStrIterStep> {
|
||||||
let result = iter.step(hare);
|
let result = iter.step(hare);
|
||||||
|
|
||||||
iter.focus = iter.heap[hare];
|
iter.focus = iter.heap[hare];
|
||||||
|
|
||||||
if iter.focus.is_string_terminator(iter.heap) {
|
if iter.focus.is_string_terminator(iter.heap) {
|
||||||
@@ -622,7 +650,7 @@ pub fn compare_pstr_prefixes<'a>(
|
|||||||
|
|
||||||
if let Some(c1) = pstr.as_str_from(n).chars().next() {
|
if let Some(c1) = pstr.as_str_from(n).chars().next() {
|
||||||
if c1 != c2 {
|
if c1 != c2 {
|
||||||
return PStrCmpResult::Ordered(c2.cmp(&c1));
|
return PStrCmpResult::Ordered(c1.cmp(&c2));
|
||||||
}
|
}
|
||||||
|
|
||||||
let n1 = n + c1.len_utf8();
|
let n1 = n + c1.len_utf8();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
|
use crate::codegen::CodeGenSettings;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::iterators::*;
|
use crate::iterators::*;
|
||||||
@@ -112,30 +113,6 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, Compilatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKey, CompilationError>
|
|
||||||
{
|
|
||||||
match term {
|
|
||||||
Term::Clause(_, ref name, ref mut terms, Some(_))
|
|
||||||
if name.as_str() == ":" && terms.len() == 2 =>
|
|
||||||
{
|
|
||||||
let mut predicate_indicator = *terms.pop().unwrap();
|
|
||||||
let module_name = *terms.pop().unwrap();
|
|
||||||
|
|
||||||
let module_name = module_name
|
|
||||||
.to_constant()
|
|
||||||
.and_then(|c| c.to_atom())
|
|
||||||
.ok_or(CompilationError::InvalidModuleExport)?;
|
|
||||||
|
|
||||||
let key = setup_predicate_indicator(&mut predicate_indicator)?;
|
|
||||||
|
|
||||||
Ok((module_name, key))
|
|
||||||
}
|
|
||||||
_ => Err(CompilationError::InvalidModuleExport),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn setup_module_export(
|
fn setup_module_export(
|
||||||
mut term: Term,
|
mut term: Term,
|
||||||
atom_tbl: &mut AtomTable,
|
atom_tbl: &mut AtomTable,
|
||||||
@@ -279,6 +256,7 @@ fn setup_qualified_import(
|
|||||||
* -
|
* -
|
||||||
* ?
|
* ?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
||||||
mut terms: Vec<Term>,
|
mut terms: Vec<Term>,
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
@@ -296,6 +274,7 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
|||||||
atom!("+") => MetaSpec::Plus,
|
atom!("+") => MetaSpec::Plus,
|
||||||
atom!("-") => MetaSpec::Minus,
|
atom!("-") => MetaSpec::Minus,
|
||||||
atom!("?") => MetaSpec::Either,
|
atom!("?") => MetaSpec::Either,
|
||||||
|
atom!(":") => MetaSpec::Colon,
|
||||||
_ => return Err(CompilationError::InvalidMetaPredicateDecl),
|
_ => return Err(CompilationError::InvalidMetaPredicateDecl),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -491,14 +470,142 @@ pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
|
||||||
|
loader: &mut Loader<'a, LS>,
|
||||||
|
module_name: Atom,
|
||||||
|
terms: Vec<Term>,
|
||||||
|
meta_specs: Vec<MetaSpec>,
|
||||||
|
) -> Vec<Term> {
|
||||||
|
let mut arg_terms = Vec::with_capacity(terms.len());
|
||||||
|
|
||||||
|
for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) {
|
||||||
|
if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec {
|
||||||
|
if let Some(name) = term.name() {
|
||||||
|
if name == atom!("$call") {
|
||||||
|
arg_terms.push(term);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let arity = term.arity();
|
||||||
|
|
||||||
|
fn get_qualified_name(
|
||||||
|
module_term: &Term,
|
||||||
|
qualified_term: &Term,
|
||||||
|
) -> Option<(Atom, Atom)> {
|
||||||
|
if let Term::Literal(_, Literal::Atom(module_name)) = module_term {
|
||||||
|
if let Some(name) = qualified_term.name() {
|
||||||
|
return Some((*module_name, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn identity_fn(_module_name: Atom, term: Term) -> Term {
|
||||||
|
term
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tag_with_module_name(module_name: Atom, term: Term) -> Term {
|
||||||
|
Term::Clause(Cell::default(), atom!(":"), vec![
|
||||||
|
Term::Literal(Cell::default(), Literal::Atom(module_name)),
|
||||||
|
term
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
let process_term: fn(Atom, Term) -> Term;
|
||||||
|
|
||||||
|
let (module_name, key, term) = match term {
|
||||||
|
Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => {
|
||||||
|
if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1]) {
|
||||||
|
process_term = tag_with_module_name;
|
||||||
|
(module_name, (name, terms[1].arity() + supp_args), terms.pop().unwrap())
|
||||||
|
} else {
|
||||||
|
arg_terms.push(Term::Clause(cell, atom!(":"), terms));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
term => {
|
||||||
|
process_term = identity_fn;
|
||||||
|
(module_name, (name, arity + supp_args), term)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let term = match term {
|
||||||
|
Term::Clause(cell, name, mut terms) => {
|
||||||
|
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||||
|
arg_terms.push(process_term(
|
||||||
|
module_name,
|
||||||
|
Term::Clause(cell, name, terms),
|
||||||
|
));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
|
||||||
|
|
||||||
|
terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
|
||||||
|
process_term(module_name, Term::Clause(cell, name, terms))
|
||||||
|
}
|
||||||
|
Term::Literal(cell, Literal::Atom(name)) => {
|
||||||
|
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
|
||||||
|
|
||||||
|
process_term(module_name, Term::Clause(
|
||||||
|
cell,
|
||||||
|
name,
|
||||||
|
vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
term => term,
|
||||||
|
};
|
||||||
|
|
||||||
|
arg_terms.push(term);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_terms.push(term);
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_terms
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
name: Atom,
|
name: Atom,
|
||||||
terms: Vec<Term>,
|
mut terms: Vec<Term>,
|
||||||
|
call_policy: CallPolicy,
|
||||||
) -> QueryTerm {
|
) -> QueryTerm {
|
||||||
let ct = loader.get_clause_type(name, terms.len());
|
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||||
QueryTerm::Clause(Cell::default(), ct, terms, false)
|
// supplementary code vector indices are unnecessary for
|
||||||
|
// root-level clauses.
|
||||||
|
terms.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ct = loader.get_clause_type(name, terms.len());
|
||||||
|
|
||||||
|
if let ClauseType::Named(arity, name, idx) = ct {
|
||||||
|
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
|
||||||
|
let module_name = loader.payload.compilation_target.module_name();
|
||||||
|
let terms = build_meta_predicate_clause(
|
||||||
|
loader,
|
||||||
|
module_name,
|
||||||
|
terms,
|
||||||
|
meta_specs,
|
||||||
|
);
|
||||||
|
|
||||||
|
return QueryTerm::Clause(
|
||||||
|
Cell::default(),
|
||||||
|
ClauseType::Named(arity, name, idx),
|
||||||
|
terms,
|
||||||
|
call_policy,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ct = ClauseType::Named(arity, name, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -506,32 +613,41 @@ fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
|
|||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
module_name: Atom,
|
module_name: Atom,
|
||||||
name: Atom,
|
name: Atom,
|
||||||
terms: Vec<Term>,
|
mut terms: Vec<Term>,
|
||||||
|
call_policy: CallPolicy,
|
||||||
) -> QueryTerm {
|
) -> QueryTerm {
|
||||||
let ct = loader.get_qualified_clause_type(module_name, name, terms.len());
|
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||||
QueryTerm::Clause(Cell::default(), ct, terms, false)
|
// supplementary code vector indices are unnecessary for
|
||||||
|
// root-level clauses.
|
||||||
|
terms.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ct = loader.get_qualified_clause_type(module_name, name, terms.len());
|
||||||
|
|
||||||
|
if let ClauseType::Named(arity, name, idx) = ct {
|
||||||
|
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
|
||||||
|
let terms = build_meta_predicate_clause(
|
||||||
|
loader,
|
||||||
|
module_name,
|
||||||
|
terms,
|
||||||
|
meta_specs,
|
||||||
|
);
|
||||||
|
|
||||||
|
return QueryTerm::Clause(
|
||||||
|
Cell::default(),
|
||||||
|
ClauseType::Named(arity, name, idx),
|
||||||
|
terms,
|
||||||
|
call_policy,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ct = ClauseType::Named(arity, name, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
fn compute_head(term: &Term) -> Vec<Term> {
|
||||||
pub(crate) struct Preprocessor {
|
|
||||||
queue: VecDeque<VecDeque<Term>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Preprocessor {
|
|
||||||
pub(super) fn new() -> Self {
|
|
||||||
Preprocessor {
|
|
||||||
queue: VecDeque::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
|
|
||||||
match term {
|
|
||||||
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
|
|
||||||
_ => Err(CompilationError::InadmissibleFact),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_head(&self, term: &Term) -> Vec<Term> {
|
|
||||||
let mut vars = IndexSet::new();
|
let mut vars = IndexSet::new();
|
||||||
|
|
||||||
for term in post_order_iter(term) {
|
for term in post_order_iter(term) {
|
||||||
@@ -544,29 +660,29 @@ impl Preprocessor {
|
|||||||
vars.into_iter()
|
vars.into_iter()
|
||||||
.map(|v| Term::Var(Cell::default(), v))
|
.map(|v| Term::Var(Cell::default(), v))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fabricate_rule_body(&self, vars: &Vec<Term>, body_term: Term) -> Term {
|
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
|
||||||
let head_term = Term::Clause(Cell::default(), atom!(""), vars.clone());
|
let head_term = Term::Clause(Cell::default(), atom!(""), vars.iter().cloned().collect());
|
||||||
let rule = vec![head_term, body_term];
|
let rule = vec![head_term, body_term];
|
||||||
|
|
||||||
Term::Clause(Cell::default(), atom!(":-"), rule)
|
Term::Clause(Cell::default(), atom!(":-"), rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
// the terms form the body of the rule. We create a head, by
|
// the terms form the body of the rule. We create a head, by
|
||||||
// gathering variables from the body of terms and recording them
|
// gathering variables from the body of terms and recording them
|
||||||
// in the head clause.
|
// in the head clause.
|
||||||
fn fabricate_rule(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
fn build_rule(body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
||||||
// collect the vars of body_term into a head, return the num_vars
|
// collect the vars of body_term into a head, return the num_vars
|
||||||
// (the arity) as well.
|
// (the arity) as well.
|
||||||
let vars = self.compute_head(&body_term);
|
let vars = compute_head(&body_term);
|
||||||
let rule = self.fabricate_rule_body(&vars, body_term);
|
let rule = build_rule_body(&vars, body_term);
|
||||||
|
|
||||||
(vars, VecDeque::from(vec![rule]))
|
(vars, VecDeque::from(vec![rule]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
fn build_disjunct(body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
||||||
let vars = self.compute_head(&body_term);
|
let vars = compute_head(&body_term);
|
||||||
let results = unfold_by_str(body_term, atom!(";"))
|
let results = unfold_by_str(body_term, atom!(";"))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|term| {
|
.map(|term| {
|
||||||
@@ -578,14 +694,14 @@ impl Preprocessor {
|
|||||||
let term = subterms.pop().unwrap();
|
let term = subterms.pop().unwrap();
|
||||||
let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
|
let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
|
||||||
|
|
||||||
self.fabricate_rule_body(&vars, clause)
|
build_rule_body(&vars, clause)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
(vars, results)
|
(vars, results)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
|
fn build_if_then(prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
|
||||||
let mut prec_seq = unfold_by_str(prec, atom!(","));
|
let mut prec_seq = unfold_by_str(prec, atom!(","));
|
||||||
let comma_sym = atom!(",");
|
let comma_sym = atom!(",");
|
||||||
let cut_sym = Literal::Atom(atom!("!"));
|
let cut_sym = Literal::Atom(atom!("!"));
|
||||||
@@ -608,7 +724,28 @@ impl Preprocessor {
|
|||||||
vec![front_term, back_term],
|
vec![front_term, back_term],
|
||||||
);
|
);
|
||||||
|
|
||||||
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
|
build_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct Preprocessor {
|
||||||
|
queue: VecDeque<VecDeque<Term>>,
|
||||||
|
settings: CodeGenSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Preprocessor {
|
||||||
|
pub(super) fn new(settings: CodeGenSettings) -> Self {
|
||||||
|
Preprocessor {
|
||||||
|
queue: VecDeque::new(),
|
||||||
|
settings,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
|
||||||
|
match term {
|
||||||
|
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
|
||||||
|
_ => Err(CompilationError::InadmissibleFact),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_query_term<'a, LS: LoadState<'a>>(
|
fn to_query_term<'a, LS: LoadState<'a>>(
|
||||||
@@ -621,7 +758,12 @@ impl Preprocessor {
|
|||||||
if name == atom!("!") || name == atom!("blocked_!") {
|
if name == atom!("!") || name == atom!("blocked_!") {
|
||||||
Ok(QueryTerm::BlockedCut)
|
Ok(QueryTerm::BlockedCut)
|
||||||
} else {
|
} else {
|
||||||
Ok(clause_to_query_term(loader, name, vec![]))
|
Ok(clause_to_query_term(
|
||||||
|
loader,
|
||||||
|
name,
|
||||||
|
vec![],
|
||||||
|
self.settings.default_call_policy(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut),
|
Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut),
|
||||||
@@ -632,7 +774,7 @@ impl Preprocessor {
|
|||||||
(atom!(";"), 2) => {
|
(atom!(";"), 2) => {
|
||||||
let term = Term::Clause(r, name, terms);
|
let term = Term::Clause(r, name, terms);
|
||||||
|
|
||||||
let (stub, clauses) = self.fabricate_disjunct(term);
|
let (stub, clauses) = build_disjunct(term);
|
||||||
self.queue.push_back(clauses);
|
self.queue.push_back(clauses);
|
||||||
|
|
||||||
Ok(QueryTerm::Jump(stub))
|
Ok(QueryTerm::Jump(stub))
|
||||||
@@ -641,7 +783,7 @@ impl Preprocessor {
|
|||||||
let conq = terms.pop().unwrap();
|
let conq = terms.pop().unwrap();
|
||||||
let prec = terms.pop().unwrap();
|
let prec = terms.pop().unwrap();
|
||||||
|
|
||||||
let (stub, clauses) = self.fabricate_if_then(prec, conq);
|
let (stub, clauses) = build_if_then(prec, conq);
|
||||||
self.queue.push_back(clauses);
|
self.queue.push_back(clauses);
|
||||||
|
|
||||||
Ok(QueryTerm::Jump(stub))
|
Ok(QueryTerm::Jump(stub))
|
||||||
@@ -658,7 +800,7 @@ impl Preprocessor {
|
|||||||
let terms = vec![prec, conq];
|
let terms = vec![prec, conq];
|
||||||
|
|
||||||
let term = Term::Clause(Cell::default(), atom!(";"), terms);
|
let term = Term::Clause(Cell::default(), atom!(";"), terms);
|
||||||
let (stub, clauses) = self.fabricate_disjunct(term);
|
let (stub, clauses) = build_disjunct(term);
|
||||||
|
|
||||||
debug_assert!(clauses.len() > 0);
|
debug_assert!(clauses.len() > 0);
|
||||||
self.queue.push_back(clauses);
|
self.queue.push_back(clauses);
|
||||||
@@ -685,6 +827,7 @@ impl Preprocessor {
|
|||||||
module_name,
|
module_name,
|
||||||
predicate_name,
|
predicate_name,
|
||||||
vec![],
|
vec![],
|
||||||
|
self.settings.default_call_policy(),
|
||||||
)),
|
)),
|
||||||
(
|
(
|
||||||
Term::Literal(_, Literal::Atom(module_name)),
|
Term::Literal(_, Literal::Atom(module_name)),
|
||||||
@@ -694,22 +837,29 @@ impl Preprocessor {
|
|||||||
module_name,
|
module_name,
|
||||||
name,
|
name,
|
||||||
terms,
|
terms,
|
||||||
|
self.settings.default_call_policy()
|
||||||
)),
|
)),
|
||||||
(module_name, predicate_name) => {
|
(module_name, predicate_name) => {
|
||||||
terms.push(module_name);
|
terms.push(module_name);
|
||||||
terms.push(predicate_name);
|
terms.push(predicate_name);
|
||||||
|
|
||||||
Ok(clause_to_query_term(loader, name, terms))
|
Ok(clause_to_query_term(
|
||||||
|
loader,
|
||||||
|
atom!("call"),
|
||||||
|
vec![Term::Clause(r, name, terms)],
|
||||||
|
self.settings.default_call_policy(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Ok(clause_to_query_term(loader, name, terms)),
|
_ => Ok(clause_to_query_term(loader, name, terms,
|
||||||
|
self.settings.default_call_policy())),
|
||||||
},
|
},
|
||||||
Term::Var(..) => Ok(QueryTerm::Clause(
|
Term::Var(..) => Ok(QueryTerm::Clause(
|
||||||
Cell::default(),
|
Cell::default(),
|
||||||
ClauseType::CallN(1),
|
ClauseType::CallN(1),
|
||||||
vec![term],
|
vec![term],
|
||||||
false,
|
self.settings.default_call_policy(),
|
||||||
)),
|
)),
|
||||||
_ => Err(CompilationError::InadmissibleQueryTerm),
|
_ => Err(CompilationError::InadmissibleQueryTerm),
|
||||||
}
|
}
|
||||||
@@ -722,10 +872,10 @@ impl Preprocessor {
|
|||||||
) -> Result<QueryTerm, CompilationError> {
|
) -> Result<QueryTerm, CompilationError> {
|
||||||
match term {
|
match term {
|
||||||
Term::Clause(r, name, mut subterms) => {
|
Term::Clause(r, name, mut subterms) => {
|
||||||
if subterms.len() == 1 && name == atom!("$call_with_default_policy") {
|
if subterms.len() == 1 && name == atom!("$call_with_inference_counting") {
|
||||||
self.to_query_term(loader, subterms.pop().unwrap())
|
self.to_query_term(loader, subterms.pop().unwrap())
|
||||||
.map(|mut query_term| {
|
.map(|mut query_term| {
|
||||||
query_term.set_default_caller();
|
query_term.set_call_policy(CallPolicy::Counted);
|
||||||
query_term
|
query_term
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ project_attributes(QueryVars, AttrVars) :-
|
|||||||
; E = error(evaluation_error((Module:project_attributes)/2), _)
|
; E = error(evaluation_error((Module:project_attributes)/2), _)
|
||||||
) ->
|
) ->
|
||||||
true
|
true
|
||||||
; write_term('caught: ', [quoted(false)]),
|
; loader:write_error(E),
|
||||||
writeq(E),
|
|
||||||
nl
|
nl
|
||||||
).
|
).
|
||||||
|
|
||||||
@@ -33,9 +32,9 @@ call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :-
|
|||||||
|
|
||||||
'$print_attribute_goals_exception'(Module, E) :-
|
'$print_attribute_goals_exception'(Module, E) :-
|
||||||
( E = error(evaluation_error((Module:attribute_goals)/3), attribute_goals/3)
|
( E = error(evaluation_error((Module:attribute_goals)/3), attribute_goals/3)
|
||||||
|
; E = error(existence_error(procedure, attribute_goals/3), attribute_goals/3)
|
||||||
-> true
|
-> true
|
||||||
; write_term('caught: ', [quoted(false)]),
|
; loader:write_error(E),
|
||||||
writeq(E),
|
|
||||||
nl
|
nl
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|||||||
@@ -15,16 +15,18 @@ pub use modular_bitfield::prelude::*;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::fmt::Debug;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::hash::{Hash};
|
use std::hash::{Hash};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
use std::io::{BufRead, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::net::{TcpStream, Shutdown};
|
use std::net::{TcpStream, Shutdown};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use native_tls::TlsStream;
|
use native_tls::TlsStream;
|
||||||
|
use hyper::body::{Bytes, Sender};
|
||||||
|
|
||||||
#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[bits = 1]
|
#[bits = 1]
|
||||||
@@ -138,6 +140,17 @@ impl Read for InputFileStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StreamLayout<CharReader<InputFileStream>> {
|
||||||
|
#[inline]
|
||||||
|
fn position(&mut self) -> Option<u64> {
|
||||||
|
// stream is the internal CharReader. subtract
|
||||||
|
// its pending buffer length from position.
|
||||||
|
self.get_mut().file.seek(SeekFrom::Current(0))
|
||||||
|
.map(|pos| pos - self.stream.rem_buf_len() as u64)
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OutputFileStream {
|
pub struct OutputFileStream {
|
||||||
file_name: Atom,
|
file_name: Atom,
|
||||||
@@ -237,6 +250,51 @@ impl Write for NamedTlsStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct HttpReadStream {
|
||||||
|
url: Atom,
|
||||||
|
body_reader: Box<dyn BufRead>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for HttpReadStream {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "Http Read Stream [{}]", self.url.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read for HttpReadStream {
|
||||||
|
#[inline]
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
|
self.body_reader.read(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HttpWriteStream {
|
||||||
|
body_writer: Sender,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for HttpWriteStream {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "Http Write Stream")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for HttpWriteStream {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
let bytes = Bytes::copy_from_slice(buf);
|
||||||
|
let len = bytes.len();
|
||||||
|
match self.body_writer.try_send_data(bytes) {
|
||||||
|
Ok(()) => Ok(len),
|
||||||
|
Err(_) => Err(std::io::Error::from(ErrorKind::Interrupted))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StandardOutputStream {}
|
pub struct StandardOutputStream {}
|
||||||
|
|
||||||
@@ -375,6 +433,8 @@ arena_allocated_impl_for_stream!(CharReader<InputFileStream>, InputFileStream);
|
|||||||
arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream);
|
arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream);
|
||||||
arena_allocated_impl_for_stream!(CharReader<NamedTcpStream>, NamedTcpStream);
|
arena_allocated_impl_for_stream!(CharReader<NamedTcpStream>, NamedTcpStream);
|
||||||
arena_allocated_impl_for_stream!(CharReader<NamedTlsStream>, NamedTlsStream);
|
arena_allocated_impl_for_stream!(CharReader<NamedTlsStream>, NamedTlsStream);
|
||||||
|
arena_allocated_impl_for_stream!(CharReader<HttpReadStream>, HttpReadStream);
|
||||||
|
arena_allocated_impl_for_stream!(CharReader<HttpWriteStream>, HttpWriteStream);
|
||||||
arena_allocated_impl_for_stream!(ReadlineStream, ReadlineStream);
|
arena_allocated_impl_for_stream!(ReadlineStream, ReadlineStream);
|
||||||
arena_allocated_impl_for_stream!(StaticStringStream, StaticStringStream);
|
arena_allocated_impl_for_stream!(StaticStringStream, StaticStringStream);
|
||||||
arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream);
|
arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream);
|
||||||
@@ -388,6 +448,8 @@ pub enum Stream {
|
|||||||
StaticString(TypedArenaPtr<StreamLayout<StaticStringStream>>),
|
StaticString(TypedArenaPtr<StreamLayout<StaticStringStream>>),
|
||||||
NamedTcp(TypedArenaPtr<StreamLayout<CharReader<NamedTcpStream>>>),
|
NamedTcp(TypedArenaPtr<StreamLayout<CharReader<NamedTcpStream>>>),
|
||||||
NamedTls(TypedArenaPtr<StreamLayout<CharReader<NamedTlsStream>>>),
|
NamedTls(TypedArenaPtr<StreamLayout<CharReader<NamedTlsStream>>>),
|
||||||
|
HttpRead(TypedArenaPtr<StreamLayout<CharReader<HttpReadStream>>>),
|
||||||
|
HttpWrite(TypedArenaPtr<StreamLayout<CharReader<HttpWriteStream>>>),
|
||||||
Null(StreamOptions),
|
Null(StreamOptions),
|
||||||
Readline(TypedArenaPtr<StreamLayout<ReadlineStream>>),
|
Readline(TypedArenaPtr<StreamLayout<ReadlineStream>>),
|
||||||
StandardOutput(TypedArenaPtr<StreamLayout<StandardOutputStream>>),
|
StandardOutput(TypedArenaPtr<StreamLayout<StandardOutputStream>>),
|
||||||
@@ -426,9 +488,9 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn stdin(arena: &mut Arena) -> Stream {
|
pub fn stdin(arena: &mut Arena, add_history: bool) -> Stream {
|
||||||
Stream::Readline(arena_alloc!(
|
Stream::Readline(arena_alloc!(
|
||||||
StreamLayout::new(ReadlineStream::new("")),
|
StreamLayout::new(ReadlineStream::new("", add_history)),
|
||||||
arena
|
arena
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -442,6 +504,8 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)),
|
ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)),
|
||||||
ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)),
|
ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)),
|
||||||
|
ArenaHeaderTag::HttpReadStream => Stream::HttpRead(TypedArenaPtr::new(ptr as *mut _)),
|
||||||
|
ArenaHeaderTag::HttpWriteStream => Stream::HttpWrite(TypedArenaPtr::new(ptr as *mut _)),
|
||||||
ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)),
|
ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)),
|
||||||
ArenaHeaderTag::StaticStringStream => {
|
ArenaHeaderTag::StaticStringStream => {
|
||||||
Stream::StaticString(TypedArenaPtr::new(ptr as *mut _))
|
Stream::StaticString(TypedArenaPtr::new(ptr as *mut _))
|
||||||
@@ -452,7 +516,9 @@ impl Stream {
|
|||||||
ArenaHeaderTag::StandardErrorStream => {
|
ArenaHeaderTag::StandardErrorStream => {
|
||||||
Stream::StandardError(TypedArenaPtr::new(ptr as *mut _))
|
Stream::StandardError(TypedArenaPtr::new(ptr as *mut _))
|
||||||
}
|
}
|
||||||
ArenaHeaderTag::NullStream => Stream::Null(StreamOptions::default()),
|
ArenaHeaderTag::Dropped | ArenaHeaderTag::NullStream => {
|
||||||
|
Stream::Null(StreamOptions::default())
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -492,6 +558,8 @@ impl Stream {
|
|||||||
Stream::StaticString(ptr) => ptr.header_ptr(),
|
Stream::StaticString(ptr) => ptr.header_ptr(),
|
||||||
Stream::NamedTcp(ptr) => ptr.header_ptr(),
|
Stream::NamedTcp(ptr) => ptr.header_ptr(),
|
||||||
Stream::NamedTls(ptr) => ptr.header_ptr(),
|
Stream::NamedTls(ptr) => ptr.header_ptr(),
|
||||||
|
Stream::HttpRead(ptr) => ptr.header_ptr(),
|
||||||
|
Stream::HttpWrite(ptr) => ptr.header_ptr(),
|
||||||
Stream::Null(_) => ptr::null(),
|
Stream::Null(_) => ptr::null(),
|
||||||
Stream::Readline(ptr) => ptr.header_ptr(),
|
Stream::Readline(ptr) => ptr.header_ptr(),
|
||||||
Stream::StandardOutput(ptr) => ptr.header_ptr(),
|
Stream::StandardOutput(ptr) => ptr.header_ptr(),
|
||||||
@@ -507,6 +575,8 @@ impl Stream {
|
|||||||
Stream::StaticString(ref ptr) => &ptr.options,
|
Stream::StaticString(ref ptr) => &ptr.options,
|
||||||
Stream::NamedTcp(ref ptr) => &ptr.options,
|
Stream::NamedTcp(ref ptr) => &ptr.options,
|
||||||
Stream::NamedTls(ref ptr) => &ptr.options,
|
Stream::NamedTls(ref ptr) => &ptr.options,
|
||||||
|
Stream::HttpRead(ref ptr) => &ptr.options,
|
||||||
|
Stream::HttpWrite(ref ptr) => &ptr.options,
|
||||||
Stream::Null(ref options) => options,
|
Stream::Null(ref options) => options,
|
||||||
Stream::Readline(ref ptr) => &ptr.options,
|
Stream::Readline(ref ptr) => &ptr.options,
|
||||||
Stream::StandardOutput(ref ptr) => &ptr.options,
|
Stream::StandardOutput(ref ptr) => &ptr.options,
|
||||||
@@ -522,6 +592,8 @@ impl Stream {
|
|||||||
Stream::StaticString(ref mut ptr) => &mut ptr.options,
|
Stream::StaticString(ref mut ptr) => &mut ptr.options,
|
||||||
Stream::NamedTcp(ref mut ptr) => &mut ptr.options,
|
Stream::NamedTcp(ref mut ptr) => &mut ptr.options,
|
||||||
Stream::NamedTls(ref mut ptr) => &mut ptr.options,
|
Stream::NamedTls(ref mut ptr) => &mut ptr.options,
|
||||||
|
Stream::HttpRead(ref mut ptr) => &mut ptr.options,
|
||||||
|
Stream::HttpWrite(ref mut ptr) => &mut ptr.options,
|
||||||
Stream::Null(ref mut options) => options,
|
Stream::Null(ref mut options) => options,
|
||||||
Stream::Readline(ref mut ptr) => &mut ptr.options,
|
Stream::Readline(ref mut ptr) => &mut ptr.options,
|
||||||
Stream::StandardOutput(ref mut ptr) => &mut ptr.options,
|
Stream::StandardOutput(ref mut ptr) => &mut ptr.options,
|
||||||
@@ -538,6 +610,8 @@ impl Stream {
|
|||||||
Stream::StaticString(ptr) => ptr.lines_read += incr_num_lines_read,
|
Stream::StaticString(ptr) => ptr.lines_read += incr_num_lines_read,
|
||||||
Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read,
|
Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read,
|
||||||
Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read,
|
Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read,
|
||||||
|
Stream::HttpRead(ptr) => ptr.lines_read += incr_num_lines_read,
|
||||||
|
Stream::HttpWrite(_) => {}
|
||||||
Stream::Null(_) => {}
|
Stream::Null(_) => {}
|
||||||
Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read,
|
Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read,
|
||||||
Stream::StandardOutput(ptr) => ptr.lines_read += incr_num_lines_read,
|
Stream::StandardOutput(ptr) => ptr.lines_read += incr_num_lines_read,
|
||||||
@@ -554,6 +628,8 @@ impl Stream {
|
|||||||
Stream::StaticString(ptr) => ptr.lines_read = value,
|
Stream::StaticString(ptr) => ptr.lines_read = value,
|
||||||
Stream::NamedTcp(ptr) => ptr.lines_read = value,
|
Stream::NamedTcp(ptr) => ptr.lines_read = value,
|
||||||
Stream::NamedTls(ptr) => ptr.lines_read = value,
|
Stream::NamedTls(ptr) => ptr.lines_read = value,
|
||||||
|
Stream::HttpRead(ptr) => ptr.lines_read = value,
|
||||||
|
Stream::HttpWrite(_) => {}
|
||||||
Stream::Null(_) => {}
|
Stream::Null(_) => {}
|
||||||
Stream::Readline(ptr) => ptr.lines_read = value,
|
Stream::Readline(ptr) => ptr.lines_read = value,
|
||||||
Stream::StandardOutput(ptr) => ptr.lines_read = value,
|
Stream::StandardOutput(ptr) => ptr.lines_read = value,
|
||||||
@@ -570,6 +646,8 @@ impl Stream {
|
|||||||
Stream::StaticString(ptr) => ptr.lines_read,
|
Stream::StaticString(ptr) => ptr.lines_read,
|
||||||
Stream::NamedTcp(ptr) => ptr.lines_read,
|
Stream::NamedTcp(ptr) => ptr.lines_read,
|
||||||
Stream::NamedTls(ptr) => ptr.lines_read,
|
Stream::NamedTls(ptr) => ptr.lines_read,
|
||||||
|
Stream::HttpRead(ptr) => ptr.lines_read,
|
||||||
|
Stream::HttpWrite(_) => 0,
|
||||||
Stream::Null(_) => 0,
|
Stream::Null(_) => 0,
|
||||||
Stream::Readline(ptr) => ptr.lines_read,
|
Stream::Readline(ptr) => ptr.lines_read,
|
||||||
Stream::StandardOutput(ptr) => ptr.lines_read,
|
Stream::StandardOutput(ptr) => ptr.lines_read,
|
||||||
@@ -584,12 +662,14 @@ impl CharRead for Stream {
|
|||||||
Stream::InputFile(file) => (*file).peek_char(),
|
Stream::InputFile(file) => (*file).peek_char(),
|
||||||
Stream::NamedTcp(tcp_stream) => (*tcp_stream).peek_char(),
|
Stream::NamedTcp(tcp_stream) => (*tcp_stream).peek_char(),
|
||||||
Stream::NamedTls(tls_stream) => (*tls_stream).peek_char(),
|
Stream::NamedTls(tls_stream) => (*tls_stream).peek_char(),
|
||||||
|
Stream::HttpRead(http_stream) => (*http_stream).peek_char(),
|
||||||
Stream::Readline(rl_stream) => (*rl_stream).peek_char(),
|
Stream::Readline(rl_stream) => (*rl_stream).peek_char(),
|
||||||
Stream::StaticString(src) => (*src).peek_char(),
|
Stream::StaticString(src) => (*src).peek_char(),
|
||||||
Stream::Byte(cursor) => (*cursor).peek_char(),
|
Stream::Byte(cursor) => (*cursor).peek_char(),
|
||||||
Stream::OutputFile(_) |
|
Stream::OutputFile(_) |
|
||||||
Stream::StandardError(_) |
|
Stream::StandardError(_) |
|
||||||
Stream::StandardOutput(_) |
|
Stream::StandardOutput(_) |
|
||||||
|
Stream::HttpWrite(_) |
|
||||||
Stream::Null(_) => Some(Err(std::io::Error::new(
|
Stream::Null(_) => Some(Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::ReadFromOutputStream,
|
StreamError::ReadFromOutputStream,
|
||||||
@@ -602,12 +682,14 @@ impl CharRead for Stream {
|
|||||||
Stream::InputFile(file) => (*file).read_char(),
|
Stream::InputFile(file) => (*file).read_char(),
|
||||||
Stream::NamedTcp(tcp_stream) => (*tcp_stream).read_char(),
|
Stream::NamedTcp(tcp_stream) => (*tcp_stream).read_char(),
|
||||||
Stream::NamedTls(tls_stream) => (*tls_stream).read_char(),
|
Stream::NamedTls(tls_stream) => (*tls_stream).read_char(),
|
||||||
|
Stream::HttpRead(http_stream) => (*http_stream).read_char(),
|
||||||
Stream::Readline(rl_stream) => (*rl_stream).read_char(),
|
Stream::Readline(rl_stream) => (*rl_stream).read_char(),
|
||||||
Stream::StaticString(src) => (*src).read_char(),
|
Stream::StaticString(src) => (*src).read_char(),
|
||||||
Stream::Byte(cursor) => (*cursor).read_char(),
|
Stream::Byte(cursor) => (*cursor).read_char(),
|
||||||
Stream::OutputFile(_) |
|
Stream::OutputFile(_) |
|
||||||
Stream::StandardError(_) |
|
Stream::StandardError(_) |
|
||||||
Stream::StandardOutput(_) |
|
Stream::StandardOutput(_) |
|
||||||
|
Stream::HttpWrite(_) |
|
||||||
Stream::Null(_) => Some(Err(std::io::Error::new(
|
Stream::Null(_) => Some(Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::ReadFromOutputStream,
|
StreamError::ReadFromOutputStream,
|
||||||
@@ -620,12 +702,14 @@ impl CharRead for Stream {
|
|||||||
Stream::InputFile(file) => file.put_back_char(c),
|
Stream::InputFile(file) => file.put_back_char(c),
|
||||||
Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c),
|
Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c),
|
||||||
Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c),
|
Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c),
|
||||||
|
Stream::HttpRead(http_stream) => http_stream.put_back_char(c),
|
||||||
Stream::Readline(rl_stream) => rl_stream.put_back_char(c),
|
Stream::Readline(rl_stream) => rl_stream.put_back_char(c),
|
||||||
Stream::StaticString(src) => src.put_back_char(c),
|
Stream::StaticString(src) => src.put_back_char(c),
|
||||||
Stream::Byte(cursor) => cursor.put_back_char(c),
|
Stream::Byte(cursor) => cursor.put_back_char(c),
|
||||||
Stream::OutputFile(_) |
|
Stream::OutputFile(_) |
|
||||||
Stream::StandardError(_) |
|
Stream::StandardError(_) |
|
||||||
Stream::StandardOutput(_) |
|
Stream::StandardOutput(_) |
|
||||||
|
Stream::HttpWrite(_) |
|
||||||
Stream::Null(_) => {}
|
Stream::Null(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -635,12 +719,14 @@ impl CharRead for Stream {
|
|||||||
Stream::InputFile(ref mut file) => file.consume(nread),
|
Stream::InputFile(ref mut file) => file.consume(nread),
|
||||||
Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread),
|
Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread),
|
||||||
Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread),
|
Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread),
|
||||||
|
Stream::HttpRead(ref mut http_stream) => http_stream.consume(nread),
|
||||||
Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread),
|
Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread),
|
||||||
Stream::StaticString(ref mut src) => src.consume(nread),
|
Stream::StaticString(ref mut src) => src.consume(nread),
|
||||||
Stream::Byte(ref mut cursor) => cursor.consume(nread),
|
Stream::Byte(ref mut cursor) => cursor.consume(nread),
|
||||||
Stream::OutputFile(_) |
|
Stream::OutputFile(_) |
|
||||||
Stream::StandardError(_) |
|
Stream::StandardError(_) |
|
||||||
Stream::StandardOutput(_) |
|
Stream::StandardOutput(_) |
|
||||||
|
Stream::HttpWrite(_) |
|
||||||
Stream::Null(_) => {}
|
Stream::Null(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -653,12 +739,14 @@ impl Read for Stream {
|
|||||||
Stream::InputFile(file) => (*file).read(buf),
|
Stream::InputFile(file) => (*file).read(buf),
|
||||||
Stream::NamedTcp(tcp_stream) => (*tcp_stream).read(buf),
|
Stream::NamedTcp(tcp_stream) => (*tcp_stream).read(buf),
|
||||||
Stream::NamedTls(tls_stream) => (*tls_stream).read(buf),
|
Stream::NamedTls(tls_stream) => (*tls_stream).read(buf),
|
||||||
|
Stream::HttpRead(http_stream) => (*http_stream).read(buf),
|
||||||
Stream::Readline(rl_stream) => (*rl_stream).read(buf),
|
Stream::Readline(rl_stream) => (*rl_stream).read(buf),
|
||||||
Stream::StaticString(src) => (*src).read(buf),
|
Stream::StaticString(src) => (*src).read(buf),
|
||||||
Stream::Byte(cursor) => (*cursor).read(buf),
|
Stream::Byte(cursor) => (*cursor).read(buf),
|
||||||
Stream::OutputFile(_)
|
Stream::OutputFile(_)
|
||||||
| Stream::StandardError(_)
|
| Stream::StandardError(_)
|
||||||
| Stream::StandardOutput(_)
|
| Stream::StandardOutput(_)
|
||||||
|
| Stream::HttpWrite(_)
|
||||||
| Stream::Null(_) => Err(std::io::Error::new(
|
| Stream::Null(_) => Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::ReadFromOutputStream,
|
StreamError::ReadFromOutputStream,
|
||||||
@@ -678,6 +766,8 @@ impl Write for Stream {
|
|||||||
Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf),
|
Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf),
|
||||||
Stream::StandardOutput(stream) => stream.write(buf),
|
Stream::StandardOutput(stream) => stream.write(buf),
|
||||||
Stream::StandardError(stream) => stream.write(buf),
|
Stream::StandardError(stream) => stream.write(buf),
|
||||||
|
Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf),
|
||||||
|
Stream::HttpRead(_) |
|
||||||
Stream::StaticString(_) |
|
Stream::StaticString(_) |
|
||||||
Stream::Readline(_) |
|
Stream::Readline(_) |
|
||||||
Stream::InputFile(..) |
|
Stream::InputFile(..) |
|
||||||
@@ -696,6 +786,8 @@ impl Write for Stream {
|
|||||||
Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(),
|
Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(),
|
||||||
Stream::StandardError(stream) => stream.stream.flush(),
|
Stream::StandardError(stream) => stream.stream.flush(),
|
||||||
Stream::StandardOutput(stream) => stream.stream.flush(),
|
Stream::StandardOutput(stream) => stream.stream.flush(),
|
||||||
|
Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(),
|
||||||
|
Stream::HttpRead(_) |
|
||||||
Stream::StaticString(_) |
|
Stream::StaticString(_) |
|
||||||
Stream::Readline(_) |
|
Stream::Readline(_) |
|
||||||
Stream::InputFile(_) |
|
Stream::InputFile(_) |
|
||||||
@@ -776,8 +868,8 @@ impl Stream {
|
|||||||
pub(crate) fn position(&mut self) -> Option<(u64, usize)> {
|
pub(crate) fn position(&mut self) -> Option<(u64, usize)> {
|
||||||
// returns lines_read, position.
|
// returns lines_read, position.
|
||||||
let result = match self {
|
let result = match self {
|
||||||
Stream::InputFile(ref mut file_stream) => {
|
Stream::InputFile(file_stream) => {
|
||||||
file_stream.get_mut().file.seek(SeekFrom::Current(0)).ok()
|
file_stream.position()
|
||||||
}
|
}
|
||||||
Stream::NamedTcp(..)
|
Stream::NamedTcp(..)
|
||||||
| Stream::NamedTls(..)
|
| Stream::NamedTls(..)
|
||||||
@@ -801,6 +893,7 @@ impl Stream {
|
|||||||
} = &mut **stream_layout;
|
} = &mut **stream_layout;
|
||||||
|
|
||||||
stream.get_mut().file.seek(SeekFrom::Start(position)).unwrap();
|
stream.get_mut().file.seek(SeekFrom::Start(position)).unwrap();
|
||||||
|
stream.reset_buffer(); // flush the internal buffer.
|
||||||
|
|
||||||
if let Ok(metadata) = stream.get_ref().file.metadata() {
|
if let Ok(metadata) = stream.get_ref().file.metadata() {
|
||||||
*past_end_of_stream = position > metadata.len();
|
*past_end_of_stream = position > metadata.len();
|
||||||
@@ -816,10 +909,11 @@ impl Stream {
|
|||||||
Stream::Byte(stream) => stream.past_end_of_stream,
|
Stream::Byte(stream) => stream.past_end_of_stream,
|
||||||
Stream::InputFile(stream) => stream.past_end_of_stream,
|
Stream::InputFile(stream) => stream.past_end_of_stream,
|
||||||
Stream::OutputFile(stream) => stream.past_end_of_stream,
|
Stream::OutputFile(stream) => stream.past_end_of_stream,
|
||||||
// Stream::PausedProlog(stream) => stream.paused_stream.past_end_of_stream(),
|
|
||||||
Stream::StaticString(stream) => stream.past_end_of_stream,
|
Stream::StaticString(stream) => stream.past_end_of_stream,
|
||||||
Stream::NamedTcp(stream) => stream.past_end_of_stream,
|
Stream::NamedTcp(stream) => stream.past_end_of_stream,
|
||||||
Stream::NamedTls(stream) => stream.past_end_of_stream,
|
Stream::NamedTls(stream) => stream.past_end_of_stream,
|
||||||
|
Stream::HttpRead(stream) => stream.past_end_of_stream,
|
||||||
|
Stream::HttpWrite(stream) => stream.past_end_of_stream,
|
||||||
Stream::Null(_) => false,
|
Stream::Null(_) => false,
|
||||||
Stream::Readline(stream) => stream.past_end_of_stream,
|
Stream::Readline(stream) => stream.past_end_of_stream,
|
||||||
Stream::StandardOutput(stream) => stream.past_end_of_stream,
|
Stream::StandardOutput(stream) => stream.past_end_of_stream,
|
||||||
@@ -841,6 +935,8 @@ impl Stream {
|
|||||||
Stream::StaticString(stream) => stream.past_end_of_stream = value,
|
Stream::StaticString(stream) => stream.past_end_of_stream = value,
|
||||||
Stream::NamedTcp(stream) => stream.past_end_of_stream = value,
|
Stream::NamedTcp(stream) => stream.past_end_of_stream = value,
|
||||||
Stream::NamedTls(stream) => stream.past_end_of_stream = value,
|
Stream::NamedTls(stream) => stream.past_end_of_stream = value,
|
||||||
|
Stream::HttpRead(stream) => stream.past_end_of_stream = value,
|
||||||
|
Stream::HttpWrite(stream) => stream.past_end_of_stream = value,
|
||||||
Stream::Null(_) => {}
|
Stream::Null(_) => {}
|
||||||
Stream::Readline(stream) => stream.past_end_of_stream = value,
|
Stream::Readline(stream) => stream.past_end_of_stream = value,
|
||||||
Stream::StandardOutput(stream) => stream.past_end_of_stream = value,
|
Stream::StandardOutput(stream) => stream.past_end_of_stream = value,
|
||||||
@@ -855,6 +951,8 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Stream::InputFile(stream_layout) = self {
|
if let Stream::InputFile(stream_layout) = self {
|
||||||
|
let position = stream_layout.position();
|
||||||
|
|
||||||
let StreamLayout {
|
let StreamLayout {
|
||||||
past_end_of_stream,
|
past_end_of_stream,
|
||||||
stream,
|
stream,
|
||||||
@@ -863,7 +961,7 @@ impl Stream {
|
|||||||
|
|
||||||
match stream.get_ref().file.metadata() {
|
match stream.get_ref().file.metadata() {
|
||||||
Ok(metadata) => {
|
Ok(metadata) => {
|
||||||
if let Ok(position) = stream.get_mut().file.seek(SeekFrom::Current(0)) {
|
if let Some(position) = position {
|
||||||
return match position.cmp(&metadata.len()) {
|
return match position.cmp(&metadata.len()) {
|
||||||
Ordering::Equal => AtEndOfStream::At,
|
Ordering::Equal => AtEndOfStream::At,
|
||||||
Ordering::Less => AtEndOfStream::Not,
|
Ordering::Less => AtEndOfStream::Not,
|
||||||
@@ -904,10 +1002,11 @@ impl Stream {
|
|||||||
Stream::Byte(_)
|
Stream::Byte(_)
|
||||||
| Stream::Readline(_)
|
| Stream::Readline(_)
|
||||||
| Stream::StaticString(_)
|
| Stream::StaticString(_)
|
||||||
|
| Stream::HttpRead(_)
|
||||||
| Stream::InputFile(..) => atom!("read"),
|
| Stream::InputFile(..) => atom!("read"),
|
||||||
Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"),
|
Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"),
|
||||||
Stream::OutputFile(file) if file.is_append => atom!("append"),
|
Stream::OutputFile(file) if file.is_append => atom!("append"),
|
||||||
Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) => atom!("write"),
|
Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) | Stream::HttpWrite(_) => atom!("write"),
|
||||||
Stream::Null(_) => atom!(""),
|
Stream::Null(_) => atom!(""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -961,6 +1060,34 @@ impl Stream {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn from_http_stream(
|
||||||
|
url: Atom,
|
||||||
|
http_stream: Box<dyn BufRead>,
|
||||||
|
arena: &mut Arena,
|
||||||
|
) -> Self {
|
||||||
|
Stream::HttpRead(arena_alloc!(
|
||||||
|
StreamLayout::new(CharReader::new(HttpReadStream {
|
||||||
|
url,
|
||||||
|
body_reader: http_stream
|
||||||
|
})),
|
||||||
|
arena
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn from_http_sender(
|
||||||
|
body_writer: Sender,
|
||||||
|
arena: &mut Arena,
|
||||||
|
) -> Self {
|
||||||
|
Stream::HttpWrite(arena_alloc!(
|
||||||
|
StreamLayout::new(CharReader::new(HttpWriteStream {
|
||||||
|
body_writer
|
||||||
|
})),
|
||||||
|
arena
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn from_file_as_output(
|
pub(crate) fn from_file_as_output(
|
||||||
file_name: Atom,
|
file_name: Atom,
|
||||||
@@ -988,18 +1115,51 @@ impl Stream {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn close(&mut self) -> Result<(), std::io::Error> {
|
pub(crate) fn close(&mut self) -> Result<(), std::io::Error> {
|
||||||
let result = match self {
|
let mut stream = std::mem::replace(self, Stream::Null(StreamOptions::default()));
|
||||||
|
|
||||||
|
match stream {
|
||||||
Stream::NamedTcp(ref mut tcp_stream) => {
|
Stream::NamedTcp(ref mut tcp_stream) => {
|
||||||
tcp_stream.inner_mut().tcp_stream.shutdown(Shutdown::Both)
|
tcp_stream.inner_mut().tcp_stream.shutdown(Shutdown::Both)
|
||||||
},
|
},
|
||||||
Stream::NamedTls(ref mut tls_stream) => {
|
Stream::NamedTls(ref mut tls_stream) => {
|
||||||
tls_stream.inner_mut().tls_stream.shutdown()
|
tls_stream.inner_mut().tls_stream.shutdown()
|
||||||
}
|
}
|
||||||
_ => Ok(())
|
Stream::HttpRead(ref mut http_stream) => {
|
||||||
};
|
unsafe {
|
||||||
|
http_stream.set_tag(ArenaHeaderTag::Dropped);
|
||||||
|
std::ptr::drop_in_place(&mut http_stream.inner_mut().body_reader as *mut _);
|
||||||
|
}
|
||||||
|
|
||||||
*self = Stream::Null(StreamOptions::default());
|
Ok(())
|
||||||
result
|
}
|
||||||
|
Stream::HttpWrite(ref mut http_stream) => {
|
||||||
|
unsafe {
|
||||||
|
http_stream.set_tag(ArenaHeaderTag::Dropped);
|
||||||
|
std::ptr::drop_in_place(&mut http_stream.inner_mut().body_writer as *mut _);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Stream::InputFile(mut file_stream) => {
|
||||||
|
// close the stream by dropping the inner File.
|
||||||
|
unsafe {
|
||||||
|
file_stream.set_tag(ArenaHeaderTag::Dropped);
|
||||||
|
std::ptr::drop_in_place(&mut file_stream.inner_mut().file as *mut _);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Stream::OutputFile(mut file_stream) => {
|
||||||
|
// close the stream by dropping the inner File.
|
||||||
|
unsafe {
|
||||||
|
file_stream.set_tag(ArenaHeaderTag::Dropped);
|
||||||
|
std::ptr::drop_in_place(&mut file_stream.file as *mut _);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -1016,6 +1176,7 @@ impl Stream {
|
|||||||
match self {
|
match self {
|
||||||
Stream::NamedTcp(..)
|
Stream::NamedTcp(..)
|
||||||
| Stream::NamedTls(..)
|
| Stream::NamedTls(..)
|
||||||
|
| Stream::HttpRead(..)
|
||||||
| Stream::Byte(_)
|
| Stream::Byte(_)
|
||||||
| Stream::Readline(_)
|
| Stream::Readline(_)
|
||||||
| Stream::StaticString(_)
|
| Stream::StaticString(_)
|
||||||
@@ -1031,6 +1192,7 @@ impl Stream {
|
|||||||
| Stream::StandardOutput(_)
|
| Stream::StandardOutput(_)
|
||||||
| Stream::NamedTcp(..)
|
| Stream::NamedTcp(..)
|
||||||
| Stream::NamedTls(..)
|
| Stream::NamedTls(..)
|
||||||
|
| Stream::HttpWrite(..)
|
||||||
| Stream::Byte(_)
|
| Stream::Byte(_)
|
||||||
| Stream::OutputFile(..) => true,
|
| Stream::OutputFile(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
@@ -1160,6 +1322,18 @@ impl MachineState {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
|
||||||
|
if name != atom!("[]") {
|
||||||
|
Some(name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -1176,6 +1350,19 @@ impl MachineState {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
|
||||||
|
match name {
|
||||||
|
atom!("eof_code") => EOFAction::EOFCode,
|
||||||
|
atom!("error") => EOFAction::Error,
|
||||||
|
atom!("reset") => EOFAction::Reset,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@@ -1186,6 +1373,13 @@ impl MachineState {
|
|||||||
debug_assert_eq!(arity, 0);
|
debug_assert_eq!(arity, 0);
|
||||||
name == atom!("true")
|
name == atom!("true")
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
name == atom!("true")
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@@ -1200,6 +1394,17 @@ impl MachineState {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
match name {
|
||||||
|
atom!("text") => StreamType::Text,
|
||||||
|
atom!("binary") => StreamType::Binary,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@@ -1240,6 +1445,24 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
|
||||||
|
return match stream_aliases.get(&name) {
|
||||||
|
Some(stream) if !stream.is_null_stream() => Ok(*stream),
|
||||||
|
_ => {
|
||||||
|
let stub = functor_stub(caller, arity);
|
||||||
|
let addr = atom_as_cell!(name);
|
||||||
|
|
||||||
|
let existence_error = self.existence_error(ExistenceError::Stream(addr));
|
||||||
|
|
||||||
|
Err(self.error_form(existence_error, stub))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
(HeapCellValueTag::Cons, ptr) => {
|
(HeapCellValueTag::Cons, ptr) => {
|
||||||
match_untyped_arena_ptr!(ptr,
|
match_untyped_arena_ptr!(ptr,
|
||||||
(ArenaHeaderTag::Stream, stream) => {
|
(ArenaHeaderTag::Stream, stream) => {
|
||||||
@@ -1249,6 +1472,12 @@ impl MachineState {
|
|||||||
Ok(stream)
|
Ok(stream)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
(ArenaHeaderTag::Dropped, _value) => {
|
||||||
|
let stub = functor_stub(caller, arity);
|
||||||
|
let err = self.existence_error(ExistenceError::Stream(addr));
|
||||||
|
|
||||||
|
return Err(self.error_form(err, stub));
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -1304,7 +1533,7 @@ impl MachineState {
|
|||||||
let stub = functor_stub(caller, arity);
|
let stub = functor_stub(caller, arity);
|
||||||
let err = self.permission_error(perm, err_atom, stream_as_cell!(stream));
|
let err = self.permission_error(perm, err_atom, stream_as_cell!(stream));
|
||||||
|
|
||||||
return self.error_form(err, stub);
|
self.error_form(err, stub)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -1332,7 +1561,7 @@ impl MachineState {
|
|||||||
let stub = functor_stub(stub_name, stub_arity);
|
let stub = functor_stub(stub_name, stub_arity);
|
||||||
let err = self.permission_error(Permission::Open, atom!("source_sink"), culprit);
|
let err = self.permission_error(Permission::Open, atom!("source_sink"), culprit);
|
||||||
|
|
||||||
return self.error_form(err, stub);
|
self.error_form(err, stub)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn occupied_alias_permission_error(
|
pub(crate) fn occupied_alias_permission_error(
|
||||||
@@ -1342,24 +1571,22 @@ impl MachineState {
|
|||||||
stub_arity: usize,
|
stub_arity: usize,
|
||||||
) -> MachineStub {
|
) -> MachineStub {
|
||||||
let stub = functor_stub(stub_name, stub_arity);
|
let stub = functor_stub(stub_name, stub_arity);
|
||||||
let alias_name = atom!("alias");
|
|
||||||
|
|
||||||
let err = self.permission_error(
|
let err = self.permission_error(
|
||||||
Permission::Open,
|
Permission::Open,
|
||||||
atom!("source_sink"),
|
atom!("source_sink"),
|
||||||
functor!(alias_name, [atom(alias)]),
|
functor!(atom!("alias"), [atom(alias)]),
|
||||||
);
|
);
|
||||||
|
|
||||||
return self.error_form(err, stub);
|
self.error_form(err, stub)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub {
|
pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub {
|
||||||
let stub = functor_stub(stub_name, stub_arity);
|
let stub = functor_stub(stub_name, stub_arity);
|
||||||
|
|
||||||
let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]);
|
let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]);
|
||||||
let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub);
|
let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub);
|
||||||
|
|
||||||
return self.error_form(err, stub);
|
self.error_form(err, stub)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn check_stream_properties(
|
pub(crate) fn check_stream_properties(
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -119,3 +119,21 @@ impl TermStream for LiveTermStream {
|
|||||||
&self.listing_src
|
&self.listing_src
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InlineTermStream {
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TermStream for InlineTermStream {
|
||||||
|
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
|
||||||
|
Err(CompilationError::from(ParserError::UnexpectedEOF))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eof(&mut self) -> Result<bool, CompilationError> {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn listing_src(&self) -> &ListingSource {
|
||||||
|
&ListingSource::User
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,10 +87,8 @@ macro_rules! cell_as_atom_cell {
|
|||||||
|
|
||||||
macro_rules! cell_as_f64_ptr {
|
macro_rules! cell_as_f64_ptr {
|
||||||
($cell:expr) => {{
|
($cell:expr) => {{
|
||||||
let ptr_u64 = ConsPtr::from_bytes($cell.into_bytes());
|
let offset = $cell.get_value();
|
||||||
F64Ptr(TypedArenaPtr::new(
|
F64Ptr::from_offset(offset)
|
||||||
ptr_u64.as_ptr() as *mut OrderedFloat<f64>
|
|
||||||
))
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,13 +244,6 @@ macro_rules! match_untyped_arena_ptr_pat_body {
|
|||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
$code
|
$code
|
||||||
}};
|
}};
|
||||||
($ptr:ident, F64, $n:ident, $code:expr) => {{
|
|
||||||
let payload_ptr =
|
|
||||||
unsafe { std::mem::transmute::<_, *mut OrderedFloat<f64>>($ptr.payload_offset()) };
|
|
||||||
let $n = TypedArenaPtr::new(payload_ptr);
|
|
||||||
#[allow(unused_braces)]
|
|
||||||
$code
|
|
||||||
}};
|
|
||||||
($ptr:ident, Rational, $n:ident, $code:expr) => {{
|
($ptr:ident, Rational, $n:ident, $code:expr) => {{
|
||||||
let payload_ptr = unsafe { std::mem::transmute::<_, *mut Rational>($ptr.payload_offset()) };
|
let payload_ptr = unsafe { std::mem::transmute::<_, *mut Rational>($ptr.payload_offset()) };
|
||||||
let $n = TypedArenaPtr::new(payload_ptr);
|
let $n = TypedArenaPtr::new(payload_ptr);
|
||||||
@@ -281,6 +272,26 @@ macro_rules! match_untyped_arena_ptr_pat_body {
|
|||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
$code
|
$code
|
||||||
}};
|
}};
|
||||||
|
($ptr:ident, HttpListener, $listener:ident, $code:expr) => {{
|
||||||
|
let payload_ptr = unsafe { std::mem::transmute::<_, *mut HttpListener>($ptr.payload_offset()) };
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut $listener = TypedArenaPtr::new(payload_ptr);
|
||||||
|
#[allow(unused_braces)]
|
||||||
|
$code
|
||||||
|
}};
|
||||||
|
($ptr:ident, HttpResponse, $listener:ident, $code:expr) => {{
|
||||||
|
let payload_ptr = unsafe { std::mem::transmute::<_, *mut HttpResponse>($ptr.payload_offset()) };
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut $listener = TypedArenaPtr::new(payload_ptr);
|
||||||
|
#[allow(unused_braces)]
|
||||||
|
$code
|
||||||
|
}};
|
||||||
|
($ptr:ident, IndexPtr, $ip:ident, $code:expr) => {{
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut $ip = TypedArenaPtr::new(unsafe { std::mem::transmute::<_, *mut IndexPtr>($ptr.get_ptr()) });
|
||||||
|
#[allow(unused_braces)]
|
||||||
|
$code
|
||||||
|
}};
|
||||||
($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{
|
($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{
|
||||||
let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
|
let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
|
||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
@@ -294,12 +305,20 @@ macro_rules! match_untyped_arena_ptr_pat {
|
|||||||
| ArenaHeaderTag::OutputFileStream
|
| ArenaHeaderTag::OutputFileStream
|
||||||
| ArenaHeaderTag::NamedTcpStream
|
| ArenaHeaderTag::NamedTcpStream
|
||||||
| ArenaHeaderTag::NamedTlsStream
|
| ArenaHeaderTag::NamedTlsStream
|
||||||
|
| ArenaHeaderTag::HttpReadStream
|
||||||
|
| ArenaHeaderTag::HttpWriteStream
|
||||||
| ArenaHeaderTag::ReadlineStream
|
| ArenaHeaderTag::ReadlineStream
|
||||||
| ArenaHeaderTag::StaticStringStream
|
| ArenaHeaderTag::StaticStringStream
|
||||||
| ArenaHeaderTag::ByteStream
|
| ArenaHeaderTag::ByteStream
|
||||||
| ArenaHeaderTag::StandardOutputStream
|
| ArenaHeaderTag::StandardOutputStream
|
||||||
| ArenaHeaderTag::StandardErrorStream
|
| ArenaHeaderTag::StandardErrorStream
|
||||||
};
|
};
|
||||||
|
(IndexPtr) => {
|
||||||
|
ArenaHeaderTag::IndexPtrUndefined |
|
||||||
|
ArenaHeaderTag::IndexPtrDynamicUndefined |
|
||||||
|
ArenaHeaderTag::IndexPtrDynamicIndex |
|
||||||
|
ArenaHeaderTag::IndexPtrIndex
|
||||||
|
};
|
||||||
($tag:ident) => {
|
($tag:ident) => {
|
||||||
ArenaHeaderTag::$tag
|
ArenaHeaderTag::$tag
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
|
use crate::machine::machine_indices::*;
|
||||||
use crate::parser::char_reader::*;
|
use crate::parser::char_reader::*;
|
||||||
use crate::types::HeapCellValueTag;
|
use crate::types::HeapCellValueTag;
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ use std::ops::Neg;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
use rug::{Integer, Rational};
|
use crate::parser::rug::{Integer, Rational};
|
||||||
|
|
||||||
use fxhash::FxBuildHasher;
|
use fxhash::FxBuildHasher;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
@@ -234,12 +235,22 @@ pub enum GenContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GenContext {
|
impl GenContext {
|
||||||
|
#[inline]
|
||||||
pub fn chunk_num(self) -> usize {
|
pub fn chunk_num(self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
GenContext::Head => 0,
|
GenContext::Head => 0,
|
||||||
GenContext::Mid(cn) | GenContext::Last(cn) => cn,
|
GenContext::Mid(cn) | GenContext::Last(cn) => cn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_last(self) -> bool {
|
||||||
|
if let GenContext::Last(_) = self {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bitfield]
|
#[bitfield]
|
||||||
@@ -361,28 +372,28 @@ pub enum ArithmeticError {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParserError {
|
pub enum ParserError {
|
||||||
BackQuotedString(usize, usize),
|
BackQuotedString(usize, usize),
|
||||||
UnexpectedChar(char, usize, usize),
|
|
||||||
UnexpectedEOF,
|
|
||||||
IO(IOError),
|
IO(IOError),
|
||||||
IncompleteReduction(usize, usize),
|
IncompleteReduction(usize, usize),
|
||||||
InvalidSingleQuotedCharacter(char),
|
InvalidSingleQuotedCharacter(char),
|
||||||
|
LexicalError(lexical::Error),
|
||||||
MissingQuote(usize, usize),
|
MissingQuote(usize, usize),
|
||||||
NonPrologChar(usize, usize),
|
NonPrologChar(usize, usize),
|
||||||
ParseBigInt(usize, usize),
|
ParseBigInt(usize, usize),
|
||||||
LexicalError(lexical::Error),
|
UnexpectedChar(char, usize, usize),
|
||||||
|
UnexpectedEOF,
|
||||||
Utf8Error(usize, usize),
|
Utf8Error(usize, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParserError {
|
impl ParserError {
|
||||||
pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
|
pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
|
||||||
match self {
|
match self {
|
||||||
&ParserError::BackQuotedString(line_num, col_num)
|
&ParserError::BackQuotedString(line_num, col_num) |
|
||||||
| &ParserError::UnexpectedChar(_, line_num, col_num)
|
&ParserError::IncompleteReduction(line_num, col_num) |
|
||||||
| &ParserError::IncompleteReduction(line_num, col_num)
|
&ParserError::MissingQuote(line_num, col_num) |
|
||||||
| &ParserError::MissingQuote(line_num, col_num)
|
&ParserError::NonPrologChar(line_num, col_num) |
|
||||||
| &ParserError::NonPrologChar(line_num, col_num)
|
&ParserError::ParseBigInt(line_num, col_num) |
|
||||||
| &ParserError::ParseBigInt(line_num, col_num)
|
&ParserError::UnexpectedChar(_, line_num, col_num) |
|
||||||
| &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
|
&ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -390,8 +401,6 @@ impl ParserError {
|
|||||||
pub fn as_atom(&self) -> Atom {
|
pub fn as_atom(&self) -> Atom {
|
||||||
match self {
|
match self {
|
||||||
ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
|
ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
|
||||||
ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
|
|
||||||
ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"),
|
|
||||||
ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
|
ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
|
||||||
ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"),
|
ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"),
|
||||||
ParserError::IO(_) => atom!("input_output_error"),
|
ParserError::IO(_) => atom!("input_output_error"),
|
||||||
@@ -399,6 +408,8 @@ impl ParserError {
|
|||||||
ParserError::MissingQuote(..) => atom!("missing_quote"),
|
ParserError::MissingQuote(..) => atom!("missing_quote"),
|
||||||
ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
|
ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
|
||||||
ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
|
ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
|
||||||
|
ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
|
||||||
|
ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"),
|
||||||
ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
|
ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -466,7 +477,8 @@ pub enum Fixity {
|
|||||||
#[repr(u64)]
|
#[repr(u64)]
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
pub struct Fixnum {
|
pub struct Fixnum {
|
||||||
num: B57,
|
num: B56,
|
||||||
|
#[allow(unused)] f: bool,
|
||||||
#[allow(unused)] m: bool,
|
#[allow(unused)] m: bool,
|
||||||
#[allow(unused)] tag: B6,
|
#[allow(unused)] tag: B6,
|
||||||
}
|
}
|
||||||
@@ -475,22 +487,23 @@ impl Fixnum {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn build_with(num: i64) -> Self {
|
pub fn build_with(num: i64) -> Self {
|
||||||
Fixnum::new()
|
Fixnum::new()
|
||||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))
|
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
|
||||||
.with_tag(HeapCellValueTag::Fixnum as u8)
|
.with_tag(HeapCellValueTag::Fixnum as u8)
|
||||||
.with_m(false)
|
.with_m(false)
|
||||||
//num as u64).with__m(false)
|
.with_f(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> {
|
pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> {
|
||||||
const UPPER_BOUND: i64 = (1 << 56) - 1;
|
const UPPER_BOUND: i64 = (1 << 55) - 1;
|
||||||
const LOWER_BOUND: i64 = -(1 << 56);
|
const LOWER_BOUND: i64 = -(1 << 55);
|
||||||
|
|
||||||
if LOWER_BOUND <= num && num <= UPPER_BOUND {
|
if LOWER_BOUND <= num && num <= UPPER_BOUND {
|
||||||
Ok(Fixnum::new()
|
Ok(Fixnum::new()
|
||||||
.with_m(false)
|
.with_m(false)
|
||||||
|
.with_f(false)
|
||||||
.with_tag(HeapCellValueTag::Fixnum as u8)
|
.with_tag(HeapCellValueTag::Fixnum as u8)
|
||||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))) //num as u64 & ((1 << 57) - 1)))
|
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1)))
|
||||||
} else {
|
} else {
|
||||||
Err(OutOfBounds {})
|
Err(OutOfBounds {})
|
||||||
}
|
}
|
||||||
@@ -499,7 +512,7 @@ impl Fixnum {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_num(self) -> i64 {
|
pub fn get_num(self) -> i64 {
|
||||||
let n = self.num() as i64;
|
let n = self.num() as i64;
|
||||||
let (n, overflowed) = (n << 7).overflowing_shr(7); // sign-extend the 57-bit signed fixnum.
|
let (n, overflowed) = (n << 8).overflowing_shr(8);
|
||||||
debug_assert_eq!(overflowed, false);
|
debug_assert_eq!(overflowed, false);
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
@@ -518,30 +531,34 @@ impl Neg for Fixnum {
|
|||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
Atom(Atom),
|
Atom(Atom),
|
||||||
Char(char),
|
Char(char),
|
||||||
|
CodeIndex(CodeIndex),
|
||||||
Fixnum(Fixnum),
|
Fixnum(Fixnum),
|
||||||
Integer(TypedArenaPtr<Integer>),
|
Integer(TypedArenaPtr<Integer>),
|
||||||
Rational(TypedArenaPtr<Rational>),
|
Rational(TypedArenaPtr<Rational>),
|
||||||
Float(F64Ptr),
|
Float(F64Offset),
|
||||||
String(Atom),
|
String(Atom),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<F64Ptr> for Literal {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(ptr: F64Ptr) -> Literal {
|
||||||
|
Literal::Float(ptr.as_offset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Literal {
|
impl fmt::Display for Literal {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Literal::Atom(ref atom) => {
|
Literal::Atom(ref atom) => {
|
||||||
// if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) {
|
|
||||||
// write!(f, "'{}'", atom)
|
|
||||||
// } else {
|
|
||||||
write!(f, "{}", atom.flat_index())
|
write!(f, "{}", atom.flat_index())
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
Literal::Char(c) => write!(f, "'{}'", *c as u32),
|
Literal::Char(c) => write!(f, "'{}'", *c as u32),
|
||||||
|
Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64),
|
||||||
Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
|
Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
|
||||||
Literal::Integer(ref n) => write!(f, "{}", n),
|
Literal::Integer(ref n) => write!(f, "{}", n),
|
||||||
Literal::Rational(ref n) => write!(f, "{}", n),
|
Literal::Rational(ref n) => write!(f, "{}", n),
|
||||||
Literal::Float(ref n) => write!(f, "{}", *n),
|
Literal::Float(ref n) => write!(f, "{}", *n),
|
||||||
Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
|
Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
|
||||||
// Literal::Usize(integer) => write!(f, "u{}", integer),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -561,7 +578,10 @@ pub enum Term {
|
|||||||
Clause(Cell<RegType>, Atom, Vec<Term>),
|
Clause(Cell<RegType>, Atom, Vec<Term>),
|
||||||
Cons(Cell<RegType>, Box<Term>, Box<Term>),
|
Cons(Cell<RegType>, Box<Term>, Box<Term>),
|
||||||
Literal(Cell<RegType>, Literal),
|
Literal(Cell<RegType>, Literal),
|
||||||
PartialString(Cell<RegType>, Atom, Option<Box<Term>>),
|
// PartialString wraps a String in anticipation of it absorbing
|
||||||
|
// other PartialString variants in as_partial_string.
|
||||||
|
PartialString(Cell<RegType>, String, Box<Term>),
|
||||||
|
CompleteString(Cell<RegType>, Atom),
|
||||||
Var(Cell<VarReg>, Rc<String>),
|
Var(Cell<VarReg>, Rc<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ impl<R> CharReader<R> {
|
|||||||
pub fn inner_mut(&mut self) -> &mut R {
|
pub fn inner_mut(&mut self) -> &mut R {
|
||||||
&mut self.inner
|
&mut self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the number of bytes remaining to be read. Useful for,
|
||||||
|
// e.g., determining the position relative to the end of the
|
||||||
|
// owning stream.
|
||||||
|
#[inline]
|
||||||
|
pub fn rem_buf_len(&self) -> usize {
|
||||||
|
self.buf.len() - self.pos
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CharRead {
|
pub trait CharRead {
|
||||||
@@ -96,7 +104,7 @@ impl<R> CharReader<R> {
|
|||||||
self.inner
|
self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_buffer(&mut self) {
|
pub fn reset_buffer(&mut self) {
|
||||||
self.buf.clear();
|
self.buf.clear();
|
||||||
self.pos = 0;
|
self.pos = 0;
|
||||||
}
|
}
|
||||||
@@ -246,33 +254,6 @@ impl<R: Read> CharRead for CharReader<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
impl<R: Seek> BufReader<R> {
|
|
||||||
/// Seeks relative to the current position. If the new position lies within the buffer,
|
|
||||||
/// the buffer will not be flushed, allowing for more efficient seeks.
|
|
||||||
/// This method does not return the location of the underlying reader, so the caller
|
|
||||||
/// must track this information themselves if it is required.
|
|
||||||
#[stable(feature = "bufreader_seek_relative", since = "1.53.0")]
|
|
||||||
pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
|
|
||||||
let pos = self.pos as u64;
|
|
||||||
if offset < 0 {
|
|
||||||
if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
|
|
||||||
self.pos = new_pos as usize;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if let Some(new_pos) = pos.checked_add(offset as u64) {
|
|
||||||
if new_pos <= self.cap as u64 {
|
|
||||||
self.pos = new_pos as usize;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.seek(SeekFrom::Current(offset)).map(drop)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
impl<R: Read> Read for CharReader<R> {
|
impl<R: Read> Read for CharReader<R> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
// // If we don't have any buffered data and we're doing a massive read
|
// // If we don't have any buffered data and we're doing a massive read
|
||||||
@@ -377,108 +358,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
impl<R: Seek> Seek for BufReader<R> {
|
|
||||||
/// Seek to an offset, in bytes, in the underlying reader.
|
|
||||||
///
|
|
||||||
/// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
|
|
||||||
/// position the underlying reader would be at if the `BufReader<R>` had no
|
|
||||||
/// internal buffer.
|
|
||||||
///
|
|
||||||
/// Seeking always discards the internal buffer, even if the seek position
|
|
||||||
/// would otherwise fall within it. This guarantees that calling
|
|
||||||
/// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader
|
|
||||||
/// at the same position.
|
|
||||||
///
|
|
||||||
/// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
|
|
||||||
///
|
|
||||||
/// See [`std::io::Seek`] for more details.
|
|
||||||
///
|
|
||||||
/// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
|
|
||||||
/// where `n` minus the internal buffer length overflows an `i64`, two
|
|
||||||
/// seeks will be performed instead of one. If the second seek returns
|
|
||||||
/// [`Err`], the underlying reader will be left at the same position it would
|
|
||||||
/// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
|
|
||||||
///
|
|
||||||
/// [`std::io::Seek`]: Seek
|
|
||||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
|
||||||
let result: u64;
|
|
||||||
if let SeekFrom::Current(n) = pos {
|
|
||||||
let remainder = (self.cap - self.pos) as i64;
|
|
||||||
// it should be safe to assume that remainder fits within an i64 as the alternative
|
|
||||||
// means we managed to allocate 8 exbibytes and that's absurd.
|
|
||||||
// But it's not out of the realm of possibility for some weird underlying reader to
|
|
||||||
// support seeking by i64::MIN so we need to handle underflow when subtracting
|
|
||||||
// remainder.
|
|
||||||
if let Some(offset) = n.checked_sub(remainder) {
|
|
||||||
result = self.inner.seek(SeekFrom::Current(offset))?;
|
|
||||||
} else {
|
|
||||||
// seek backwards by our remainder, and then by the offset
|
|
||||||
self.inner.seek(SeekFrom::Current(-remainder))?;
|
|
||||||
self.discard_buffer();
|
|
||||||
result = self.inner.seek(SeekFrom::Current(n))?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Seeking with Start/End doesn't care about our buffer length.
|
|
||||||
result = self.inner.seek(pos)?;
|
|
||||||
}
|
|
||||||
self.discard_buffer();
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current seek position from the start of the stream.
|
|
||||||
///
|
|
||||||
/// The value returned is equivalent to `self.seek(SeekFrom::Current(0))`
|
|
||||||
/// but does not flush the internal buffer. Due to this optimization the
|
|
||||||
/// function does not guarantee that calling `.into_inner()` immediately
|
|
||||||
/// afterwards will yield the underlying reader at the same position. Use
|
|
||||||
/// [`BufReader::seek`] instead if you require that guarantee.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// This function will panic if the position of the inner reader is smaller
|
|
||||||
/// than the amount of buffered data. That can happen if the inner reader
|
|
||||||
/// has an incorrect implementation of [`Seek::stream_position`], or if the
|
|
||||||
/// position has gone out of sync due to calling [`Seek::seek`] directly on
|
|
||||||
/// the underlying reader.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// use std::{
|
|
||||||
/// io::{self, BufRead, BufReader, Seek},
|
|
||||||
/// fs::File,
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// fn main() -> io::Result<()> {
|
|
||||||
/// let mut f = BufReader::new(File::open("foo.txt")?);
|
|
||||||
///
|
|
||||||
/// let before = f.stream_position()?;
|
|
||||||
/// f.read_line(&mut String::new())?;
|
|
||||||
/// let after = f.stream_position()?;
|
|
||||||
///
|
|
||||||
/// println!("The first line was {} bytes long", after - before);
|
|
||||||
/// Ok(())
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
fn stream_position(&mut self) -> io::Result<u64> {
|
|
||||||
let remainder = (self.cap - self.pos) as u64;
|
|
||||||
self.inner.stream_position().map(|pos| {
|
|
||||||
pos.checked_sub(remainder).expect(
|
|
||||||
"overflow when subtracting remaining buffer size from inner stream position",
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
impl<T> SizeHint for CharReader<T> {
|
|
||||||
fn lower_bound(&self) -> usize {
|
|
||||||
self.buffer().len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use lexical::parse_lossy;
|
use lexical::parse_lossy;
|
||||||
use ordered_float::*;
|
|
||||||
|
|
||||||
|
use crate::arena::ArenaAllocated;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
pub use crate::machine::machine_state::*;
|
pub use crate::machine::machine_state::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
@@ -367,7 +367,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
if hexadecimal_digit_char!(c) {
|
if hexadecimal_digit_char!(c) {
|
||||||
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
|
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
Err(ParserError::IncompleteReduction(self.line_num, self.col_num))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,11 +400,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// on failure, restore the token characters and backslash.
|
Err(ParserError::IncompleteReduction(self.line_num, self.col_num))
|
||||||
// self.reader.put_back_all(token.chars().map(Ok));
|
|
||||||
// self.reader.put_back(Ok('\\'));
|
|
||||||
|
|
||||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,12 +633,8 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
|
|
||||||
fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> {
|
fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> {
|
||||||
self.return_char(token.pop().unwrap());
|
self.return_char(token.pop().unwrap());
|
||||||
|
let n = parse_lossy::<f64, _>(token.as_bytes())?;
|
||||||
let result = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?);
|
Ok(Token::Literal(Literal::from(float_alloc!(n, self.machine_st.arena))))
|
||||||
Ok(Token::Literal(Literal::Float(arena_alloc!(
|
|
||||||
result,
|
|
||||||
&mut self.machine_st.arena
|
|
||||||
))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
|
fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
|
||||||
@@ -752,20 +744,18 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let n = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?);
|
let n = parse_lossy::<f64, _>(token.as_bytes())?;
|
||||||
Ok(Token::Literal(Literal::Float(arena_alloc!(
|
Ok(Token::Literal(Literal::from(
|
||||||
n,
|
float_alloc!(n, self.machine_st.arena)
|
||||||
&mut self.machine_st.arena
|
)))
|
||||||
))))
|
|
||||||
} else {
|
} else {
|
||||||
return Ok(self.vacate_with_float(token)?);
|
return Ok(self.vacate_with_float(token)?);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let n = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?);
|
let n = parse_lossy::<f64, _>(token.as_bytes())?;
|
||||||
Ok(Token::Literal(Literal::Float(arena_alloc!(
|
Ok(Token::Literal(Literal::from(
|
||||||
n,
|
float_alloc!(n, self.machine_st.arena)
|
||||||
&mut self.machine_st.arena
|
)))
|
||||||
))))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.return_char('.');
|
self.return_char('.');
|
||||||
|
|||||||
@@ -7,28 +7,7 @@ macro_rules! char_class {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! alpha_char {
|
macro_rules! alpha_char {
|
||||||
($c: expr) => {
|
($c: expr) => {
|
||||||
match $c {
|
$c.is_alphabetic() || $c == '_'
|
||||||
'a'..='z' => true,
|
|
||||||
'A'..='Z' => true,
|
|
||||||
'_' => true,
|
|
||||||
'\u{00A0}'..='\u{00BF}' => true,
|
|
||||||
'\u{00C0}'..='\u{00D6}' => true,
|
|
||||||
'\u{00D8}'..='\u{00F6}' => true,
|
|
||||||
'\u{00F8}'..='\u{00FF}' => true,
|
|
||||||
'\u{0100}'..='\u{017F}' => true, // Latin Extended-A
|
|
||||||
'\u{0180}'..='\u{024F}' => true, // Latin Extended-B
|
|
||||||
'\u{0250}'..='\u{02AF}' => true, // IPA Extensions
|
|
||||||
'\u{02B0}'..='\u{02FF}' => true, // Spacing Modifier Letters
|
|
||||||
'\u{0300}'..='\u{036F}' => true, // Combining Diacritical Marks
|
|
||||||
'\u{0370}'..='\u{03FF}' => true, // Greek/Coptic
|
|
||||||
'\u{0400}'..='\u{04FF}' => true, // Cyrillic
|
|
||||||
'\u{0500}'..='\u{052F}' => true, // Cyrillic Supplement
|
|
||||||
'\u{0530}'..='\u{058F}' => true, // Armenian
|
|
||||||
'\u{0590}'..='\u{05FF}' => true, // Hebrew
|
|
||||||
'\u{0600}'..='\u{06FF}' => true, // Arabic
|
|
||||||
'\u{0700}'..='\u{074F}' => true, // Syriac
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +42,7 @@ macro_rules! octet_char {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! capital_letter_char {
|
macro_rules! capital_letter_char {
|
||||||
($c: expr) => {
|
($c: expr) => {
|
||||||
('A'..='Z').contains(&$c)
|
$c.is_uppercase()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +153,7 @@ macro_rules! octal_digit_char {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! binary_digit_char {
|
macro_rules! binary_digit_char {
|
||||||
($c: expr) => {
|
($c: expr) => {
|
||||||
$c >= '0' && $c <= '1'
|
$c == '0' || $c == '1'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +192,7 @@ macro_rules! single_quote_char {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! small_letter_char {
|
macro_rules! small_letter_char {
|
||||||
($c: expr) => {
|
($c: expr) => {
|
||||||
('a'..='z').contains(&$c)
|
$c.is_alphabetic() && !$c.is_uppercase()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#[cfg(feature = "num-rug-adapter")]
|
#[cfg(feature = "num-rug-adapter")]
|
||||||
use num_rug_adapter as rug;
|
pub use num_rug_adapter as rug;
|
||||||
|
|
||||||
#[cfg(feature = "rug")]
|
#[cfg(feature = "rug")]
|
||||||
pub use rug;
|
pub use rug;
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ use crate::parser::ast::*;
|
|||||||
use crate::parser::char_reader::*;
|
use crate::parser::char_reader::*;
|
||||||
use crate::parser::lexer::*;
|
use crate::parser::lexer::*;
|
||||||
|
|
||||||
use ordered_float::OrderedFloat;
|
use crate::parser::rug::ops::NegAssign;
|
||||||
|
|
||||||
use rug::ops::NegAssign;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -51,11 +49,10 @@ struct TokenDesc {
|
|||||||
spec: u32,
|
spec: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_partial_string(
|
pub(crate) fn as_partial_string(
|
||||||
head: Term,
|
head: Term,
|
||||||
mut tail: Term,
|
mut tail: Term,
|
||||||
atom_tbl: &mut AtomTable,
|
) -> Result<(String, Option<Box<Term>>), Term> {
|
||||||
) -> Result<(Atom, Option<Box<Term>>), Term> {
|
|
||||||
let mut string = match &head {
|
let mut string = match &head {
|
||||||
Term::Literal(_, Literal::Atom(atom)) => {
|
Term::Literal(_, Literal::Atom(atom)) => {
|
||||||
if let Some(c) = atom.as_char() {
|
if let Some(c) = atom.as_char() {
|
||||||
@@ -94,6 +91,15 @@ fn is_partial_string(
|
|||||||
|
|
||||||
tail_ref = succ;
|
tail_ref = succ;
|
||||||
}
|
}
|
||||||
|
Term::PartialString(_, pstr, tail) => {
|
||||||
|
string += &pstr;
|
||||||
|
tail_ref = tail;
|
||||||
|
}
|
||||||
|
Term::CompleteString(_, cstr) => {
|
||||||
|
string += cstr.as_str();
|
||||||
|
tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
|
||||||
|
break;
|
||||||
|
}
|
||||||
tail_ref => {
|
tail_ref => {
|
||||||
tail = mem::replace(tail_ref, Term::AnonVar);
|
tail = mem::replace(tail_ref, Term::AnonVar);
|
||||||
break;
|
break;
|
||||||
@@ -103,21 +109,17 @@ fn is_partial_string(
|
|||||||
|
|
||||||
match &tail {
|
match &tail {
|
||||||
Term::AnonVar | Term::Var(..) => {
|
Term::AnonVar | Term::Var(..) => {
|
||||||
let pstr_atom = atom_tbl.build_with(&string);
|
Ok((string, Some(Box::new(tail))))
|
||||||
Ok((pstr_atom, Some(Box::new(tail))))
|
|
||||||
}
|
}
|
||||||
Term::Literal(_, Literal::Atom(atom!("[]"))) => {
|
Term::Literal(_, Literal::Atom(atom!("[]"))) => {
|
||||||
let pstr_atom = atom_tbl.build_with(&string);
|
Ok((string, None))
|
||||||
Ok((pstr_atom, None))
|
|
||||||
}
|
}
|
||||||
Term::Literal(_, Literal::String(tail)) => {
|
Term::Literal(_, Literal::String(tail)) => {
|
||||||
string += tail.as_str();
|
string += tail.as_str();
|
||||||
let pstr_atom = atom_tbl.build_with(&string);
|
Ok((string, None))
|
||||||
Ok((pstr_atom, None))
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let pstr_atom = atom_tbl.build_with(&string);
|
Ok((string, Some(Box::new(tail))))
|
||||||
Ok((pstr_atom, Some(Box::new(tail))))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -414,7 +416,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
TokenType::Term
|
TokenType::Term
|
||||||
}
|
}
|
||||||
Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_chars() => {
|
Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_chars() => {
|
||||||
self.terms.push(Term::PartialString(Cell::default(), s, None));
|
self.terms.push(Term::CompleteString(Cell::default(), s));
|
||||||
TokenType::Term
|
TokenType::Term
|
||||||
}
|
}
|
||||||
Token::Literal(c) => {
|
Token::Literal(c) => {
|
||||||
@@ -566,24 +568,19 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
let head = subterms.pop().unwrap();
|
let head = subterms.pop().unwrap();
|
||||||
|
|
||||||
self.terms.push(
|
self.terms.push(
|
||||||
match is_partial_string(head, tail, &mut self.lexer.machine_st.atom_tbl) {
|
match as_partial_string(head, tail) {
|
||||||
Ok((string_buf, tail_opt)) => {
|
Ok((string_buf, Some(tail))) => {
|
||||||
Term::PartialString(Cell::default(), string_buf, tail_opt)
|
Term::PartialString(Cell::default(), string_buf, tail)
|
||||||
|
}
|
||||||
|
Ok((string_buf, None)) => {
|
||||||
|
let atom = self.lexer.machine_st.atom_tbl.build_with(&string_buf);
|
||||||
|
Term::CompleteString(Cell::default(), atom)
|
||||||
}
|
}
|
||||||
Err(term) => term,
|
Err(term) => term,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
|
||||||
self.terms.push(Term::Cons(
|
|
||||||
Cell::default(),
|
|
||||||
Box::new(head),
|
|
||||||
Box::new(tail),
|
|
||||||
));
|
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
self.terms
|
self.terms.push(Term::Clause(Cell::default(), name, subterms));
|
||||||
.push(Term::Clause(Cell::default(), name, subterms));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(&mut TokenDesc {
|
if let Some(&mut TokenDesc {
|
||||||
@@ -743,9 +740,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
|
|
||||||
self.terms.push(match list {
|
self.terms.push(match list {
|
||||||
Term::Cons(_, head, tail) => {
|
Term::Cons(_, head, tail) => {
|
||||||
match is_partial_string(*head, *tail, &mut self.lexer.machine_st.atom_tbl) {
|
match as_partial_string(*head, *tail) {
|
||||||
Ok((string_buf, tail_opt)) => {
|
Ok((string_buf, Some(tail))) => {
|
||||||
Term::PartialString(Cell::default(), string_buf, tail_opt)
|
Term::PartialString(Cell::default(), string_buf, tail)
|
||||||
|
}
|
||||||
|
Ok((string_buf, None)) => {
|
||||||
|
let atom = self.lexer.machine_st.atom_tbl.build_with(&string_buf);
|
||||||
|
Term::CompleteString(Cell::default(), atom)
|
||||||
}
|
}
|
||||||
Err(term) => term,
|
Err(term) => term,
|
||||||
}
|
}
|
||||||
@@ -823,13 +824,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
|
|
||||||
self.reduce_op(1400);
|
self.reduce_op(1400);
|
||||||
|
|
||||||
if self.stack.len() == 1 {
|
if self.stack.len() <= 1 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let idx = self.stack.len() - 2;
|
let idx = self.stack.len() - 2;
|
||||||
|
|
||||||
let td = self.stack.remove(idx);
|
let td = self.stack.remove(idx);
|
||||||
|
|
||||||
match td.tt {
|
match td.tt {
|
||||||
TokenType::Open | TokenType::OpenCT => {
|
TokenType::Open | TokenType::OpenCT => {
|
||||||
if self.stack[idx].tt == TokenType::Comma {
|
if self.stack[idx].tt == TokenType::Comma {
|
||||||
@@ -948,9 +949,9 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
self.negate_number(n, negate_rc, |r, _| Literal::Rational(r))
|
self.negate_number(n, negate_rc, |r, _| Literal::Rational(r))
|
||||||
}
|
}
|
||||||
Token::Literal(Literal::Float(n)) => self.negate_number(
|
Token::Literal(Literal::Float(n)) => self.negate_number(
|
||||||
**n,
|
**n.as_ptr(),
|
||||||
|n| OrderedFloat(-n.into_inner()),
|
|n| -n,
|
||||||
|n, arena| Literal::Float(arena_alloc!(n, arena)),
|
|n, arena| Literal::from(float_alloc!(n, arena)),
|
||||||
),
|
),
|
||||||
Token::Literal(c) => {
|
Token::Literal(c) => {
|
||||||
if let Some(name) = atomize_constant(&mut self.lexer.machine_st.atom_tbl, c) {
|
if let Some(name) = atomize_constant(&mut self.lexer.machine_st.atom_tbl, c) {
|
||||||
|
|||||||
@@ -58,13 +58,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
#[inline]
|
|
||||||
pub fn take(&mut self) -> Self {
|
|
||||||
mem::replace(self, Self::empty_block())
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
self.top as usize - self.base as usize
|
self.top as usize - self.base as usize
|
||||||
|
|||||||
80
src/read.rs
80
src/read.rs
@@ -1,29 +1,29 @@
|
|||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::parser::parser::*;
|
use crate::parser::parser::*;
|
||||||
|
|
||||||
use crate::arena::*;
|
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::iterators::*;
|
use crate::iterators::*;
|
||||||
use crate::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
|
use crate::machine::machine_errors::*;
|
||||||
use crate::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::machine::machine_state::MachineState;
|
use crate::machine::machine_state::MachineState;
|
||||||
use crate::machine::streams::*;
|
use crate::machine::streams::*;
|
||||||
use crate::parser::char_reader::*;
|
use crate::parser::char_reader::*;
|
||||||
|
use crate::repl_helper::Helper;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use fxhash::FxBuildHasher;
|
use fxhash::FxBuildHasher;
|
||||||
|
|
||||||
|
use indexmap::IndexSet;
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use rustyline::{Cmd, Config, Editor, KeyEvent};
|
use rustyline::{Config, Editor};
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io::{Cursor, Error, ErrorKind, Read};
|
use std::io::{Cursor, Error, ErrorKind, Read};
|
||||||
|
|
||||||
type SubtermDeque = VecDeque<(usize, usize)>;
|
type SubtermDeque = VecDeque<(usize, usize)>;
|
||||||
|
|
||||||
// pub(crate) type PrologStream = ParsingStream<Stream>;
|
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
pub(crate) fn devour_whitespace(
|
pub(crate) fn devour_whitespace(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -41,19 +41,21 @@ impl MachineState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
mut inner: Stream,
|
mut inner: Stream,
|
||||||
op_dir: &OpDir,
|
op_dir: &OpDir,
|
||||||
) -> Result<TermWriteResult, ParserError> {
|
) -> Result<TermWriteResult, CompilationError> {
|
||||||
let (term, num_lines_read) = {
|
let (term, num_lines_read) = {
|
||||||
let prior_num_lines_read = inner.lines_read();
|
let prior_num_lines_read = inner.lines_read();
|
||||||
let mut parser = Parser::new(inner, self);
|
let mut parser = Parser::new(inner, self);
|
||||||
|
|
||||||
parser.add_lines_read(prior_num_lines_read);
|
parser.add_lines_read(prior_num_lines_read);
|
||||||
|
|
||||||
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
|
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))
|
||||||
|
.map_err(CompilationError::from)?;
|
||||||
|
|
||||||
(term, parser.lines_read() - prior_num_lines_read)
|
(term, parser.lines_read() - prior_num_lines_read)
|
||||||
};
|
};
|
||||||
|
|
||||||
inner.add_lines_read(num_lines_read);
|
inner.add_lines_read(num_lines_read);
|
||||||
Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl))
|
write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,23 +80,21 @@ fn get_prompt() -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn input_stream(arena: &mut Arena) -> Stream {
|
|
||||||
let input_stream = ReadlineStream::new("");
|
|
||||||
Stream::from_readline_stream(input_stream, arena)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ReadlineStream {
|
pub struct ReadlineStream {
|
||||||
rl: Editor<()>,
|
rl: Editor<Helper>,
|
||||||
pending_input: Cursor<String>,
|
pending_input: Cursor<String>,
|
||||||
|
add_history: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadlineStream {
|
impl ReadlineStream {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(pending_input: &str) -> Self {
|
pub fn new(pending_input: &str, add_history: bool) -> Self {
|
||||||
let config = Config::builder().check_cursor_position(true).build();
|
let config = Config::builder().check_cursor_position(true).build();
|
||||||
let mut rl = Editor::<()>::with_config(config);
|
let helper = Helper::new();
|
||||||
|
|
||||||
|
let mut rl = Editor::with_config(config);
|
||||||
|
rl.set_helper(Some(helper));
|
||||||
|
|
||||||
if let Some(mut path) = dirs_next::home_dir() {
|
if let Some(mut path) = dirs_next::home_dir() {
|
||||||
path.push(HISTORY_FILE);
|
path.push(HISTORY_FILE);
|
||||||
@@ -103,14 +103,20 @@ impl ReadlineStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
|
// rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
|
||||||
|
|
||||||
ReadlineStream {
|
ReadlineStream {
|
||||||
rl,
|
rl,
|
||||||
pending_input: Cursor::new(pending_input.to_owned()),
|
pending_input: Cursor::new(pending_input.to_owned()),
|
||||||
|
add_history: add_history,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_atoms_for_completion(&mut self, atoms: *const IndexSet<Atom>) {
|
||||||
|
let helper = self.rl.helper_mut().unwrap();
|
||||||
|
helper.atoms = atoms;
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.pending_input.get_mut().clear();
|
self.pending_input.get_mut().clear();
|
||||||
@@ -143,6 +149,9 @@ impl ReadlineStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn save_history(&mut self) {
|
fn save_history(&mut self) {
|
||||||
|
if !self.add_history {
|
||||||
|
return;
|
||||||
|
};
|
||||||
if let Some(mut path) = dirs_next::home_dir() {
|
if let Some(mut path) = dirs_next::home_dir() {
|
||||||
path.push(HISTORY_FILE);
|
path.push(HISTORY_FILE);
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
@@ -239,7 +248,7 @@ pub(crate) fn write_term_to_heap(
|
|||||||
term: &Term,
|
term: &Term,
|
||||||
heap: &mut Heap,
|
heap: &mut Heap,
|
||||||
atom_tbl: &mut AtomTable,
|
atom_tbl: &mut AtomTable,
|
||||||
) -> TermWriteResult {
|
) -> Result<TermWriteResult, CompilationError> {
|
||||||
let term_writer = TermWriter::new(heap, atom_tbl);
|
let term_writer = TermWriter::new(heap, atom_tbl);
|
||||||
term_writer.write_term_to_heap(term)
|
term_writer.write_term_to_heap(term)
|
||||||
}
|
}
|
||||||
@@ -290,7 +299,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
match term {
|
match term {
|
||||||
&TermRef::Cons(..) => list_loc_as_cell!(h),
|
&TermRef::Cons(..) => list_loc_as_cell!(h),
|
||||||
&TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
|
&TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
|
||||||
&TermRef::PartialString(_, _, ref src, None) =>
|
&TermRef::CompleteString(_, _, ref src) =>
|
||||||
if src.as_str().is_empty() {
|
if src.as_str().is_empty() {
|
||||||
empty_list_as_cell!()
|
empty_list_as_cell!()
|
||||||
} else if self.heap[h].get_tag() == HeapCellValueTag::CStr {
|
} else if self.heap[h].get_tag() == HeapCellValueTag::CStr {
|
||||||
@@ -305,7 +314,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult {
|
fn write_term_to_heap(mut self, term: &'a Term) -> Result<TermWriteResult, CompilationError> {
|
||||||
let heap_loc = self.heap.len();
|
let heap_loc = self.heap.len();
|
||||||
|
|
||||||
for term in breadth_first_iter(term, true) {
|
for term in breadth_first_iter(term, true) {
|
||||||
@@ -327,7 +336,11 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
self.push_stub_addr();
|
self.push_stub_addr();
|
||||||
self.push_stub_addr();
|
self.push_stub_addr();
|
||||||
}
|
}
|
||||||
&TermRef::Clause(Level::Root, _, ref ct, subterms) => {
|
&TermRef::Clause(Level::Root, _, name, subterms) => {
|
||||||
|
if subterms.len() > MAX_ARITY {
|
||||||
|
return Err(CompilationError::ExceededMaxArity);
|
||||||
|
}
|
||||||
|
|
||||||
self.heap.push(if subterms.len() == 0 {
|
self.heap.push(if subterms.len() == 0 {
|
||||||
heap_loc_as_cell!(heap_loc + 1)
|
heap_loc_as_cell!(heap_loc + 1)
|
||||||
} else {
|
} else {
|
||||||
@@ -335,7 +348,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
self.queue.push_back((subterms.len(), h + 2));
|
self.queue.push_back((subterms.len(), h + 2));
|
||||||
let named = atom_as_cell!(ct.name(), subterms.len());
|
let named = atom_as_cell!(name, subterms.len());
|
||||||
|
|
||||||
self.heap.push(named);
|
self.heap.push(named);
|
||||||
|
|
||||||
@@ -345,9 +358,9 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
&TermRef::Clause(_, _, ref ct, subterms) => {
|
&TermRef::Clause(_, _, name, subterms) => {
|
||||||
self.queue.push_back((subterms.len(), h + 1));
|
self.queue.push_back((subterms.len(), h + 1));
|
||||||
let named = atom_as_cell!(ct.name(), subterms.len());
|
let named = atom_as_cell!(name, subterms.len());
|
||||||
|
|
||||||
self.heap.push(named);
|
self.heap.push(named);
|
||||||
|
|
||||||
@@ -373,14 +386,18 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
&TermRef::PartialString(lvl, _, ref src, tail) => {
|
&TermRef::CompleteString(_, _, ref src) => {
|
||||||
if tail.is_some() {
|
|
||||||
allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
|
|
||||||
} else {
|
|
||||||
put_complete_string(self.heap, src.as_str(), self.atom_tbl);
|
put_complete_string(self.heap, src.as_str(), self.atom_tbl);
|
||||||
}
|
}
|
||||||
|
&TermRef::PartialString(lvl, _, ref src, _) => {
|
||||||
|
if let Level::Root = lvl {
|
||||||
|
// Var tags can't refer directly to partial strings,
|
||||||
|
// so a PStrLoc cell must be pushed.
|
||||||
|
self.heap.push(pstr_loc_as_cell!(heap_loc + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
|
||||||
|
|
||||||
if tail.is_some() {
|
|
||||||
let h = self.heap.len();
|
let h = self.heap.len();
|
||||||
self.queue.push_back((1, h - 1));
|
self.queue.push_back((1, h - 1));
|
||||||
|
|
||||||
@@ -388,7 +405,6 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
&TermRef::Var(_, _, ref var) => {
|
&TermRef::Var(_, _, ref var) => {
|
||||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||||
if let Some(addr) = self.var_dict.get(var).cloned() {
|
if let Some(addr) = self.var_dict.get(var).cloned() {
|
||||||
@@ -410,9 +426,9 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
self.modify_head_of_queue(&term, h);
|
self.modify_head_of_queue(&term, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
TermWriteResult {
|
Ok(TermWriteResult {
|
||||||
heap_loc,
|
heap_loc,
|
||||||
var_dict: self.var_dict,
|
var_dict: self.var_dict,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
110
src/repl_helper.rs
Normal file
110
src/repl_helper.rs
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
use indexmap::IndexSet;
|
||||||
|
use rustyline::completion::{Completer, Candidate};
|
||||||
|
use rustyline::hint::Hinter;
|
||||||
|
use rustyline::validate::Validator;
|
||||||
|
use rustyline::highlight::{MatchingBracketHighlighter, Highlighter};
|
||||||
|
use rustyline::{Helper as RlHelper, Result, Context};
|
||||||
|
|
||||||
|
use crate::atom_table::{Atom, STATIC_ATOMS_MAP};
|
||||||
|
|
||||||
|
// TODO: Maybe add validation to the helper
|
||||||
|
pub struct Helper {
|
||||||
|
highligher: MatchingBracketHighlighter,
|
||||||
|
pub atoms: *const IndexSet<Atom>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Helper {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
highligher: MatchingBracketHighlighter::new(),
|
||||||
|
atoms: std::ptr::null(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RlHelper for Helper {}
|
||||||
|
|
||||||
|
fn get_prefix(line: &str, pos: usize) -> Option<usize> {
|
||||||
|
let mut start_of_atom = None;
|
||||||
|
let mut first_letter = true;
|
||||||
|
|
||||||
|
for (i, char) in line.chars().enumerate() {
|
||||||
|
if first_letter {
|
||||||
|
if char.is_alphabetic() && char.is_lowercase() {
|
||||||
|
start_of_atom = Some(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
first_letter = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !char.is_alphanumeric() && char != '_' {
|
||||||
|
first_letter = true;
|
||||||
|
start_of_atom = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == pos {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if first_letter || pos == 0 {
|
||||||
|
start_of_atom = Some(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
start_of_atom
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StrPtr(*const str);
|
||||||
|
|
||||||
|
impl Candidate for StrPtr {
|
||||||
|
fn display(&self) -> &str {
|
||||||
|
unsafe {
|
||||||
|
self.0.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replacement(&self) -> &str {
|
||||||
|
unsafe {
|
||||||
|
self.0.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Completer for Helper {
|
||||||
|
type Candidate = StrPtr;
|
||||||
|
|
||||||
|
fn complete(&self, line: &str, pos: usize, _ctx: &Context<'_>) -> Result<(usize, Vec<Self::Candidate>)> {
|
||||||
|
let start_of_prefix = get_prefix(line, pos);
|
||||||
|
if let Some(idx) = start_of_prefix {
|
||||||
|
let sub_str = line.get(idx..pos).unwrap();
|
||||||
|
Ok((idx, unsafe {
|
||||||
|
let mut matching = (*self.atoms).iter()
|
||||||
|
.chain(STATIC_ATOMS_MAP.values())
|
||||||
|
.filter(|a| a.as_str().starts_with(sub_str))
|
||||||
|
.map(|s| StrPtr(s.as_str()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
matching.sort_unstable_by(|a, b| Ord::cmp(&(*a.0).len(), &(*b.0).len()));
|
||||||
|
matching
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Ok((0, vec![]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Highlighter for Helper {
|
||||||
|
fn highlight<'l>(&self, line: &'l str, pos: usize) -> std::borrow::Cow<'l, str> {
|
||||||
|
self.highligher.highlight(line, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight_char(&self, line: &str, pos: usize) -> bool {
|
||||||
|
self.highligher.highlight_char(line, pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Validator for Helper {}
|
||||||
|
|
||||||
|
impl Hinter for Helper {
|
||||||
|
type Hint = String;
|
||||||
|
}
|
||||||
@@ -100,7 +100,7 @@ run :-
|
|||||||
Dss
|
Dss
|
||||||
),
|
),
|
||||||
E,
|
E,
|
||||||
( write('caught: '), write(E), nl,
|
( loader:write_error(E), nl,
|
||||||
portray_clause([N, Settings, Vs, Gs4, Dss]), nl,
|
portray_clause([N, Settings, Vs, Gs4, Dss]), nl,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ test_queries_on_setup_call_cleanup :-
|
|||||||
catch(setup_call_cleanup(X=throw(ex), true, X), ex, true),
|
catch(setup_call_cleanup(X=throw(ex), true, X), ex, true),
|
||||||
findall([S,G,C], setup_call_cleanup(S = 1, G = 2, C = 3), [[1,2,3]]),
|
findall([S,G,C], setup_call_cleanup(S = 1, G = 2, C = 3), [[1,2,3]]),
|
||||||
findall([S,G,C], setup_call_cleanup((S=1;S=2), G=3, C=4), [[1,3,4]]),
|
findall([S,G,C], setup_call_cleanup((S=1;S=2), G=3, C=4), [[1,3,4]]),
|
||||||
findall([S,G], setup_call_cleanup(S=1, G=2, writeq(S+G)), [[1,2]]),
|
findall([S,G], setup_call_cleanup(S=1, G=2, write_term(S+G, [variable_names(['S'=S,'G'=G])])), [[1,2]]),
|
||||||
findall([S,G], setup_call_cleanup(S=1, (G=2;G=3), writeq(S+G)), [[1,2],[1,3]]),
|
findall([S,G], setup_call_cleanup(S=1, (G=2;G=3), write_term(S+G, [variable_names(['S'=S,'G'=G])])), [[1,2],[1,3]]),
|
||||||
findall([S,G], (setup_call_cleanup(S=1, G=2, writeq(S+G>A+B)), A = 3, B = 4), [[1,2]]),
|
findall([S,G], (setup_call_cleanup(S=1, G=2, write_term(S+G>A+B, [variable_names(['S'=S,'G'=G,'A'=A,'B'=B])])), A = 3, B = 4), [[1,2]]),
|
||||||
findall([S,G,E], catch(setup_call_cleanup(S=1, (G=2;G=3,throw(x)), writeq(S+G)), E, true), [[1,2,_],[_,_,x]]),
|
findall([S,G,E], catch(setup_call_cleanup(S=1, (G=2;G=3,throw(x)), write_term(S+G, [variable_names(['S'=S,'G'=G])])), E, true), [[1,2,_],[_,_,x]]),
|
||||||
findall([S,B,G], (setup_call_cleanup(S=1, (G=2;G=3),writeq(S+G>B)), B=4, !), [[1,4,2]]),
|
findall([S,B,G], (setup_call_cleanup(S=1, (G=2;G=3),write_term(S+G>B, [variable_names(['S'=S,'G'=G,'B'=B])])), B=4, !), [[1,4,2]]),
|
||||||
findall([S,G,B], (setup_call_cleanup(S=1,G=2,writeq(S+G>B)),B=3,!), [[1,2,3]]),
|
findall([S,G,B], (setup_call_cleanup(S=1,G=2,write_term(S+G>B, [variable_names(['S'=S,'G'=G,'B'=B])])),B=3,!), [[1,2,3]]),
|
||||||
findall([S,G,B], (setup_call_cleanup(S=1,(G=2;false),writeq(S+G>B)),B=3,!), [[1,2,3]]),
|
findall([S,G,B], (setup_call_cleanup(S=1,(G=2;false),write_term(S+G>B, [variable_names(['S'=S,'G'=G,'B'=B])])),B=3,!), [[1,2,3]]),
|
||||||
findall([S,G,B], (setup_call_cleanup(S=1,(G=2;S=2),writeq(S+G>B)), B=3, !), [[1,2,3]]),
|
findall([S,G,B], (setup_call_cleanup(S=1,(G=2;S=2),write_term(S+G>B, [variable_names(['S'=S,'G'=G,'B'=B])])), B=3, !), [[1,2,3]]),
|
||||||
catch((setup_call_cleanup(S=1,(G=2;G=3), writeq(S+G>B)), B=4, !, throw(x)), x, true),
|
catch((setup_call_cleanup(S=1,(G=2;G=3), write_term(S+G>B, [variable_names(['S'=S,'G'=G,'B'=B])])), B=4, !, throw(x)), x, true),
|
||||||
findall(Pat, catch(setup_call_cleanup(true,throw(goal),throw(cl)), Pat, true), [goal]),
|
findall(Pat, catch(setup_call_cleanup(true,throw(goal),throw(cl)), Pat, true), [goal]),
|
||||||
findall(Pat, catch(( setup_call_cleanup(true,(G=1;G=2),throw(cl)), throw(cont)), Pat, true), [cont]),
|
findall(Pat, catch(( setup_call_cleanup(true,(G=1;G=2),throw(cl)), throw(cont)), Pat, true), [cont]),
|
||||||
findall([X,Y], (setup_call_cleanup(true, (X=1;X=2), writeq(a)), setup_call_cleanup(true,(Y=1;Y=2),writeq(b)), !), [[1,1]]).
|
findall([X,Y], (setup_call_cleanup(true, (X=1;X=2), writeq(a)), setup_call_cleanup(true,(Y=1;Y=2),writeq(b)), !), [[1,1]]).
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ delegate_task([Arg0|Args], Goals0) :-
|
|||||||
; member(Arg0, ["-v", "--version"]) -> print_version
|
; member(Arg0, ["-v", "--version"]) -> print_version
|
||||||
; member(Arg0, ["-g", "--goal"]) -> gather_goal(g, Args, Goals0)
|
; member(Arg0, ["-g", "--goal"]) -> gather_goal(g, Args, Goals0)
|
||||||
; member(Arg0, ["-f"]) -> disable_init_file
|
; member(Arg0, ["-f"]) -> disable_init_file
|
||||||
|
; member(Arg0, ["--no-add-history"]) -> ignore_machine_arg
|
||||||
; atom_chars(Mod, Arg0),
|
; atom_chars(Mod, Arg0),
|
||||||
catch(consult(Mod), E, print_exception(E))
|
catch(consult(Mod), E, print_exception(E))
|
||||||
),
|
),
|
||||||
@@ -73,7 +74,9 @@ print_help :-
|
|||||||
write(' -g, --goal GOAL '),
|
write(' -g, --goal GOAL '),
|
||||||
write('Run the query GOAL'), nl,
|
write('Run the query GOAL'), nl,
|
||||||
write(' -f '),
|
write(' -f '),
|
||||||
write('Fast startup. Do not load initialization file (~/.scryerrc)'),nl,
|
write('Fast startup. Do not load initialization file (~/.scryerrc)'), nl,
|
||||||
|
write(' --no-add-history '),
|
||||||
|
write('Prevent adding input to history file (~/.scryer_history)'), nl,
|
||||||
% write(' '),
|
% write(' '),
|
||||||
halt.
|
halt.
|
||||||
|
|
||||||
@@ -94,6 +97,8 @@ gather_goal(Type, Args0, Goals) :-
|
|||||||
disable_init_file :-
|
disable_init_file :-
|
||||||
asserta('disabled_init_file').
|
asserta('disabled_init_file').
|
||||||
|
|
||||||
|
ignore_machine_arg.
|
||||||
|
|
||||||
arg_type(g).
|
arg_type(g).
|
||||||
arg_type(t).
|
arg_type(t).
|
||||||
arg_type(g(_)).
|
arg_type(g(_)).
|
||||||
@@ -124,8 +129,8 @@ run_goals([g(Gs0)|Goals]) :-
|
|||||||
),
|
),
|
||||||
run_goals(Goals).
|
run_goals(Goals).
|
||||||
run_goals([Goal|_]) :-
|
run_goals([Goal|_]) :-
|
||||||
write('caught: '),
|
loader:write_error(error(domain_error(arg_type, Goal), run_goals/1)),
|
||||||
write(error(domain_error(arg_type, Goal), run_goals/1)), nl,
|
nl,
|
||||||
halt.
|
halt.
|
||||||
|
|
||||||
repl :-
|
repl :-
|
||||||
@@ -175,23 +180,26 @@ submit_query_and_print_results_(Term, VarList) :-
|
|||||||
'$get_b_value'(B),
|
'$get_b_value'(B),
|
||||||
bb_put('$report_all', false),
|
bb_put('$report_all', false),
|
||||||
bb_put('$report_n_more', 0),
|
bb_put('$report_n_more', 0),
|
||||||
'$call'(Term),
|
call(user:Term),
|
||||||
write_eqs_and_read_input(B, VarList),
|
write_eqs_and_read_input(B, VarList),
|
||||||
!.
|
!.
|
||||||
submit_query_and_print_results_(_, _) :-
|
submit_query_and_print_results_(_, _) :-
|
||||||
|
( bb_get('$answer_count', 0) ->
|
||||||
|
write(' ')
|
||||||
|
; true
|
||||||
|
),
|
||||||
write('false.'),
|
write('false.'),
|
||||||
nl.
|
nl.
|
||||||
|
|
||||||
|
|
||||||
submit_query_and_print_results(Term0, VarList) :-
|
submit_query_and_print_results(Term, VarList) :-
|
||||||
( functor(Term0, call, _) ->
|
% ( functor(Term0, call, _) ->
|
||||||
Term = Term0 % prevent pre-mature expansion of incomplete goal
|
% Term = Term0 % prevent pre-mature expansion of incomplete goal
|
||||||
% in the first argument, which is done by call/N
|
% % in the first argument, which is done by call/N
|
||||||
; expand_goal(Term0, user, Term)
|
% ; expand_goal(Term0, user, Term)
|
||||||
),
|
% ),
|
||||||
setup_call_cleanup(bb_put('$first_answer', true),
|
bb_put('$answer_count', 0),
|
||||||
submit_query_and_print_results_(Term, VarList),
|
submit_query_and_print_results_(Term, VarList).
|
||||||
bb_put('$first_answer', false)).
|
|
||||||
|
|
||||||
|
|
||||||
needs_bracketing(Value, Op) :-
|
needs_bracketing(Value, Op) :-
|
||||||
@@ -293,14 +301,17 @@ write_eqs_and_read_input(B, VarList) :-
|
|||||||
append(Equations, AttrGoals, Goals),
|
append(Equations, AttrGoals, Goals),
|
||||||
% one layer of depth added for (=/2) functor
|
% one layer of depth added for (=/2) functor
|
||||||
maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars),
|
maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars),
|
||||||
|
% maplist(term_variables_under_max_depth(22), Equations, EquationVars),
|
||||||
append([AttrGoalVars | EquationVars], Vars1),
|
append([AttrGoalVars | EquationVars], Vars1),
|
||||||
term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order.
|
term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order.
|
||||||
charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated),
|
charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated),
|
||||||
( bb_get('$first_answer', true) ->
|
bb_get('$answer_count', Count),
|
||||||
write(' '),
|
( Count =:= 0 ->
|
||||||
bb_put('$first_answer', false)
|
write(' ')
|
||||||
; true
|
; true
|
||||||
),
|
),
|
||||||
|
Count1 is Count + 1,
|
||||||
|
bb_put('$answer_count', Count1),
|
||||||
( B0 == B ->
|
( B0 == B ->
|
||||||
( Goals == [] ->
|
( Goals == [] ->
|
||||||
write('true.'), nl
|
write('true.'), nl
|
||||||
@@ -344,7 +355,9 @@ read_input(ThreadedGoals, NewVarList) :-
|
|||||||
bb_put('$report_all', true),
|
bb_put('$report_all', true),
|
||||||
nl, write('; '), false
|
nl, write('; '), false
|
||||||
; C = f ->
|
; C = f ->
|
||||||
bb_put('$report_n_more', 5),
|
bb_get('$answer_count', Count),
|
||||||
|
More is 5 - Count mod 5,
|
||||||
|
bb_put('$report_n_more', More),
|
||||||
nl, write('; '), false
|
nl, write('; '), false
|
||||||
; read_input(ThreadedGoals, NewVarList)
|
; read_input(ThreadedGoals, NewVarList)
|
||||||
).
|
).
|
||||||
@@ -408,8 +421,7 @@ print_exception(E) :-
|
|||||||
% "^C".
|
% "^C".
|
||||||
; true
|
; true
|
||||||
),
|
),
|
||||||
write_term('caught: ', [quoted(false), max_depth(20)]),
|
loader:write_error(E),
|
||||||
writeq(E),
|
|
||||||
nl.
|
nl.
|
||||||
|
|
||||||
print_exception_with_check(E) :-
|
print_exception_with_check(E) :-
|
||||||
|
|||||||
248
src/types.rs
248
src/types.rs
@@ -5,9 +5,6 @@ use crate::machine::machine_indices::*;
|
|||||||
use crate::machine::partial_string::PartialString;
|
use crate::machine::partial_string::PartialString;
|
||||||
use crate::machine::streams::*;
|
use crate::machine::streams::*;
|
||||||
use crate::parser::ast::Fixnum;
|
use crate::parser::ast::Fixnum;
|
||||||
use crate::parser::rug::{Integer, Rational};
|
|
||||||
|
|
||||||
use ordered_float::OrderedFloat;
|
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@@ -18,58 +15,55 @@ use std::ops::{Add, Sub, SubAssign};
|
|||||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[bits = 6]
|
#[bits = 6]
|
||||||
pub enum HeapCellValueTag {
|
pub enum HeapCellValueTag {
|
||||||
// non-constants / tags with adjoining forwarding bits.
|
Str = 0b000011,
|
||||||
Cons = 0b00,
|
Lis = 0b000101,
|
||||||
F64 = 0b01,
|
Var = 0b000111,
|
||||||
Str = 0b000010,
|
StackVar = 0b001001,
|
||||||
Lis = 0b000011,
|
AttrVar = 0b001011,
|
||||||
Var = 0b000110,
|
PStrLoc = 0b001101,
|
||||||
StackVar = 0b000111,
|
PStrOffset = 0b001111,
|
||||||
AttrVar = 0b010011,
|
|
||||||
PStrLoc = 0b111111,
|
|
||||||
PStrOffset = 0b001110,
|
|
||||||
// constants.
|
// constants.
|
||||||
Fixnum = 0b010010,
|
Cons = 0b0,
|
||||||
Char = 0b011011,
|
F64 = 0b010001,
|
||||||
Atom = 0b001010,
|
Fixnum = 0b010011,
|
||||||
PStr = 0b001011,
|
Char = 0b010101,
|
||||||
CStr = 0b010110, // a complete string.
|
Atom = 0b010111,
|
||||||
|
PStr = 0b011001,
|
||||||
|
CStr = 0b011011,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[bits = 6]
|
#[bits = 6]
|
||||||
pub enum HeapCellValueView {
|
pub enum HeapCellValueView {
|
||||||
// non-constants / tags with adjoining forwarding bits.
|
Str = 0b000011,
|
||||||
Cons = 0b00,
|
Lis = 0b000101,
|
||||||
F64 = 0b01,
|
Var = 0b000111,
|
||||||
Str = 0b000010,
|
StackVar = 0b001001,
|
||||||
Lis = 0b000011,
|
AttrVar = 0b001011,
|
||||||
Var = 0b000110,
|
PStrLoc = 0b001101,
|
||||||
StackVar = 0b000111,
|
PStrOffset = 0b001111,
|
||||||
AttrVar = 0b010011,
|
|
||||||
PStrLoc = 0b111111,
|
|
||||||
PStrOffset = 0b001110,
|
|
||||||
// constants.
|
// constants.
|
||||||
Fixnum = 0b010010,
|
Cons = 0b0,
|
||||||
Char = 0b011011,
|
F64 = 0b010001,
|
||||||
Atom = 0b001010,
|
Fixnum = 0b010011,
|
||||||
PStr = 0b001011,
|
Char = 0b010101,
|
||||||
CStr = 0b010110,
|
Atom = 0b010111,
|
||||||
|
PStr = 0b011001,
|
||||||
|
CStr = 0b011011,
|
||||||
// trail elements.
|
// trail elements.
|
||||||
TrailedHeapVar = 0b011110,
|
TrailedHeapVar = 0b011101,
|
||||||
TrailedStackVar = 0b011111,
|
TrailedStackVar = 0b011111,
|
||||||
TrailedAttrVarHeapLink = 0b101110,
|
TrailedAttrVarHeapLink = 0b100001,
|
||||||
TrailedAttrVarListLink = 0b100010,
|
TrailedAttrVarListLink = 0b100011,
|
||||||
TrailedAttachedValue = 0b101010,
|
TrailedAttachedValue = 0b100101,
|
||||||
TrailedBlackboardEntry = 0b100110,
|
TrailedBlackboardEntry = 0b100111,
|
||||||
TrailedBlackboardOffset = 0b100111,
|
TrailedBlackboardOffset = 0b101001,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[bits = 2]
|
#[bits = 1]
|
||||||
pub enum ConsPtrMaskTag {
|
pub enum ConsPtrMaskTag {
|
||||||
Cons = 0b00,
|
Cons = 0b0,
|
||||||
F64 = 0b01,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bitfield]
|
#[bitfield]
|
||||||
@@ -77,6 +71,7 @@ pub enum ConsPtrMaskTag {
|
|||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct ConsPtr {
|
pub struct ConsPtr {
|
||||||
ptr: B61,
|
ptr: B61,
|
||||||
|
f: bool,
|
||||||
m: bool,
|
m: bool,
|
||||||
tag: ConsPtrMaskTag,
|
tag: ConsPtrMaskTag,
|
||||||
}
|
}
|
||||||
@@ -86,22 +81,28 @@ impl ConsPtr {
|
|||||||
pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self {
|
pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self {
|
||||||
ConsPtr::new()
|
ConsPtr::new()
|
||||||
.with_ptr(ptr as *const u8 as u64)
|
.with_ptr(ptr as *const u8 as u64)
|
||||||
|
.with_f(false)
|
||||||
.with_m(false)
|
.with_m(false)
|
||||||
.with_tag(tag)
|
.with_tag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub fn as_ptr(self) -> *mut u8 {
|
pub fn as_ptr(self) -> *mut u8 {
|
||||||
self.ptr() as *mut _
|
self.ptr() as *mut _
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_tag(self) -> ConsPtrMaskTag {
|
||||||
|
self.tag()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
|
||||||
#[bits = 6]
|
#[bits = 6]
|
||||||
pub(crate) enum RefTag {
|
pub(crate) enum RefTag {
|
||||||
HeapCell = 0b0110,
|
HeapCell = 0b000111,
|
||||||
StackCell = 0b111,
|
StackCell = 0b001001,
|
||||||
AttrVar = 0b10011,
|
AttrVar = 0b001011,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bitfield]
|
#[bitfield]
|
||||||
@@ -244,66 +245,25 @@ pub struct HeapCellValue {
|
|||||||
tag: HeapCellValueTag,
|
tag: HeapCellValueTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for HeapCellValue {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
read_heap_cell!(*self,
|
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
|
||||||
if arity == 0 {
|
|
||||||
write!(f, "{}", name.as_str())
|
|
||||||
} else {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}/{}",
|
|
||||||
name.as_str(),
|
|
||||||
arity
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::PStr, pstr_atom) => {
|
|
||||||
let pstr = PartialString::from(pstr_atom);
|
|
||||||
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"pstr ( \"{}\", )",
|
|
||||||
pstr.as_str_from(0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Cons, c) => {
|
|
||||||
match_untyped_arena_ptr!(c,
|
|
||||||
(ArenaHeaderTag::Integer, n) => {
|
|
||||||
write!(f, "{}", n)
|
|
||||||
}
|
|
||||||
(ArenaHeaderTag::Rational, r) => {
|
|
||||||
write!(f, "{}", r)
|
|
||||||
}
|
|
||||||
(ArenaHeaderTag::F64, fl) => {
|
|
||||||
write!(f, "{}", fl)
|
|
||||||
}
|
|
||||||
(ArenaHeaderTag::Stream, stream) => {
|
|
||||||
write!(f, "$stream({})", stream.as_ptr() as usize)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
write!(f, "")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for HeapCellValue {
|
impl fmt::Debug for HeapCellValue {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
|
||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
tag @ (HeapCellValueTag::Cons | HeapCellValueTag::F64) => {
|
HeapCellValueTag::F64 => {
|
||||||
|
f.debug_struct("HeapCellValue")
|
||||||
|
.field("tag", &HeapCellValueTag::F64)
|
||||||
|
.field("offset", &self.get_value())
|
||||||
|
.field("m", &self.m())
|
||||||
|
.field("f", &self.f())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
HeapCellValueTag::Cons => {
|
||||||
let cons_ptr = ConsPtr::from_bytes(self.into_bytes());
|
let cons_ptr = ConsPtr::from_bytes(self.into_bytes());
|
||||||
|
|
||||||
f.debug_struct("HeapCellValue")
|
f.debug_struct("HeapCellValue")
|
||||||
.field("tag", &tag)
|
.field("tag", &HeapCellValueTag::Cons)
|
||||||
.field("ptr", &cons_ptr.ptr())
|
.field("ptr", &cons_ptr.ptr())
|
||||||
.field("m", &cons_ptr.m())
|
.field("m", &cons_ptr.m())
|
||||||
|
.field("f", &cons_ptr.f())
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
HeapCellValueTag::Atom => {
|
HeapCellValueTag::Atom => {
|
||||||
@@ -341,7 +301,7 @@ impl fmt::Debug for HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<TypedArenaPtr<T>> for HeapCellValue {
|
impl<T: ArenaAllocated> From<TypedArenaPtr<T>> for HeapCellValue {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
|
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
|
||||||
HeapCellValue::from(arena_ptr.header_ptr() as u64)
|
HeapCellValue::from(arena_ptr.header_ptr() as u64)
|
||||||
@@ -351,11 +311,9 @@ impl<T> From<TypedArenaPtr<T>> for HeapCellValue {
|
|||||||
impl From<F64Ptr> for HeapCellValue {
|
impl From<F64Ptr> for HeapCellValue {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(f64_ptr: F64Ptr) -> HeapCellValue {
|
fn from(f64_ptr: F64Ptr) -> HeapCellValue {
|
||||||
HeapCellValue::from_bytes(
|
HeapCellValue::build_with(
|
||||||
ConsPtr::from(f64_ptr.as_ptr() as u64)
|
HeapCellValueTag::F64,
|
||||||
.with_tag(ConsPtrMaskTag::F64)
|
f64_ptr.as_offset().to_u64(),
|
||||||
.with_m(false)
|
|
||||||
.into_bytes(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -375,8 +333,10 @@ impl From<ConsPtr> for HeapCellValue {
|
|||||||
impl<'a> From<(Number, &mut Arena)> for HeapCellValue {
|
impl<'a> From<(Number, &mut Arena)> for HeapCellValue {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue {
|
fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue {
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
match n {
|
match n {
|
||||||
Number::Float(n) => HeapCellValue::from(arena_alloc!(n, arena)),
|
Number::Float(OrderedFloat(n)) => HeapCellValue::from(float_alloc!(n, arena)),
|
||||||
Number::Integer(n) => HeapCellValue::from(n),
|
Number::Integer(n) => HeapCellValue::from(n),
|
||||||
Number::Rational(n) => HeapCellValue::from(n),
|
Number::Rational(n) => HeapCellValue::from(n),
|
||||||
Number::Fixnum(n) => fixnum_as_cell!(n),
|
Number::Fixnum(n) => fixnum_as_cell!(n),
|
||||||
@@ -430,11 +390,6 @@ impl HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_forwarded(self) -> bool {
|
|
||||||
self.get_forwarding_bit().unwrap_or(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_ref(self) -> bool {
|
pub fn is_ref(self) -> bool {
|
||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
@@ -486,14 +441,16 @@ impl HeapCellValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_compound(self) -> bool {
|
pub fn is_compound(self, heap: &[HeapCellValue]) -> bool {
|
||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
HeapCellValueTag::Str
|
HeapCellValueTag::Str => {
|
||||||
| HeapCellValueTag::Lis
|
cell_as_atom_cell!(heap[self.get_value()]).get_arity() > 0
|
||||||
| HeapCellValueTag::CStr
|
}
|
||||||
| HeapCellValueTag::PStr
|
HeapCellValueTag::Lis |
|
||||||
| HeapCellValueTag::PStrLoc
|
HeapCellValueTag::CStr |
|
||||||
| HeapCellValueTag::PStrOffset => {
|
HeapCellValueTag::PStr |
|
||||||
|
HeapCellValueTag::PStrLoc |
|
||||||
|
HeapCellValueTag::PStrOffset => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
HeapCellValueTag::Atom => {
|
HeapCellValueTag::Atom => {
|
||||||
@@ -549,7 +506,6 @@ impl HeapCellValue {
|
|||||||
Ok(tag) => tag,
|
Ok(tag) => tag,
|
||||||
Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
|
Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
|
||||||
ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
|
ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
|
||||||
ConsPtrMaskTag::F64 => HeapCellValueTag::F64,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -588,46 +544,39 @@ impl HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub fn get_forwarding_bit(self) -> Option<bool> {
|
pub fn get_forwarding_bit(self) -> bool {
|
||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
HeapCellValueTag::Cons // the list of non-forwardable cell tags.
|
HeapCellValueTag::Cons => ConsPtr::from_bytes(self.into_bytes()).f(),
|
||||||
| HeapCellValueTag::F64
|
_ => self.f()
|
||||||
// | HeapCellValueTag::Atom
|
|
||||||
// | HeapCellValueTag::PStr
|
|
||||||
| HeapCellValueTag::Fixnum
|
|
||||||
| HeapCellValueTag::Char => None,
|
|
||||||
_ => Some(self.f()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub fn set_forwarding_bit(&mut self, f: bool) {
|
pub fn set_forwarding_bit(&mut self, f: bool) {
|
||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
HeapCellValueTag::Cons // the list of non-forwardable cell tags.
|
HeapCellValueTag::Cons => {
|
||||||
| HeapCellValueTag::F64
|
let value = ConsPtr::from_bytes(self.into_bytes()).with_f(f);
|
||||||
// | HeapCellValueTag::Atom
|
*self = HeapCellValue::from_bytes(value.into_bytes());
|
||||||
// | HeapCellValueTag::PStr
|
}
|
||||||
| HeapCellValueTag::Fixnum
|
|
||||||
| HeapCellValueTag::Char => {}
|
|
||||||
_ => self.set_f(f),
|
_ => self.set_f(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub fn get_mark_bit(self) -> bool {
|
pub fn get_mark_bit(self) -> bool {
|
||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
HeapCellValueTag::Cons | HeapCellValueTag::F64 => {
|
HeapCellValueTag::Cons => {
|
||||||
ConsPtr::from_bytes(self.into_bytes()).m()
|
ConsPtr::from_bytes(self.into_bytes()).m()
|
||||||
}
|
}
|
||||||
_ => self.m(),
|
_ => self.m(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
pub fn set_mark_bit(&mut self, m: bool) {
|
pub fn set_mark_bit(&mut self, m: bool) {
|
||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
HeapCellValueTag::Cons | HeapCellValueTag::F64 => {
|
HeapCellValueTag::Cons => {
|
||||||
let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m);
|
let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m);
|
||||||
*self = HeapCellValue::from_bytes(value.into_bytes());
|
*self = HeapCellValue::from_bytes(value.into_bytes());
|
||||||
}
|
}
|
||||||
@@ -635,7 +584,7 @@ impl HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn order_category(self) -> Option<TermOrderCategory> {
|
pub fn order_category(self, heap: &[HeapCellValue]) -> Option<TermOrderCategory> {
|
||||||
match Number::try_from(self).ok() {
|
match Number::try_from(self).ok() {
|
||||||
Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
|
Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
|
||||||
Some(TermOrderCategory::Integer)
|
Some(TermOrderCategory::Integer)
|
||||||
@@ -654,9 +603,19 @@ impl HeapCellValue {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc |
|
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc |
|
||||||
HeapCellValueTag::CStr | HeapCellValueTag::Str => {
|
HeapCellValueTag::CStr => {
|
||||||
Some(TermOrderCategory::Compound)
|
Some(TermOrderCategory::Compound)
|
||||||
}
|
}
|
||||||
|
HeapCellValueTag::Str => {
|
||||||
|
let value = heap[self.get_value()];
|
||||||
|
let arity = cell_as_atom_cell!(value).get_arity();
|
||||||
|
|
||||||
|
if arity == 0 {
|
||||||
|
Some(TermOrderCategory::Atom)
|
||||||
|
} else {
|
||||||
|
Some(TermOrderCategory::Compound)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -681,7 +640,7 @@ const_assert!(mem::size_of::<HeapCellValue>() == 8);
|
|||||||
|
|
||||||
#[bitfield]
|
#[bitfield]
|
||||||
#[repr(u64)]
|
#[repr(u64)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
pub struct UntypedArenaPtr {
|
pub struct UntypedArenaPtr {
|
||||||
ptr: B61,
|
ptr: B61,
|
||||||
m: bool,
|
m: bool,
|
||||||
@@ -697,6 +656,13 @@ impl From<*const ArenaHeader> for UntypedArenaPtr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<*const IndexPtr> for UntypedArenaPtr {
|
||||||
|
#[inline]
|
||||||
|
fn from(ptr: *const IndexPtr) -> UntypedArenaPtr {
|
||||||
|
unsafe { mem::transmute(ptr) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<UntypedArenaPtr> for *const ArenaHeader {
|
impl From<UntypedArenaPtr> for *const ArenaHeader {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {
|
fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ pub fn run_top_level_test_with_args<
|
|||||||
Command::cargo_bin(SCRYER_PROLOG)
|
Command::cargo_bin(SCRYER_PROLOG)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.arg("-f")
|
.arg("-f")
|
||||||
|
.arg("--no-add-history")
|
||||||
.args(args)
|
.args(args)
|
||||||
.write_stdin(stdin)
|
.write_stdin(stdin)
|
||||||
.assert()
|
.assert()
|
||||||
|
|||||||
@@ -29,12 +29,7 @@ fn do_not_duplicate_path_components() {
|
|||||||
['tests-pl/issue852-throw_e.pl'].\n\
|
['tests-pl/issue852-throw_e.pl'].\n\
|
||||||
halt.\n\
|
halt.\n\
|
||||||
",
|
",
|
||||||
"\
|
" throw(e).\n false.\n throw(e).\n false.\n",
|
||||||
caught: e\n\
|
|
||||||
false.\n\
|
|
||||||
caught: e\n\
|
|
||||||
false.\n\
|
|
||||||
",
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,10 +52,10 @@ fn handle_residual_goal() {
|
|||||||
",
|
",
|
||||||
" \
|
" \
|
||||||
true.\n \
|
true.\n \
|
||||||
true.\n\
|
true.\n \
|
||||||
false.\n \
|
false.\n \
|
||||||
X = - X.\n \
|
X = - X.\n \
|
||||||
dif:dif(- X,X).\n\
|
dif:dif(- X,X).\n \
|
||||||
false.\n \
|
false.\n \
|
||||||
Vars = [X], dif:dif(- X,X).\n \
|
Vars = [X], dif:dif(- X,X).\n \
|
||||||
true.\n \
|
true.\n \
|
||||||
@@ -79,7 +74,7 @@ fn occurs_check_flag() {
|
|||||||
f(X, X).\n\
|
f(X, X).\n\
|
||||||
halt.\n\
|
halt.\n\
|
||||||
",
|
",
|
||||||
"false.\n",
|
" false.\n",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,10 +90,10 @@ fn occurs_check_flag2() {
|
|||||||
halt.\n\
|
halt.\n\
|
||||||
",
|
",
|
||||||
" \
|
" \
|
||||||
true.\n\
|
true.\n \
|
||||||
|
false.\n \
|
||||||
|
true.\n \
|
||||||
false.\n \
|
false.\n \
|
||||||
true.\n\
|
|
||||||
false.\n\
|
|
||||||
false.\n\
|
false.\n\
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
@@ -136,7 +131,7 @@ fn no_stutter() {
|
|||||||
run_top_level_test_no_args("write(a), write(b), false.\n\
|
run_top_level_test_no_args("write(a), write(b), false.\n\
|
||||||
halt.\n\
|
halt.\n\
|
||||||
",
|
",
|
||||||
"abfalse.\n")
|
"ab false.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -170,6 +165,6 @@ fn ignored_constraint() {
|
|||||||
fn call_0() {
|
fn call_0() {
|
||||||
load_module_test(
|
load_module_test(
|
||||||
"tests-pl/issue831-call0.pl",
|
"tests-pl/issue831-call0.pl",
|
||||||
"caught: error(existence_error(procedure,call/0),call/0)\n",
|
" error(existence_error(procedure,call/0),call/0).\n",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ fn hello_world() {
|
|||||||
fn syntax_error() {
|
fn syntax_error() {
|
||||||
load_module_test(
|
load_module_test(
|
||||||
"tests-pl/syntax_error.pl",
|
"tests-pl/syntax_error.pl",
|
||||||
"caught: error(syntax_error(incomplete_reduction),read_term/3:6)\n",
|
" error(syntax_error(incomplete_reduction),read_term/3:6).\n",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ fn rules() {
|
|||||||
fn setup_call_cleanup_load() {
|
fn setup_call_cleanup_load() {
|
||||||
load_module_test(
|
load_module_test(
|
||||||
"src/tests/setup_call_cleanup.pl",
|
"src/tests/setup_call_cleanup.pl",
|
||||||
"1+21+31+2>_17737+_177381+_158071+2>41+2>_177381+2>31+2>31+2>4ba"
|
"1+21+31+2>A+B1+G1+2>41+2>B1+2>31+2>31+2>4ba",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ fn setup_call_cleanup_process() {
|
|||||||
run_top_level_test_with_args(
|
run_top_level_test_with_args(
|
||||||
&["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"],
|
&["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"],
|
||||||
"",
|
"",
|
||||||
"1+21+31+2>_19590+_195911+_176601+2>41+2>_195911+2>31+2>31+2>4ba"
|
"1+21+31+2>A+B1+G1+2>41+2>B1+2>31+2>31+2>4ba",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user