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:
|
||||
command: test
|
||||
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]
|
||||
name = "scryer-prolog"
|
||||
version = "0.9.0"
|
||||
version = "0.9.1"
|
||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "A modern Prolog implementation written mostly in Rust."
|
||||
@@ -9,31 +9,26 @@ repository = "https://github.com/mthom/scryer-prolog"
|
||||
license = "BSD-3-Clause"
|
||||
keywords = ["prolog", "prolog-interpreter", "prolog-system"]
|
||||
categories = ["command-line-utilities"]
|
||||
build = "build.rs"
|
||||
|
||||
[workspace]
|
||||
members = ["crates/num-rug-adapter",
|
||||
"crates/static-string-indexing",
|
||||
"crates/instructions-template",
|
||||
"crates/to-syn-value",
|
||||
"crates/to-syn-value_derive"]
|
||||
build = "build/main.rs"
|
||||
rust-version = "1.61"
|
||||
|
||||
[features]
|
||||
num = ["num-rug-adapter"]
|
||||
# no default features to make num tests work
|
||||
# workaround for --no-default-features and --features not working intuitively for workspaces with a root package
|
||||
# see rust-lang/cargo#7160
|
||||
default = ["rug"]
|
||||
|
||||
[build-dependencies]
|
||||
indexmap = "1.0.2"
|
||||
static-string-indexing = { path = "./crates/static-string-indexing" }
|
||||
instructions-template = { path = "./crates/instructions-template" }
|
||||
proc-macro2 = "*"
|
||||
proc-macro2 = "1.0.36"
|
||||
quote = "1.0.15"
|
||||
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]
|
||||
cpu-time = "1.0.0"
|
||||
crossterm = "0.16.0"
|
||||
crossterm = "0.20.0"
|
||||
dirs-next = "2.0.0"
|
||||
divrem = "0.1.0"
|
||||
fxhash = "0.2.1"
|
||||
@@ -43,33 +38,39 @@ indexmap = "1.0.2"
|
||||
lazy_static = "1.4.0"
|
||||
lexical = "5.2.2"
|
||||
libc = "0.2.62"
|
||||
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } # modular-bitfield = "0.11.2"
|
||||
nix = "0.15.0"
|
||||
num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" }
|
||||
ordered-float = "2.1.1"
|
||||
modular-bitfield = "0.11.2"
|
||||
ctrlc = "3.2.2"
|
||||
ordered-float = "2.6.0"
|
||||
phf = { version = "0.9", features = ["macros"] }
|
||||
ref_thread_local = "0.0.0"
|
||||
rug = { version = "1.12.0", optional = true }
|
||||
rug = { version = "1.15.0", optional = true }
|
||||
rustyline = "9.0.0"
|
||||
ring = "0.16.13"
|
||||
ripemd160 = "0.8.0"
|
||||
sha3 = "0.8.2"
|
||||
blake2 = "0.8.1"
|
||||
openssl = { version = "0.10.29", features = ["vendored"] }
|
||||
crrl ="0.2.0"
|
||||
native-tls = "0.2.4"
|
||||
chrono = "0.4.11"
|
||||
select = "0.4.3"
|
||||
roxmltree = "0.11.0"
|
||||
base64 = "0.12.3"
|
||||
smallvec = "*"
|
||||
smallvec = "1.8.0"
|
||||
sodiumoxide = "0.2.6"
|
||||
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]
|
||||
assert_cmd = "1.0.3"
|
||||
predicates-core = "1.0.2"
|
||||
serial_test = "0.5.1"
|
||||
|
||||
[patch.crates-io]
|
||||
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" }
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
@@ -1,5 +1,5 @@
|
||||
# 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
|
||||
WORKDIR /scryer-prolog
|
||||
RUN cargo install cargo-chef
|
||||
|
||||
94
README.md
94
README.md
@@ -1,3 +1,4 @@
|
||||
|
||||
# Scryer Prolog
|
||||
|
||||
Scryer Prolog aims to become to ISO Prolog what GHC is to Haskell: an open
|
||||
@@ -101,7 +102,7 @@ strings.
|
||||
|
||||
## Installing Scryer Prolog
|
||||
|
||||
### Native Install (Unix Only)
|
||||
### Native Install
|
||||
|
||||
First, install the latest stable version of
|
||||
[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
|
||||
used.
|
||||
|
||||
Scryer Prolog can be installed with cargo, like so:
|
||||
|
||||
```
|
||||
$> 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:
|
||||
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:
|
||||
|
||||
```
|
||||
$> git clone https://github.com/mthom/scryer-prolog
|
||||
@@ -136,9 +125,20 @@ $> cargo run [--release]
|
||||
The optional `--release` flag will perform various optimizations,
|
||||
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**.
|
||||
|
||||
### Docker Install (All Platforms)
|
||||
### Docker Install
|
||||
|
||||
First, install [Docker](https://docs.docker.com/get-docker/) on Linux,
|
||||
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`
|
||||
or `.` to abort the search and return to the
|
||||
toplevel prompt. Press `f` to see the next 5 answers, and
|
||||
`a` to see all answers. Press `h` to show a help message.
|
||||
toplevel prompt. Press `f` to see up to the next multiple of
|
||||
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`:
|
||||
|
||||
@@ -267,9 +273,30 @@ in any clause of a predicate's definition.
|
||||
|
||||
### 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`
|
||||
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.
|
||||
|
||||
For example, the following query succeeds:
|
||||
@@ -279,15 +306,9 @@ For example, the following query succeeds:
|
||||
true.
|
||||
```
|
||||
|
||||
Internally, strings are represented very compactly in packed
|
||||
UTF-8 encoding. A naive representation of strings as lists of
|
||||
characters would use one memory cell per character, one
|
||||
memory cell per list constructor, and one memory cell for
|
||||
each tail that occurs in the list. Since one memory cell takes
|
||||
8 bytes on 64-bit machines, the packed representation used by
|
||||
Scryer Prolog yields an up to **24-fold reduction** of
|
||||
memory usage, and corresponding reduction of memory accesses when
|
||||
creating and processing strings.
|
||||
This shows that the string `"abc"`, which is represented as a sequence
|
||||
of 3 bytes internally, appears to Prolog programs as a list of
|
||||
characters.
|
||||
|
||||
Scryer Prolog uses the same efficient encoding for *partial* strings,
|
||||
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
|
||||
only the standard predicate `(=)/2` is used.
|
||||
|
||||
Definite clause grammars as provided by
|
||||
[`library(dcgs)`](src/lib/dcgs.pl), and the predicates from
|
||||
[`library(lists)`](src/lib/lists.pl), are ideally suited for reasoning
|
||||
about strings.
|
||||
|
||||
Partial strings were first proposed by Ulrich Neumerkel in issue
|
||||
[#95](https://github.com/mthom/scryer-prolog/issues/95).
|
||||
The efficient internal representation of strings and partial strings
|
||||
was first proposed and explained by Ulrich Neumerkel in
|
||||
issues [#24](https://github.com/mthom/scryer-prolog/issues/24)
|
||||
and [#95](https://github.com/mthom/scryer-prolog/issues/95), and
|
||||
Scryer Prolog is the first Prolog system that implements it.
|
||||
|
||||
### 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.
|
||||
* [`http/http_open`](src/lib/http/http_open.pl) Open a stream to
|
||||
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)
|
||||
`load_html/3` and `load_xml/3` represent HTML and XML documents
|
||||
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)
|
||||
Predicates for negotiating TLS connections explicitly.
|
||||
* [`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:
|
||||
|
||||
|
||||
@@ -190,9 +190,9 @@ enum REPLCodePtr {
|
||||
DynamicProperty,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
|
||||
AbolishClause,
|
||||
#[strum_discriminants(strum(props(Arity = "5", Name = "$asserta")))]
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))]
|
||||
Asserta,
|
||||
#[strum_discriminants(strum(props(Arity = "5", Name = "$assertz")))]
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))]
|
||||
Assertz,
|
||||
#[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
|
||||
Retract,
|
||||
@@ -276,6 +276,8 @@ enum SystemClauseType {
|
||||
DeleteHeadAttribute,
|
||||
#[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))]
|
||||
DynamicModuleResolution(usize),
|
||||
#[strum_discriminants(strum(props(Arity = "arity", Name = "$prepare_call_clause")))]
|
||||
PrepareCallClause(usize),
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))]
|
||||
EnqueueAttributedVar,
|
||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
|
||||
@@ -402,8 +404,6 @@ enum SystemClauseType {
|
||||
InferenceLevel,
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$clean_up_block")))]
|
||||
CleanUpBlock,
|
||||
#[strum_discriminants(strum(props(Arity = "0", Name = "$erase_ball")))]
|
||||
EraseBall,
|
||||
#[strum_discriminants(strum(props(Arity = "0", Name = "$fail")))]
|
||||
Fail,
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$get_ball")))]
|
||||
@@ -432,6 +432,12 @@ enum SystemClauseType {
|
||||
ReturnFromVerifyAttr,
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_ball")))]
|
||||
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")))]
|
||||
SetCutPointByDefault(RegType),
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_double_quotes")))]
|
||||
@@ -490,7 +496,7 @@ enum SystemClauseType {
|
||||
CryptoDataEncrypt,
|
||||
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
|
||||
CryptoDataDecrypt,
|
||||
#[strum_discriminants(strum(props(Arity = "5", Name = "$crypto_curve_scalar_mult")))]
|
||||
#[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_curve_scalar_mult")))]
|
||||
CryptoCurveScalarMult,
|
||||
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
|
||||
Ed25519Sign,
|
||||
@@ -538,6 +544,26 @@ enum SystemClauseType {
|
||||
PopCount,
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$cpu_now")))]
|
||||
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),
|
||||
}
|
||||
|
||||
@@ -802,8 +828,8 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
use crate::parser::ast::*;
|
||||
use crate::types::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
use slice_deque::SliceDeque;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
@@ -915,8 +941,8 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
IndexingCodePtr,
|
||||
IndexingCodePtr,
|
||||
),
|
||||
SwitchOnConstant(IndexMap<Literal, IndexingCodePtr>),
|
||||
SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>),
|
||||
SwitchOnConstant(IndexMap<Literal, IndexingCodePtr, FxBuildHasher>),
|
||||
SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -1026,8 +1052,8 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum IndexingLine {
|
||||
Indexing(IndexingInstruction),
|
||||
IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
|
||||
DynamicIndexedChoice(SliceDeque<usize>),
|
||||
IndexedChoice(VecDeque<IndexedChoiceInstruction>),
|
||||
DynamicIndexedChoice(VecDeque<usize>),
|
||||
}
|
||||
|
||||
impl From<IndexingInstruction> for IndexingLine {
|
||||
@@ -1095,6 +1121,7 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
#[inline]
|
||||
pub fn is_head_instr(&self) -> bool {
|
||||
match self {
|
||||
Instruction::Deallocate |
|
||||
Instruction::GetConstant(..) |
|
||||
Instruction::GetList(..) |
|
||||
Instruction::GetPartialString(..) |
|
||||
@@ -1424,6 +1451,12 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::DefaultExecuteN(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::CallTermLessThan(_) |
|
||||
&Instruction::CallTermGreaterThanOrEqual(_) |
|
||||
@@ -1585,6 +1618,9 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::CallDeleteAttribute(_) |
|
||||
&Instruction::CallDeleteHeadAttribute(_) |
|
||||
&Instruction::CallDynamicModuleResolution(..) |
|
||||
&Instruction::CallPrepareCallClause(..) |
|
||||
&Instruction::CallCompileInlineOrExpandedGoal(..) |
|
||||
&Instruction::CallIsExpandedOrInlined(_) |
|
||||
&Instruction::CallEnqueueAttributedVar(_) |
|
||||
&Instruction::CallFetchGlobalVar(_) |
|
||||
&Instruction::CallFirstStream(_) |
|
||||
@@ -1648,7 +1684,6 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::CallSetStreamPosition(_) |
|
||||
&Instruction::CallInferenceLevel(_) |
|
||||
&Instruction::CallCleanUpBlock(_) |
|
||||
&Instruction::CallEraseBall(_) |
|
||||
&Instruction::CallFail(_) |
|
||||
&Instruction::CallGetBall(_) |
|
||||
&Instruction::CallGetCurrentBlock(_) |
|
||||
@@ -1658,12 +1693,22 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::CallInstallNewBlock(_) |
|
||||
&Instruction::CallMaybe(_) |
|
||||
&Instruction::CallCpuNow(_) |
|
||||
&Instruction::CallDeterministicLengthRundown(_) |
|
||||
&Instruction::CallHttpOpen(_) |
|
||||
&Instruction::CallHttpListen(_) |
|
||||
&Instruction::CallHttpAccept(_) |
|
||||
&Instruction::CallHttpAnswer(_) |
|
||||
&Instruction::CallPredicateDefined(_) |
|
||||
&Instruction::CallStripModule(_) |
|
||||
&Instruction::CallCurrentTime(_) |
|
||||
&Instruction::CallQuotedToken(_) |
|
||||
&Instruction::CallReadTermFromChars(_) |
|
||||
&Instruction::CallResetBlock(_) |
|
||||
&Instruction::CallReturnFromVerifyAttr(_) |
|
||||
&Instruction::CallSetBall(_) |
|
||||
&Instruction::CallPushBallStack(_) |
|
||||
&Instruction::CallPopBallStack(_) |
|
||||
&Instruction::CallPopFromBallStack(_) |
|
||||
&Instruction::CallSetCutPointByDefault(..) |
|
||||
&Instruction::CallSetDoubleQuotes(_) |
|
||||
&Instruction::CallSetSeed(_) |
|
||||
@@ -1786,7 +1831,10 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::ExecuteFileTime(_) |
|
||||
&Instruction::ExecuteDeleteAttribute(_) |
|
||||
&Instruction::ExecuteDeleteHeadAttribute(_) |
|
||||
&Instruction::ExecuteDynamicModuleResolution(_, _) |
|
||||
&Instruction::ExecuteDynamicModuleResolution(..) |
|
||||
&Instruction::ExecutePrepareCallClause(..) |
|
||||
&Instruction::ExecuteCompileInlineOrExpandedGoal(..) |
|
||||
&Instruction::ExecuteIsExpandedOrInlined(_) |
|
||||
&Instruction::ExecuteEnqueueAttributedVar(_) |
|
||||
&Instruction::ExecuteFetchGlobalVar(_) |
|
||||
&Instruction::ExecuteFirstStream(_) |
|
||||
@@ -1850,7 +1898,6 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::ExecuteSetStreamPosition(_) |
|
||||
&Instruction::ExecuteInferenceLevel(_) |
|
||||
&Instruction::ExecuteCleanUpBlock(_) |
|
||||
&Instruction::ExecuteEraseBall(_) |
|
||||
&Instruction::ExecuteFail(_) |
|
||||
&Instruction::ExecuteGetBall(_) |
|
||||
&Instruction::ExecuteGetCurrentBlock(_) |
|
||||
@@ -1860,12 +1907,22 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::ExecuteInstallNewBlock(_) |
|
||||
&Instruction::ExecuteMaybe(_) |
|
||||
&Instruction::ExecuteCpuNow(_) |
|
||||
&Instruction::ExecuteDeterministicLengthRundown(_) |
|
||||
&Instruction::ExecuteHttpOpen(_) |
|
||||
&Instruction::ExecuteHttpListen(_) |
|
||||
&Instruction::ExecuteHttpAccept(_) |
|
||||
&Instruction::ExecuteHttpAnswer(_) |
|
||||
&Instruction::ExecutePredicateDefined(_) |
|
||||
&Instruction::ExecuteStripModule(_) |
|
||||
&Instruction::ExecuteCurrentTime(_) |
|
||||
&Instruction::ExecuteQuotedToken(_) |
|
||||
&Instruction::ExecuteReadTermFromChars(_) |
|
||||
&Instruction::ExecuteResetBlock(_) |
|
||||
&Instruction::ExecuteReturnFromVerifyAttr(_) |
|
||||
&Instruction::ExecuteSetBall(_) |
|
||||
&Instruction::ExecutePushBallStack(_) |
|
||||
&Instruction::ExecutePopBallStack(_) |
|
||||
&Instruction::ExecutePopFromBallStack(_) |
|
||||
&Instruction::ExecuteSetCutPointByDefault(_, _) |
|
||||
&Instruction::ExecuteSetDoubleQuotes(_) |
|
||||
&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_to_instr_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 {
|
||||
let ident = variant.ident.clone();
|
||||
@@ -2212,6 +2270,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
||||
) => 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 {
|
||||
@@ -2241,6 +2305,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
||||
) => Instruction::#instr_ident(0)
|
||||
}
|
||||
);
|
||||
|
||||
is_inbuilt_arms.push(
|
||||
quote! {
|
||||
(atom!(#name), #arity) => true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for (name, arity, variant) in instr_data.builtin_type_variants {
|
||||
@@ -2302,6 +2372,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
||||
) => Instruction::#instr_ident(0)
|
||||
}
|
||||
});
|
||||
|
||||
is_inbuilt_arms.push(
|
||||
quote! {
|
||||
(atom!(#name), #arity) => true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
);
|
||||
|
||||
is_inbuilt_arms.push(
|
||||
quote! {
|
||||
(atom!(#name), #arity) => true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
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))
|
||||
)
|
||||
}
|
||||
} else if ident.to_string() == "InlineCallN" {
|
||||
quote! {
|
||||
(atom!(#name), arity) => ClauseType::System(
|
||||
SystemClauseType::#ident(arity)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
(atom!(#name), #arity) => ClauseType::System(
|
||||
@@ -2421,6 +2509,7 @@ pub fn generate_instructions_rs() -> TokenStream {
|
||||
});
|
||||
|
||||
let ident = variant.ident;
|
||||
|
||||
let instr_ident = if ident != "CallContinuation" {
|
||||
format_ident!("Call{}", ident)
|
||||
} else {
|
||||
@@ -2444,6 +2533,18 @@ pub fn generate_instructions_rs() -> TokenStream {
|
||||
) => 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 {
|
||||
@@ -2509,6 +2610,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
||||
)) => Instruction::#instr_ident(0)
|
||||
}
|
||||
});
|
||||
|
||||
is_inbuilt_arms.push(
|
||||
quote! {
|
||||
(atom!(#name), #arity) => true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for (name, arity, variant) in instr_data.clause_type_variants {
|
||||
@@ -2516,7 +2623,7 @@ pub fn generate_instructions_rs() -> TokenStream {
|
||||
|
||||
if ident == "Named" {
|
||||
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! {
|
||||
@@ -2578,6 +2685,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
||||
ClauseType::#ident => Instruction::#ident(0)
|
||||
}
|
||||
});
|
||||
|
||||
is_inbuilt_arms.push(
|
||||
quote! {
|
||||
(atom!(#name), _arity) => true
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let to_execute_arms: Vec<_> = instr_data.instr_variants
|
||||
@@ -2912,7 +3025,7 @@ pub fn generate_instructions_rs() -> TokenStream {
|
||||
}
|
||||
|
||||
impl ClauseType {
|
||||
pub fn from(name: Atom, arity: usize) -> ClauseType {
|
||||
pub fn from(name: Atom, arity: usize, arena: &mut Arena) -> ClauseType {
|
||||
match (name, arity) {
|
||||
#(
|
||||
#clause_type_from_name_and_arity_arms,
|
||||
@@ -2928,19 +3041,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_builtin(&self) -> bool {
|
||||
if let ClauseType::BuiltIn(_) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_inlined(&self) -> bool {
|
||||
if let ClauseType::Inlined(_) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
|
||||
match (name, arity) {
|
||||
#(
|
||||
#is_inbuilt_arms,
|
||||
)*
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3135,7 +3241,7 @@ enum Arity {
|
||||
impl From<&'static str> for Arity {
|
||||
fn from(arity: &'static str) -> Self {
|
||||
usize::from_str_radix(&arity, 10)
|
||||
.map(|n| Arity::Static(n))
|
||||
.map(Arity::Static)
|
||||
.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 static_string_indexing::index_static_strings;
|
||||
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
|
||||
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() {
|
||||
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 dest_path = Path::new(&out_dir).join("libraries.rs");
|
||||
|
||||
@@ -65,10 +78,9 @@ fn main() {
|
||||
.write_all(quoted_output.to_string().as_bytes())
|
||||
.unwrap();
|
||||
|
||||
Command::new("rustfmt")
|
||||
.arg(instructions_path.as_os_str())
|
||||
.spawn().unwrap()
|
||||
.wait().unwrap();
|
||||
if has_rustfmt {
|
||||
format_generated_file(instructions_path.as_path());
|
||||
}
|
||||
|
||||
let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
|
||||
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())
|
||||
.unwrap();
|
||||
|
||||
Command::new("rustfmt")
|
||||
.arg(static_atoms_path.as_os_str())
|
||||
.spawn().unwrap()
|
||||
.wait().unwrap();
|
||||
if has_rustfmt {
|
||||
format_generated_file(static_atoms_path.as_path());
|
||||
}
|
||||
|
||||
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() {
|
||||
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() {
|
||||
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 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 } },)*
|
||||
};
|
||||
}
|
||||
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 take_bindings(self) -> AllocVarDict;
|
||||
fn max_reg_allocated(&self) -> usize;
|
||||
|
||||
fn drain_var_data<'a>(
|
||||
&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::machine_indices::*;
|
||||
use crate::machine::streams::*;
|
||||
use crate::raw_block::*;
|
||||
use crate::read::*;
|
||||
|
||||
use modular_bitfield::prelude::*;
|
||||
use ordered_float::OrderedFloat;
|
||||
use rug::{Integer, Rational};
|
||||
use crate::parser::rug::{Integer, Rational};
|
||||
|
||||
use std::alloc;
|
||||
use std::fmt;
|
||||
@@ -20,14 +21,116 @@ macro_rules! arena_alloc {
|
||||
($e:expr, $arena:expr) => {{
|
||||
let result = $e;
|
||||
#[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)]
|
||||
#[bits = 7]
|
||||
pub enum ArenaHeaderTag {
|
||||
F64 = 0b01,
|
||||
Integer = 0b10,
|
||||
Rational = 0b11,
|
||||
OssifiedOpDir = 0b0000100,
|
||||
@@ -37,6 +140,8 @@ pub enum ArenaHeaderTag {
|
||||
OutputFileStream = 0b10100,
|
||||
NamedTcpStream = 0b011100,
|
||||
NamedTlsStream = 0b100000,
|
||||
HttpReadStream = 0b100001,
|
||||
HttpWriteStream = 0b100010,
|
||||
ReadlineStream = 0b110000,
|
||||
StaticStringStream = 0b110100,
|
||||
ByteStream = 0b111000,
|
||||
@@ -44,7 +149,13 @@ pub enum ArenaHeaderTag {
|
||||
StandardErrorStream = 0b11000,
|
||||
NullStream = 0b111100,
|
||||
TcpListener = 0b1000000,
|
||||
HttpListener = 0b1000001,
|
||||
HttpResponse = 0b1000010,
|
||||
Dropped = 0b1000100,
|
||||
IndexPtrDynamicUndefined = 0b1000101,
|
||||
IndexPtrDynamicIndex = 0b1000110,
|
||||
IndexPtrIndex = 0b1000111,
|
||||
IndexPtrUndefined = 0b1001000,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
@@ -72,9 +183,15 @@ impl ArenaHeader {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialOrd, Ord)]
|
||||
#[derive(Debug)]
|
||||
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> {
|
||||
fn eq(&self, other: &TypedArenaPtr<T>) -> bool {
|
||||
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 + Ord> Ord for TypedArenaPtr<T> {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
(**self).cmp(&**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Hash> Hash for TypedArenaPtr<T> {
|
||||
#[inline(always)]
|
||||
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]
|
||||
pub const fn new(data: *mut T) -> Self {
|
||||
unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) }
|
||||
@@ -132,14 +255,14 @@ impl<T: ?Sized> TypedArenaPtr<T> {
|
||||
#[inline]
|
||||
pub fn header_ptr(&self) -> *const ArenaHeader {
|
||||
let mut ptr = self.as_ptr() as *const u8 as usize;
|
||||
ptr -= mem::size_of::<*const ArenaHeader>();
|
||||
ptr -= T::header_offset_from_payload(); // mem::size_of::<*const ArenaHeader>();
|
||||
ptr as *const ArenaHeader
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
|
||||
let mut ptr = self.as_ptr() as *const u8 as usize;
|
||||
ptr -= mem::size_of::<*const ArenaHeader>();
|
||||
ptr -= T::header_offset_from_payload(); // mem::size_of::<*const ArenaHeader>();
|
||||
ptr as *mut ArenaHeader
|
||||
}
|
||||
|
||||
@@ -173,18 +296,66 @@ impl<T: ?Sized> TypedArenaPtr<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ArenaAllocated {
|
||||
pub trait ArenaAllocated: Sized {
|
||||
type PtrToAllocated;
|
||||
|
||||
fn tag() -> ArenaHeaderTag;
|
||||
fn size(&self) -> usize;
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated
|
||||
where
|
||||
Self: Sized;
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated;
|
||||
|
||||
fn header_offset_from_payload() -> usize {
|
||||
mem::size_of::<*const ArenaHeader>()
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct F64Ptr(pub TypedArenaPtr<OrderedFloat<f64>>);
|
||||
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)]
|
||||
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 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
@@ -193,41 +364,94 @@ impl fmt::Display for F64Ptr {
|
||||
}
|
||||
|
||||
impl Deref for F64Ptr {
|
||||
type Target = TypedArenaPtr<OrderedFloat<f64>>;
|
||||
type Target = OrderedFloat<f64>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
unsafe { &*self.0.as_ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for F64Ptr {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
unsafe { &mut *self.0.as_ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for OrderedFloat<f64> {
|
||||
type PtrToAllocated = F64Ptr;
|
||||
|
||||
#[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 {
|
||||
impl F64Ptr {
|
||||
#[inline(always)]
|
||||
pub fn from_offset(offset: usize) -> Self {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
F64Ptr(TypedArenaPtr::new(dst as *mut Self))
|
||||
F64Ptr(ptr::NonNull::new_unchecked(lookup_float(offset)))
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
@@ -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)]
|
||||
struct AllocSlab {
|
||||
next: *mut AllocSlab,
|
||||
@@ -347,7 +658,10 @@ struct AllocSlab {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Arena(*mut AllocSlab);
|
||||
pub struct Arena {
|
||||
base: *mut AllocSlab,
|
||||
pub f64_tbl: F64Table,
|
||||
}
|
||||
|
||||
unsafe impl Send for Arena {}
|
||||
unsafe impl Sync for Arena {}
|
||||
@@ -355,26 +669,7 @@ unsafe impl Sync for Arena {}
|
||||
impl Arena {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Arena(ptr::null_mut())
|
||||
}
|
||||
|
||||
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
|
||||
Arena { base: ptr::null_mut(), f64_tbl: F64Table::new() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,6 +695,12 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
|
||||
ArenaHeaderTag::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 => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>());
|
||||
}
|
||||
@@ -420,20 +721,28 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
|
||||
ArenaHeaderTag::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 => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>());
|
||||
}
|
||||
ArenaHeaderTag::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 {
|
||||
fn drop(&mut self) {
|
||||
let mut ptr = self.0;
|
||||
let mut ptr = self.base;
|
||||
|
||||
while !ptr.is_null() {
|
||||
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 ordered_float::OrderedFloat;
|
||||
use rug::{Integer, Rational};
|
||||
use crate::parser::rug::{Integer, Rational};
|
||||
|
||||
#[test]
|
||||
fn float_ptr_cast() {
|
||||
let mut wam = MockWAM::new();
|
||||
|
||||
let f = OrderedFloat(0f64);
|
||||
let mut fp = arena_alloc!(f, &mut wam.machine_st.arena);
|
||||
let cell = HeapCellValue::from(fp);
|
||||
let f = 0f64;
|
||||
let fp = float_alloc!(f, wam.machine_st.arena);
|
||||
let mut cell = HeapCellValue::from(fp);
|
||||
|
||||
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
|
||||
assert_eq!(fp.get_mark_bit(), false);
|
||||
assert_eq!(**fp, f);
|
||||
assert_eq!(cell.get_mark_bit(), false);
|
||||
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,
|
||||
(HeapCellValueTag::F64, ptr) => {
|
||||
assert_eq!(**ptr, f)
|
||||
assert_eq!(OrderedFloat(*ptr), OrderedFloat(f))
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
@@ -542,8 +851,9 @@ mod tests {
|
||||
|
||||
// integer
|
||||
|
||||
let big_int = 2 * Integer::from(1u64 << 63);
|
||||
let big_int_ptr: TypedArenaPtr<Integer> = arena_alloc!(big_int, &mut wam.machine_st.arena);
|
||||
let big_int: Integer = 2 * Integer::from(1u64 << 63);
|
||||
let big_int_ptr: TypedArenaPtr<Integer> =
|
||||
arena_alloc!(big_int, &mut wam.machine_st.arena);
|
||||
|
||||
assert!(!big_int_ptr.as_ptr().is_null());
|
||||
|
||||
@@ -696,16 +1006,16 @@ mod tests {
|
||||
_ => { 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);
|
||||
|
||||
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),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked(1 << 57) {
|
||||
match Fixnum::build_with_checked(1 << 56) {
|
||||
Ok(_) => assert!(false),
|
||||
_ => assert!(true),
|
||||
}
|
||||
@@ -725,17 +1035,17 @@ mod tests {
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked((1 << 56) - 1) {
|
||||
Ok(n) => assert_eq!(n.get_num(), (1 << 56) - 1),
|
||||
match Fixnum::build_with_checked((1 << 55) - 1) {
|
||||
Ok(n) => assert_eq!(n.get_num(), (1 << 55) - 1),
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked(-(1 << 56)) {
|
||||
Ok(n) => assert_eq!(n.get_num(), -(1 << 56)),
|
||||
match Fixnum::build_with_checked(-(1 << 55)) {
|
||||
Ok(n) => assert_eq!(n.get_num(), -(1 << 55)),
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked(-(1 << 56) - 1) {
|
||||
match Fixnum::build_with_checked(-(1 << 55) - 1) {
|
||||
Ok(_n) => assert!(false),
|
||||
_ => assert!(true),
|
||||
}
|
||||
@@ -747,22 +1057,11 @@ mod tests {
|
||||
|
||||
// float
|
||||
|
||||
let float = OrderedFloat(3.1415926f64);
|
||||
let float_ptr = arena_alloc!(float, &mut wam.machine_st.arena);
|
||||
let float = 3.1415926f64;
|
||||
let float_ptr = float_alloc!(float, wam.machine_st.arena);
|
||||
let cell = HeapCellValue::from(float_ptr);
|
||||
|
||||
assert!(!float_ptr.as_ptr().is_null());
|
||||
|
||||
let float_cell = typed_arena_ptr_as_cell!(float_ptr);
|
||||
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
|
||||
|
||||
match float_cell.to_untyped_arena_ptr() {
|
||||
Some(untyped_arena_ptr) => {
|
||||
assert_eq!(Some(float_ptr.header_ptr()), Some(untyped_arena_ptr.into()),);
|
||||
}
|
||||
None => {
|
||||
assert!(false); // we fail.
|
||||
}
|
||||
}
|
||||
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
|
||||
|
||||
// char
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use crate::allocator::*;
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::fixtures::*;
|
||||
use crate::debray_allocator::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::targets::QueryInstruction;
|
||||
use crate::types::*;
|
||||
|
||||
use crate::parser::ast::*;
|
||||
@@ -12,7 +13,6 @@ use crate::parser::rug::ops::PowAssign;
|
||||
use crate::parser::rug::{Assign, Integer, Rational};
|
||||
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
|
||||
use ordered_float::*;
|
||||
|
||||
@@ -64,21 +64,24 @@ impl<'a> ArithInstructionIterator<'a> {
|
||||
fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
|
||||
let state = match term {
|
||||
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(..) => {
|
||||
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
||||
}
|
||||
ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
|
||||
let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
|
||||
ct @ ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
|
||||
// let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
|
||||
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
||||
}
|
||||
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Literal::Atom(*name),
|
||||
terms.len(),
|
||||
)),
|
||||
}?,
|
||||
}?,*/
|
||||
Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
|
||||
Term::Cons(..) | Term::PartialString(..) => {
|
||||
Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => {
|
||||
return Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Literal::Atom(atom!(".")),
|
||||
2,
|
||||
@@ -107,29 +110,26 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
||||
while let Some(iter_state) = self.state_stack.pop() {
|
||||
match iter_state {
|
||||
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();
|
||||
|
||||
if child_num == arity {
|
||||
return Some(Ok(ArithTermRef::Op(ct.name(), arity)));
|
||||
return Some(Ok(ArithTermRef::Op(name, arity)));
|
||||
} else {
|
||||
self.state_stack.push(TermIterState::Clause(
|
||||
lvl,
|
||||
child_num + 1,
|
||||
cell,
|
||||
ct,
|
||||
name,
|
||||
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::Var(lvl, cell, var) => {
|
||||
// the expression is the second argument of an
|
||||
// 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(Ok(ArithTermRef::Var(lvl, cell, var.clone())));
|
||||
}
|
||||
_ => {
|
||||
return Some(Err(ArithmeticError::NonEvaluableFunctor(
|
||||
@@ -145,8 +145,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ArithmeticEvaluator<'a, TermMarker> {
|
||||
marker: &'a mut TermMarker,
|
||||
pub(crate) struct ArithmeticEvaluator<'a> {
|
||||
marker: &'a mut DebrayAllocator,
|
||||
interm: Vec<ArithmeticTerm>,
|
||||
interm_c: usize,
|
||||
}
|
||||
@@ -169,16 +169,16 @@ fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), Ari
|
||||
match c {
|
||||
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
|
||||
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
|
||||
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(***n))),
|
||||
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))),
|
||||
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
|
||||
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
|
||||
Number::Float(OrderedFloat(f64::consts::E)),
|
||||
Number::Float(OrderedFloat(std::f64::consts::E))
|
||||
)),
|
||||
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(
|
||||
Number::Float(OrderedFloat(f64::EPSILON)),
|
||||
Number::Float(OrderedFloat(std::f64::EPSILON))
|
||||
)),
|
||||
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
|
||||
}
|
||||
@@ -186,8 +186,8 @@ fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), Ari
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
|
||||
pub(crate) fn new(marker: &'a mut TermMarker, target_int: usize) -> Self {
|
||||
impl<'a> ArithmeticEvaluator<'a> {
|
||||
pub(crate) fn new(marker: &'a mut DebrayAllocator, target_int: usize) -> Self {
|
||||
ArithmeticEvaluator {
|
||||
marker,
|
||||
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,
|
||||
src: &'a Term,
|
||||
term_loc: GenContext,
|
||||
arg: usize,
|
||||
) -> Result<ArithCont, ArithmeticError>
|
||||
{
|
||||
let mut code = vec![];
|
||||
@@ -328,17 +329,15 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
|
||||
match term_ref? {
|
||||
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
|
||||
ArithTermRef::Var(lvl, cell, name) => {
|
||||
let r = if cell.get().norm().reg_num() == 0 {
|
||||
let mut getter = || {
|
||||
use crate::targets::QueryInstruction;
|
||||
|
||||
loop {
|
||||
match self.marker.bindings().get(&name) {
|
||||
Some(&VarData::Temp(_, t, _)) if t != 0 =>
|
||||
return RegType::Temp(t),
|
||||
Some(&VarData::Perm(p)) if p != 0 =>
|
||||
return RegType::Perm(p),
|
||||
_ => {
|
||||
let r = if lvl == Level::Shallow {
|
||||
self.marker.mark_non_callable(
|
||||
name.clone(),
|
||||
arg,
|
||||
term_loc,
|
||||
cell,
|
||||
&mut code,
|
||||
)
|
||||
} else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
|
||||
self.marker.mark_var::<QueryInstruction>(
|
||||
name.clone(),
|
||||
lvl,
|
||||
@@ -346,15 +345,8 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
|
||||
term_loc,
|
||||
&mut code,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getter()
|
||||
/*
|
||||
_ => return Err(ArithmeticError::UninstantiatedVar),
|
||||
*/
|
||||
self.marker.get_binding(&name).unwrap()
|
||||
} else {
|
||||
cell.get().norm()
|
||||
};
|
||||
@@ -374,17 +366,39 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
|
||||
// integer division rounding function -- 9.1.3.1.
|
||||
pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number {
|
||||
match n {
|
||||
&Number::Integer(_) | &Number::Fixnum(_) => *n,
|
||||
&Number::Float(OrderedFloat(f)) => fixnum!(Number, f.floor() as i64, arena),
|
||||
&Number::Integer(i) => {
|
||||
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) => {
|
||||
let r_ref = r.fract_floor_ref();
|
||||
let (mut fract, mut floor) = (Rational::new(), Integer::new());
|
||||
(&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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Fixnum> for Integer {
|
||||
#[inline]
|
||||
@@ -404,23 +418,14 @@ pub(crate) fn rnd_f(n: &Number) -> f64 {
|
||||
}
|
||||
|
||||
// floating point result function -- 9.1.4.2.
|
||||
pub(crate) fn result_f<Round>(n: &Number, round: Round) -> Result<f64, EvalError>
|
||||
where
|
||||
Round: Fn(&Number) -> f64,
|
||||
{
|
||||
let f = rnd_f(n);
|
||||
classify_float(f, round)
|
||||
pub(crate) fn result_f(n: &Number) -> Result<f64, EvalError> {
|
||||
classify_float(rnd_f(n))
|
||||
}
|
||||
|
||||
fn classify_float<Round>(f: f64, round: Round) -> Result<f64, EvalError>
|
||||
where
|
||||
Round: Fn(&Number) -> f64,
|
||||
{
|
||||
fn classify_float(f: f64) -> Result<f64, EvalError> {
|
||||
match f.classify() {
|
||||
FpCategory::Normal | FpCategory::Zero => Ok(round(&Number::Float(OrderedFloat(f)))),
|
||||
FpCategory::Normal | FpCategory::Zero => Ok(f),
|
||||
FpCategory::Infinite => {
|
||||
let f = round(&Number::Float(OrderedFloat(f)));
|
||||
|
||||
if OrderedFloat(f) == OrderedFloat(f64::MAX) {
|
||||
Ok(f)
|
||||
} else {
|
||||
@@ -428,33 +433,33 @@ where
|
||||
}
|
||||
}
|
||||
FpCategory::Nan => Err(EvalError::Undefined),
|
||||
_ => Ok(round(&Number::Float(OrderedFloat(f)))),
|
||||
_ => Ok(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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]
|
||||
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]
|
||||
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]
|
||||
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]
|
||||
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]
|
||||
@@ -462,7 +467,7 @@ fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||
if FpCategory::Zero == f2.classify() {
|
||||
Err(EvalError::ZeroDivisor)
|
||||
} 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,
|
||||
(HeapCellValueTag::Cons, c) => {
|
||||
match_untyped_arena_ptr!(c,
|
||||
(ArenaHeaderTag::F64, n) => {
|
||||
Ok(Number::Float(*n))
|
||||
}
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
Ok(Number::Integer(n))
|
||||
}
|
||||
@@ -687,7 +689,7 @@ impl TryFrom<HeapCellValue> for Number {
|
||||
)
|
||||
}
|
||||
(HeapCellValueTag::F64, n) => {
|
||||
Ok(Number::Float(**n))
|
||||
Ok(Number::Float(*n))
|
||||
}
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
Ok(Number::Fixnum(n))
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
fn main() {
|
||||
use nix::sys::signal;
|
||||
use std::sync::atomic::Ordering;
|
||||
use scryer_prolog::*;
|
||||
|
||||
let handler = signal::SigHandler::Handler(handle_sigint);
|
||||
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
|
||||
ctrlc::set_handler(move || {
|
||||
scryer_prolog::machine::INTERRUPT.store(true, Ordering::Relaxed);
|
||||
}).unwrap();
|
||||
|
||||
let mut wam = machine::Machine::new();
|
||||
|
||||
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::arithmetic::*;
|
||||
use crate::debray_allocator::*;
|
||||
use crate::fixtures::*;
|
||||
use crate::forms::*;
|
||||
use crate::indexing::*;
|
||||
@@ -195,12 +196,22 @@ impl CodeGenSettings {
|
||||
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)]
|
||||
pub(crate) struct CodeGenerator<'a, TermMarker> {
|
||||
pub(crate) struct CodeGenerator<'a> {
|
||||
pub(crate) atom_tbl: &'a mut AtomTable,
|
||||
marker: TermMarker,
|
||||
marker: DebrayAllocator,
|
||||
pub(crate) var_count: IndexMap<Rc<String>, usize>,
|
||||
settings: CodeGenSettings,
|
||||
pub(crate) skeleton: PredicateSkeleton,
|
||||
@@ -208,11 +219,76 @@ pub(crate) struct CodeGenerator<'a, TermMarker> {
|
||||
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 {
|
||||
CodeGenerator {
|
||||
atom_tbl,
|
||||
marker: Allocator::new(),
|
||||
marker: DebrayAllocator::new(),
|
||||
var_count: IndexMap::new(),
|
||||
settings,
|
||||
skeleton: PredicateSkeleton::new(),
|
||||
@@ -234,45 +310,6 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
*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)
|
||||
where
|
||||
Target: crate::targets::CompilationTarget<'a>,
|
||||
@@ -316,9 +353,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
&Term::AnonVar => {
|
||||
Self::add_or_increment_void_instr::<Target>(target);
|
||||
}
|
||||
&Term::Cons(ref cell, ..)
|
||||
| &Term::Clause(ref cell, ..)
|
||||
| Term::PartialString(ref cell, ..) => {
|
||||
&Term::Cons(ref cell, ..) |
|
||||
&Term::Clause(ref cell, ..) |
|
||||
Term::PartialString(ref cell, ..) |
|
||||
Term::CompleteString(ref cell, ..) => {
|
||||
self.marker.mark_non_var::<Target>(Level::Deep, term_loc, cell, target);
|
||||
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);
|
||||
}
|
||||
}
|
||||
TermRef::Clause(lvl, cell, ct, terms) => {
|
||||
TermRef::Clause(lvl, cell, name, terms) => {
|
||||
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 {
|
||||
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) => {
|
||||
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, string, cell.get(), true));
|
||||
target.push(Target::to_pstr(lvl, atom, cell.get(), true));
|
||||
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() == "!" => {
|
||||
if self.marker.is_unbound(var.clone()) {
|
||||
@@ -397,6 +442,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
perm_v!(1),
|
||||
false,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -430,7 +476,6 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
};
|
||||
|
||||
self.update_var_count(chunked_term.post_order_iter());
|
||||
|
||||
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());
|
||||
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));
|
||||
}
|
||||
&QueryTerm::Clause(_, ref ct, _, false) => {
|
||||
&QueryTerm::Clause(_, ref ct, _, CallPolicy::Counted) => {
|
||||
code.push(call_clause!(ct.clone(), pvs));
|
||||
}
|
||||
_ => {}
|
||||
@@ -501,35 +546,39 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
&InlinedClauseType::CompareNumber(mut cmp) => {
|
||||
self.marker.reset_arg(2);
|
||||
|
||||
let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc)?;
|
||||
let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc)?;
|
||||
let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc, 1)?;
|
||||
|
||||
let at_1 = if let &Term::Var(ref vr, ref name) = &terms[0] {
|
||||
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 1, term_loc, vr, code))
|
||||
} else {
|
||||
at_1.unwrap_or(interm!(1))
|
||||
};
|
||||
if !matches!(terms[0], Term::Var(..)) {
|
||||
self.marker.advance_arg();
|
||||
}
|
||||
|
||||
let at_2 = if let &Term::Var(ref vr, ref name) = &terms[1] {
|
||||
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code))
|
||||
} else {
|
||||
at_2.unwrap_or(interm!(2))
|
||||
};
|
||||
let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc, 2)?;
|
||||
|
||||
code.append(&mut lcode);
|
||||
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));
|
||||
}
|
||||
&InlinedClauseType::IsAtom(..) => match &terms[0] {
|
||||
&Term::Literal(_, Literal::Char(_))
|
||||
| &Term::Literal(_, Literal::Atom(atom!("[]")))
|
||||
| &Term::Literal(_, Literal::Atom(..)) => {
|
||||
&Term::Literal(_, Literal::Char(_)) |
|
||||
&Term::Literal(_, Literal::Atom(atom!("[]"))) |
|
||||
&Term::Literal(_, Literal::Atom(..)) => {
|
||||
code.push(instr!("$succeed", 0));
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
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));
|
||||
}
|
||||
_ => {
|
||||
@@ -537,7 +586,11 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
}
|
||||
},
|
||||
&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));
|
||||
}
|
||||
&Term::Literal(_, Literal::String(_)) => {
|
||||
@@ -548,18 +601,37 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
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));
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsCompound(..) => match &terms[0] {
|
||||
&Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) |
|
||||
&Term::Clause(..) |
|
||||
&Term::Cons(..) |
|
||||
&Term::PartialString(..) |
|
||||
&Term::CompleteString(..) |
|
||||
&Term::Literal(_, Literal::String(..)) => {
|
||||
code.push(instr!("$succeed", 0));
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
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));
|
||||
}
|
||||
_ => {
|
||||
@@ -572,7 +644,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
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));
|
||||
}
|
||||
_ => {
|
||||
@@ -585,7 +657,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
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));
|
||||
}
|
||||
_ => {
|
||||
@@ -593,15 +673,23 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsNumber(..) => match &terms[0] {
|
||||
&Term::Literal(_, Literal::Float(_))
|
||||
| &Term::Literal(_, Literal::Rational(_))
|
||||
| &Term::Literal(_, Literal::Integer(_))
|
||||
| &Term::Literal(_, Literal::Fixnum(_)) => {
|
||||
&Term::Literal(_, Literal::Float(_)) |
|
||||
&Term::Literal(_, Literal::Rational(_)) |
|
||||
&Term::Literal(_, Literal::Integer(_)) |
|
||||
&Term::Literal(_, Literal::Fixnum(_)) => {
|
||||
code.push(instr!("$succeed", 0));
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
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));
|
||||
}
|
||||
_ => {
|
||||
@@ -614,7 +702,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
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));
|
||||
}
|
||||
_ => {
|
||||
@@ -622,12 +718,21 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
}
|
||||
},
|
||||
&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));
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
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));
|
||||
}
|
||||
_ => {
|
||||
@@ -635,10 +740,11 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
}
|
||||
},
|
||||
&InlinedClauseType::IsVar(..) => match &terms[0] {
|
||||
&Term::Literal(..)
|
||||
| &Term::Clause(..)
|
||||
| &Term::Cons(..)
|
||||
| &Term::PartialString(..) => {
|
||||
&Term::Literal(..) |
|
||||
&Term::Clause(..) |
|
||||
&Term::Cons(..) |
|
||||
&Term::PartialString(..) |
|
||||
&Term::CompleteString(..) => {
|
||||
code.push(instr!("$fail", 0));
|
||||
}
|
||||
&Term::AnonVar => {
|
||||
@@ -646,7 +752,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
}
|
||||
&Term::Var(ref vr, ref name) => {
|
||||
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));
|
||||
}
|
||||
},
|
||||
@@ -660,9 +774,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
term: &Term,
|
||||
target_int: usize,
|
||||
term_loc: GenContext,
|
||||
arg: usize,
|
||||
) -> Result<ArithCont, ArithmeticError> {
|
||||
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(
|
||||
@@ -670,11 +785,11 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
terms: &Vec<Term>,
|
||||
code: &mut Code,
|
||||
term_loc: GenContext,
|
||||
use_default_call_policy: bool,
|
||||
call_policy: CallPolicy,
|
||||
) -> Result<(), CompilationError> {
|
||||
macro_rules! compile_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());
|
||||
at
|
||||
});
|
||||
@@ -712,7 +827,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
|
||||
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));
|
||||
} else {
|
||||
code.push(instr!("is", temp_v!(1), at, 0));
|
||||
@@ -774,8 +889,8 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
_,
|
||||
ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
|
||||
ref terms,
|
||||
use_default_call_policy,
|
||||
) => self.compile_is_call(terms, code, term_loc, use_default_call_policy)?,
|
||||
call_policy,
|
||||
) => self.compile_is_call(terms, code, term_loc, call_policy)?,
|
||||
&QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => {
|
||||
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);
|
||||
|
||||
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 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();
|
||||
|
||||
if !fact.is_empty() {
|
||||
@@ -893,7 +1016,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
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));
|
||||
|
||||
let mut vs = VariableFixtures::new();
|
||||
@@ -915,6 +1038,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
false,
|
||||
);
|
||||
|
||||
if self.marker.max_reg_allocated() > MAX_ARITY {
|
||||
return Err(CompilationError::ExceededMaxArity);
|
||||
}
|
||||
|
||||
self.mark_unsafe_fact_vars(&mut compiled_fact);
|
||||
|
||||
if !compiled_fact.is_empty() {
|
||||
@@ -923,7 +1050,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
}
|
||||
|
||||
code.push(instr!("proceed"));
|
||||
code
|
||||
Ok(code)
|
||||
}
|
||||
|
||||
fn compile_query_line(
|
||||
@@ -939,10 +1066,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
let iter = query_term_post_order_iter(term);
|
||||
let query = self.compile_target::<QueryInstruction, _>(iter, term_loc, is_exposed);
|
||||
|
||||
if !query.is_empty() {
|
||||
code.extend(query.into_iter());
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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)?,
|
||||
};
|
||||
|
||||
if clauses.len() > 1 {
|
||||
let choice = match i {
|
||||
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(),
|
||||
_ => 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();
|
||||
}
|
||||
|
||||
let arg = match clause.args() {
|
||||
Some(args) => match args.iter().nth(optimal_index) {
|
||||
Some(term) => Some(term),
|
||||
None => None,
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
let arg = clause.args().and_then(|args| args.iter().nth(optimal_index));
|
||||
|
||||
if let Some(arg) = arg {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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.skeleton.clauses.push_back(clause_index_info);
|
||||
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;
|
||||
|
||||
if !index_code.is_empty() {
|
||||
@@ -1147,7 +1281,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
|
||||
if self.settings.is_extensible {
|
||||
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_start_offset + 2 * (segment_is_indexed as usize);
|
||||
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,
|
||||
var: &String,
|
||||
lvl: Level,
|
||||
term_loc: GenContext,
|
||||
target: &mut Vec<Instruction>,
|
||||
) -> usize
|
||||
where
|
||||
Target: CompilationTarget<'a>,
|
||||
{
|
||||
) -> usize {
|
||||
match term_loc {
|
||||
GenContext::Head => {
|
||||
if let Level::Shallow = lvl {
|
||||
@@ -404,4 +401,9 @@ impl Allocator for DebrayAllocator {
|
||||
self.arg_c = 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 ordered_float::OrderedFloat;
|
||||
|
||||
use slice_deque::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::ops::AddAssign;
|
||||
@@ -58,7 +57,7 @@ impl AppendOrPrepend {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Level {
|
||||
Deep,
|
||||
Root,
|
||||
@@ -74,10 +73,16 @@ impl Level {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum CallPolicy {
|
||||
Default,
|
||||
Counted,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum QueryTerm {
|
||||
// register, clause type, subterms, use default call policy.
|
||||
Clause(Cell<RegType>, ClauseType, Vec<Term>, bool),
|
||||
// register, clause type, subterms, clause call policy.
|
||||
Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
|
||||
BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q.
|
||||
UnblockedCut(Cell<VarReg>),
|
||||
GetLevelAndUnify(Cell<VarReg>, Rc<String>),
|
||||
@@ -85,9 +90,9 @@ pub enum QueryTerm {
|
||||
}
|
||||
|
||||
impl QueryTerm {
|
||||
pub(crate) fn set_default_caller(&mut self) {
|
||||
pub(crate) fn set_call_policy(&mut self, cp: CallPolicy) {
|
||||
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 {
|
||||
fn name(&self) -> Option<Atom> {
|
||||
//, atom_tbl: &AtomTable) -> Option<StringBuffer> {
|
||||
match self {
|
||||
Term::Clause(_, name, terms) => {
|
||||
// let str_buf = StringBuffer::from(*name, atom_tbl);
|
||||
|
||||
match name.as_str() {
|
||||
// str_buf.as_str() {
|
||||
":-" => {
|
||||
match name {
|
||||
atom!(":-") => {
|
||||
match terms.len() {
|
||||
1 => None, // a declaration.
|
||||
2 => terms[0].name(), //.map(|name| StringBuffer::from(name, atom_tbl)),
|
||||
2 => terms[0].name(),
|
||||
_ => Some(*name),
|
||||
}
|
||||
}
|
||||
_ => 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,
|
||||
}
|
||||
}
|
||||
@@ -267,6 +269,7 @@ pub enum MetaSpec {
|
||||
Minus,
|
||||
Plus,
|
||||
Either,
|
||||
Colon,
|
||||
RequiresExpansionWithArgument(usize),
|
||||
}
|
||||
|
||||
@@ -363,6 +366,18 @@ pub enum 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]
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
@@ -607,7 +622,7 @@ impl ArenaFrom<Number> for Literal {
|
||||
match value {
|
||||
Number::Fixnum(n) => Literal::Fixnum(n),
|
||||
Number::Integer(n) => Literal::Integer(n),
|
||||
Number::Float(f) => Literal::Float(arena_alloc!(f, arena)),
|
||||
Number::Float(OrderedFloat(f)) => Literal::from(float_alloc!(f, arena)),
|
||||
Number::Rational(r) => Literal::Rational(r),
|
||||
}
|
||||
}
|
||||
@@ -619,13 +634,29 @@ impl ArenaFrom<Number> for HeapCellValue {
|
||||
match value {
|
||||
Number::Fixnum(n) => fixnum_as_cell!(n),
|
||||
Number::Integer(n) => typed_arena_ptr_as_cell!(n),
|
||||
Number::Float(n) => typed_arena_ptr_as_cell!(arena_alloc!(n, arena)),
|
||||
Number::Float(OrderedFloat(n)) => HeapCellValue::from(float_alloc!(n, arena)),
|
||||
Number::Rational(n) => typed_arena_ptr_as_cell!(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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]
|
||||
pub(crate) fn is_positive(&self) -> bool {
|
||||
match self {
|
||||
@@ -791,7 +822,7 @@ pub(crate) struct LocalPredicateSkeleton {
|
||||
pub(crate) is_discontiguous: bool,
|
||||
pub(crate) is_dynamic: 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) retracted_dynamic_clauses: Option<Vec<ClauseIndexInfo>>, // always None if non-dynamic.
|
||||
}
|
||||
@@ -803,7 +834,7 @@ impl LocalPredicateSkeleton {
|
||||
is_discontiguous: false,
|
||||
is_dynamic: false,
|
||||
is_multifile: false,
|
||||
clause_clause_locs: sdeq![],
|
||||
clause_clause_locs: VecDeque::new(),
|
||||
clause_assert_margin: 0,
|
||||
retracted_dynamic_clauses: Some(vec![]),
|
||||
}
|
||||
@@ -844,7 +875,7 @@ impl LocalPredicateSkeleton {
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct PredicateSkeleton {
|
||||
pub(crate) core: LocalPredicateSkeleton,
|
||||
pub(crate) clauses: SliceDeque<ClauseIndexInfo>,
|
||||
pub(crate) clauses: VecDeque<ClauseIndexInfo>,
|
||||
}
|
||||
|
||||
impl PredicateSkeleton {
|
||||
@@ -852,7 +883,7 @@ impl PredicateSkeleton {
|
||||
pub(crate) fn new() -> Self {
|
||||
PredicateSkeleton {
|
||||
core: LocalPredicateSkeleton::new(),
|
||||
clauses: sdeq![],
|
||||
clauses: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,18 +899,22 @@ impl PredicateSkeleton {
|
||||
}
|
||||
|
||||
pub(crate) fn target_pos_of_clause_clause_loc(
|
||||
&self,
|
||||
&mut self,
|
||||
clause_clause_loc: 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));
|
||||
|
||||
match search_result {
|
||||
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))
|
||||
.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};
|
||||
use crate::machine::heap::*;
|
||||
|
||||
@@ -9,6 +10,49 @@ use modular_bitfield::prelude::*;
|
||||
use std::ops::Deref;
|
||||
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]
|
||||
fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) {
|
||||
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)]
|
||||
pub struct StackfulPreOrderHeapIter<'a> {
|
||||
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> {
|
||||
#[inline]
|
||||
fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
|
||||
@@ -86,11 +121,11 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
||||
#[inline]
|
||||
pub fn stack_last(&self) -> Option<usize> {
|
||||
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 cell = self.heap[h];
|
||||
|
||||
if cell.get_forwarding_bit() == Some(true) {
|
||||
if cell.get_forwarding_bit() {
|
||||
return Some(h);
|
||||
} else if cell.get_mark_bit() && !is_readable_marked {
|
||||
continue;
|
||||
@@ -102,26 +137,16 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn stack_is_empty(&self) -> bool {
|
||||
self.stack.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn focus(&self) -> usize {
|
||||
self.h
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pop_stack(&mut self) -> Option<HeapCellValue> {
|
||||
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;
|
||||
self.h = h;
|
||||
|
||||
let cell = &mut self.heap[h];
|
||||
|
||||
if cell.get_forwarding_bit() == Some(true) {
|
||||
if cell.get_forwarding_bit() {
|
||||
cell.set_forwarding_bit(false);
|
||||
} else if cell.get_mark_bit() && !is_readable_marked {
|
||||
cell.set_mark_bit(false);
|
||||
@@ -143,13 +168,23 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
||||
|
||||
fn follow(&mut self) -> Option<HeapCellValue> {
|
||||
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;
|
||||
|
||||
self.h = h;
|
||||
let cell = &mut self.heap[h];
|
||||
|
||||
if cell.get_forwarding_bit() == Some(true) {
|
||||
if cell.get_forwarding_bit() {
|
||||
let copy = *cell;
|
||||
cell.set_forwarding_bit(false);
|
||||
return Some(copy);
|
||||
@@ -159,23 +194,23 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
||||
}
|
||||
|
||||
read_heap_cell!(*cell,
|
||||
(HeapCellValueTag::Str, vh) => {
|
||||
self.stack.push(IterStackLoc::iterable_heap_loc(vh));
|
||||
(HeapCellValueTag::Str | HeapCellValueTag::PStrLoc, vh) => {
|
||||
self.push_if_unmarked(vh);
|
||||
self.stack.push(IterStackLoc::mark_heap_loc(vh));
|
||||
}
|
||||
(HeapCellValueTag::Lis, vh) => {
|
||||
self.push_if_unmarked(vh);
|
||||
|
||||
self.stack.push(IterStackLoc::iterable_heap_loc(vh + 1));
|
||||
forward_if_referent_marked(&mut self.heap, vh + 1);
|
||||
|
||||
self.stack.push(IterStackLoc::pending_mark_heap_loc(vh + 1));
|
||||
self.stack.push(IterStackLoc::mark_heap_loc(vh));
|
||||
|
||||
forward_if_referent_marked(&mut self.heap, vh);
|
||||
|
||||
return Some(self.heap[h]);
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | HeapCellValueTag::Var, vh) => {
|
||||
self.push_if_unmarked(h);
|
||||
self.stack.push(IterStackLoc::iterable_heap_loc(vh));
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, vh) => {
|
||||
self.push_if_unmarked(vh);
|
||||
self.stack.push(IterStackLoc::mark_heap_loc(vh));
|
||||
forward_if_referent_marked(&mut self.heap, vh);
|
||||
}
|
||||
(HeapCellValueTag::PStrOffset, offset) => {
|
||||
@@ -187,19 +222,20 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
||||
(HeapCellValueTag::PStr) => {
|
||||
self.push_if_unmarked(h);
|
||||
|
||||
forward_if_referent_marked(&mut self.heap, h+1);
|
||||
self.stack.push(IterStackLoc::iterable_heap_loc(h+1));
|
||||
forward_if_referent_marked(&mut self.heap, h+1);
|
||||
|
||||
return Some(self.heap[h]);
|
||||
}
|
||||
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||
if arity > 0 {
|
||||
self.push_if_unmarked(h);
|
||||
for h in (h + 2 .. h + arity + 1).rev() {
|
||||
self.stack.push(IterStackLoc::pending_mark_heap_loc(h));
|
||||
}
|
||||
|
||||
for h in (h + 1 .. h + arity + 1).rev() {
|
||||
forward_if_referent_marked(&mut self.heap, h);
|
||||
self.stack.push(IterStackLoc::iterable_heap_loc(h));
|
||||
if arity > 0 {
|
||||
self.push_if_unmarked(h+1);
|
||||
self.stack.push(IterStackLoc::mark_heap_loc(h+1));
|
||||
forward_if_referent_marked(&mut self.heap, h+1);
|
||||
}
|
||||
|
||||
return Some(self.heap[h]);
|
||||
@@ -223,12 +259,13 @@ impl<'a> Iterator for StackfulPreOrderHeapIter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[inline(always)]
|
||||
pub(crate) fn stackless_preorder_iter(
|
||||
heap: &mut Vec<HeapCellValue>,
|
||||
cell: HeapCellValue,
|
||||
) -> StacklessPreOrderHeapIter<IteratorUMP> {
|
||||
StacklessPreOrderHeapIter::new(heap, cell)
|
||||
StacklessPreOrderHeapIter::<IteratorUMP>::new(heap, cell)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -240,13 +277,14 @@ pub(crate) fn stackful_preorder_iter(
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PostOrderIterator<Iter: Iterator<Item = HeapCellValue>> {
|
||||
pub(crate) struct PostOrderIterator<Iter: FocusedHeapIter> {
|
||||
focus: usize,
|
||||
base_iter: Iter,
|
||||
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;
|
||||
|
||||
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 {
|
||||
PostOrderIterator {
|
||||
focus: 0,
|
||||
base_iter,
|
||||
base_iter_valid: true,
|
||||
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;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
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 {
|
||||
self.focus = focus;
|
||||
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 let Some(item) = self.base_iter.next() {
|
||||
let focus = self.base_iter.focus();
|
||||
|
||||
read_heap_cell!(item,
|
||||
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||
self.parent_stack.push((arity, item));
|
||||
self.parent_stack.push((arity, item, focus));
|
||||
}
|
||||
(HeapCellValueTag::Lis) => {
|
||||
self.parent_stack.push((2, item));
|
||||
self.parent_stack.push((2, item, focus));
|
||||
}
|
||||
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
||||
self.parent_stack.push((1, item));
|
||||
self.parent_stack.push((1, item, focus));
|
||||
}
|
||||
_ => {
|
||||
self.focus = focus;
|
||||
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>>;
|
||||
|
||||
impl<'a> LeftistPostOrderHeapIter<'a> {
|
||||
#[inline]
|
||||
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 {
|
||||
self.base_iter.pop_stack();
|
||||
}
|
||||
@@ -335,9 +406,11 @@ pub(crate) fn stackful_post_order_iter<'a>(
|
||||
PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, cell))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) type RightistPostOrderHeapIter<'a> =
|
||||
PostOrderIterator<StacklessPreOrderHeapIter<'a, IteratorUMP>>;
|
||||
|
||||
#[cfg(test)]
|
||||
#[inline]
|
||||
pub(crate) fn stackless_post_order_iter<'a>(
|
||||
heap: &'a mut Heap,
|
||||
@@ -351,6 +424,7 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::machine::mock_wam::*;
|
||||
|
||||
|
||||
#[test]
|
||||
fn heap_stackless_iter_tests() {
|
||||
let mut wam = MockWAM::new();
|
||||
@@ -513,6 +587,7 @@ mod tests {
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
atom_as_cell!(b_atom)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
atom_as_cell!(a_atom)
|
||||
@@ -574,7 +649,7 @@ mod tests {
|
||||
heap_loc_as_cell!(1),
|
||||
);
|
||||
|
||||
assert_eq!(iter.next(), None);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
|
||||
assert_eq!(wam.machine_st.heap[0], pstr_cell);
|
||||
@@ -601,7 +676,7 @@ mod tests {
|
||||
heap_loc_as_cell!(3),
|
||||
);
|
||||
|
||||
assert_eq!(iter.next(), None);
|
||||
assert!(iter.next().is_none());
|
||||
}
|
||||
|
||||
assert_eq!(wam.machine_st.heap[0], pstr_cell);
|
||||
@@ -623,8 +698,8 @@ mod tests {
|
||||
let pstr_offset_cell = pstr_offset_as_cell!(0);
|
||||
|
||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
|
||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
|
||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
|
||||
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
|
||||
|
||||
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[1], 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]
|
||||
@@ -1271,7 +1382,7 @@ mod tests {
|
||||
.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!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
@@ -1302,7 +1413,7 @@ mod tests {
|
||||
));
|
||||
|
||||
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!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
@@ -1425,7 +1536,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
list_loc_as_cell!(1)
|
||||
heap_loc_as_cell!(0)
|
||||
);
|
||||
|
||||
assert_eq!(iter.next(), None);
|
||||
@@ -1669,7 +1780,9 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut link_back = list_loc_as_cell!(1);
|
||||
|
||||
link_back.set_forwarding_bit(true);
|
||||
link_back.set_mark_bit(true);
|
||||
|
||||
assert_eq!(iter.next().unwrap(), link_back);
|
||||
|
||||
@@ -1691,9 +1804,14 @@ mod tests {
|
||||
);
|
||||
|
||||
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!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
list_loc_as_cell!(1)
|
||||
@@ -1757,11 +1875,11 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
str_loc_as_cell!(1)
|
||||
heap_loc_as_cell!(0)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
iter.next().unwrap(),
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
atom_as_cell!(atom!("y"))
|
||||
);
|
||||
|
||||
@@ -1781,7 +1899,7 @@ mod tests {
|
||||
.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!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
@@ -1812,7 +1930,7 @@ mod tests {
|
||||
));
|
||||
|
||||
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!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
@@ -1929,7 +2047,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
list_loc_as_cell!(1)
|
||||
heap_loc_as_cell!(0)
|
||||
);
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
@@ -2157,7 +2275,9 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut link_back = list_loc_as_cell!(1);
|
||||
|
||||
link_back.set_forwarding_bit(true);
|
||||
link_back.set_mark_bit(true);
|
||||
|
||||
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));
|
||||
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
heap_loc_as_cell!(1)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
unmark_cell_bits!(iter.next().unwrap()),
|
||||
heap_loc_as_cell!(0)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::instructions::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::rug::{Integer, Rational};
|
||||
use crate::{
|
||||
@@ -116,7 +115,6 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
||||
let mut parent_spec = DirectedOp::Left(atom!("-"), OpDesc::build_with(200, FY as u8));
|
||||
|
||||
loop {
|
||||
// match self.machine_st.store(self.machine_st.deref(addr)) {
|
||||
read_heap_cell!(self.heap[h],
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
read_heap_cell!(self.heap[s],
|
||||
@@ -156,7 +154,6 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// let addr = self.machine_st.store(self.machine_st.deref(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{08}' if is_quoted => "\\b".to_string(), // UTF-8 backspace
|
||||
'\u{07}' if is_quoted => "\\a".to_string(), // UTF-8 alert
|
||||
'"' if is_quoted => "\\\"".to_string(),
|
||||
'\\' if is_quoted => "\\\\".to_string(),
|
||||
'\'' | '\n' | '\r' | '\t' | '\u{0b}' | '\u{0c}' | '\u{08}' | '\u{07}' | '"' | '\\' => {
|
||||
c.to_string()
|
||||
}
|
||||
'\u{a0}'..='\u{d6}' => c.to_string(),
|
||||
'\u{d8}'..='\u{f6}' => c.to_string(),
|
||||
'\u{f8}'..='\u{74f}' => c.to_string(),
|
||||
'\x20'..='\x7e' => c.to_string(),
|
||||
_ => format!("\\x{:x}\\", c as u32),
|
||||
'\u{0}'..='\u{1f}' => format!("\\x{:x}\\", c as u32), // print all other control characters in hex.
|
||||
_ => c.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,9 +201,10 @@ enum TokenOrRedirect {
|
||||
Op(Atom, OpDesc),
|
||||
NumberedVar(String),
|
||||
CompositeRedirect(usize, DirectedOp),
|
||||
CurlyBracketRedirect(usize),
|
||||
FunctorRedirect(usize),
|
||||
#[allow(unused)] IpAddr(IpAddr),
|
||||
NumberFocus(NumberFocus, Option<DirectedOp>),
|
||||
NumberFocus(usize, NumberFocus, Option<DirectedOp>),
|
||||
Open,
|
||||
Close,
|
||||
Comma,
|
||||
@@ -382,9 +376,9 @@ impl HCValueOutputter for PrinterOutputter {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool {
|
||||
arity == 1 && ct.name().as_str() == "$VAR"
|
||||
#[inline(always)]
|
||||
fn is_numbered_var(name: Atom, arity: usize) -> bool {
|
||||
arity == 1 && name == atom!("$VAR")
|
||||
}
|
||||
|
||||
#[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 {
|
||||
($self:ident, $c:expr) => {{
|
||||
$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)]
|
||||
pub struct HCPrinter<'a, Outputter> {
|
||||
outputter: Outputter,
|
||||
iter: StackfulPreOrderHeapIter<'a>,
|
||||
arena: &'a mut Arena,
|
||||
op_dir: &'a OpDir,
|
||||
state_stack: Vec<TokenOrRedirect>,
|
||||
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> {
|
||||
pub fn new(
|
||||
heap: &'a mut Heap,
|
||||
arena: &'a mut Arena,
|
||||
op_dir: &'a OpDir,
|
||||
output: Outputter,
|
||||
cell: HeapCellValue,
|
||||
@@ -524,7 +539,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
HCPrinter {
|
||||
outputter: output,
|
||||
iter: stackful_preorder_iter(heap, cell),
|
||||
arena,
|
||||
op_dir,
|
||||
state_stack: vec![],
|
||||
toplevel_spec: None,
|
||||
@@ -545,9 +559,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
requires_space(tail, atom)
|
||||
}
|
||||
|
||||
fn enqueue_op(&mut self, mut max_depth: usize, ct: ClauseType, spec: OpDesc) {
|
||||
let name = ct.name();
|
||||
|
||||
fn enqueue_op(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) {
|
||||
if is_postfix!(spec.get_spec()) {
|
||||
if self.check_max_depth(&mut max_depth) {
|
||||
self.iter.pop_stack();
|
||||
@@ -634,26 +646,30 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
self.iter.pop_stack();
|
||||
}
|
||||
|
||||
if arity > 0 {
|
||||
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(name));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if arity > 0 {
|
||||
self.state_stack.push(TokenOrRedirect::Close);
|
||||
|
||||
for _ in 0..arity {
|
||||
self.state_stack
|
||||
.push(TokenOrRedirect::FunctorRedirect(max_depth));
|
||||
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
|
||||
self.state_stack.push(TokenOrRedirect::Comma);
|
||||
}
|
||||
|
||||
self.state_stack.pop();
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::Open);
|
||||
}
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::Atom(name));
|
||||
|
||||
true
|
||||
@@ -672,8 +688,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
|
||||
let op = DirectedOp::Left(name, spec);
|
||||
|
||||
self.state_stack
|
||||
.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
|
||||
self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
|
||||
self.state_stack.push(TokenOrRedirect::Space);
|
||||
self.state_stack.push(TokenOrRedirect::Atom(name));
|
||||
}
|
||||
@@ -720,9 +735,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::RightCurly);
|
||||
self.state_stack
|
||||
.push(TokenOrRedirect::FunctorRedirect(max_depth));
|
||||
self.state_stack.push(TokenOrRedirect::CurlyBracketRedirect(max_depth));
|
||||
self.state_stack.push(TokenOrRedirect::LeftCurly);
|
||||
|
||||
true
|
||||
@@ -731,8 +746,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
fn format_numbered_vars(&mut self) -> bool {
|
||||
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
|
||||
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.state_stack.push(TokenOrRedirect::NumberedVar(var));
|
||||
return true;
|
||||
@@ -745,17 +766,16 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
&mut self,
|
||||
max_depth: usize,
|
||||
arity: usize,
|
||||
ct: ClauseType,
|
||||
name: Atom,
|
||||
op_desc: Option<OpDesc>,
|
||||
) -> bool {
|
||||
if self.numbervars && is_numbered_var(&ct, arity) {
|
||||
if self.numbervars && is_numbered_var(name, arity) {
|
||||
if self.format_numbered_vars() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
let dot_atom = atom!(".");
|
||||
let name = ct.name();
|
||||
|
||||
if let Some(spec) = op_desc {
|
||||
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 {
|
||||
self.enqueue_op(max_depth, ct, spec);
|
||||
self.enqueue_op(max_depth, name, spec);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return match (name.as_str(), arity) {
|
||||
("{}", 1) if !self.ignore_ops => self.format_curly_braces(max_depth),
|
||||
return match (name, arity) {
|
||||
(atom!("{}"), 1) if !self.ignore_ops => self.format_curly_braces(max_depth),
|
||||
_ => 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> {
|
||||
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(
|
||||
self.iter.heap,
|
||||
@@ -836,7 +856,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
None
|
||||
}
|
||||
var_opt => {
|
||||
if is_cyclic && addr.is_compound() {
|
||||
if is_cyclic && addr.is_compound(self.iter.heap) {
|
||||
// self-referential variables are marked "cyclic".
|
||||
match var_opt {
|
||||
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));
|
||||
}
|
||||
|
||||
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 {
|
||||
op.is_negative_sign() && !n.is_negative()
|
||||
} else {
|
||||
@@ -935,30 +955,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
|
||||
match n {
|
||||
NumberFocus::Unfocused(n) => match n {
|
||||
Number::Float(OrderedFloat(mut fl)) => {
|
||||
if OrderedFloat(fl) == -0f64 {
|
||||
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)
|
||||
};
|
||||
Number::Float(OrderedFloat(fl)) => {
|
||||
let output_str = fmt_float(fl);
|
||||
|
||||
push_space_if_amb!(self, &output_str, {
|
||||
append_str!(self, &output_str);
|
||||
});
|
||||
}
|
||||
Number::Rational(r) => {
|
||||
self.print_rational(r, add_brackets);
|
||||
return;
|
||||
self.print_rational(max_depth, r);
|
||||
}
|
||||
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)) {
|
||||
Some(op_desc) => {
|
||||
if add_brackets {
|
||||
self.state_stack.push(TokenOrRedirect::Close);
|
||||
if r.is_integer() {
|
||||
let output_str = format!("{}", r);
|
||||
|
||||
push_space_if_amb!(self, &output_str, {
|
||||
append_str!(self, &output_str);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let rdiv_ct = atom!("rdiv");
|
||||
@@ -1010,8 +1031,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
None
|
||||
};
|
||||
|
||||
if op_desc.get_prec() > 0 {
|
||||
if !self.ignore_ops && op_desc.get_prec() > 0 {
|
||||
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
||||
max_depth,
|
||||
NumberFocus::Denominator(r),
|
||||
left_directed_op,
|
||||
));
|
||||
@@ -1020,6 +1042,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
.push(TokenOrRedirect::Op(rdiv_ct, *op_desc));
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
||||
max_depth,
|
||||
NumberFocus::Numerator(r),
|
||||
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::NumberFocus(
|
||||
max_depth,
|
||||
NumberFocus::Denominator(r),
|
||||
None,
|
||||
));
|
||||
@@ -1034,6 +1058,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
self.state_stack.push(TokenOrRedirect::Comma);
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
||||
max_depth,
|
||||
NumberFocus::Numerator(r),
|
||||
None,
|
||||
));
|
||||
@@ -1076,10 +1101,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
push_char!(self, '"');
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1089,7 +1123,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
for c in iter.chars().take(max_depth) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1175,18 +1209,25 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
let pstr = cell_as_string!(self.iter.heap[h]);
|
||||
|
||||
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 value.get_tag() != HeapCellValueTag::CStr {
|
||||
if tag != HeapCellValueTag::PStrOffset && tag != HeapCellValueTag::CStr {
|
||||
self.iter.pop_stack();
|
||||
}
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
|
||||
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
|
||||
} else if end_cell != empty_list_as_cell!() {
|
||||
if value.get_tag() != HeapCellValueTag::CStr {
|
||||
self.iter.pop_stack();
|
||||
self.iter.push_stack(h+1);
|
||||
if tag == HeapCellValueTag::PStrOffset {
|
||||
self.iter.push_stack(end_h);
|
||||
}
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
|
||||
@@ -1264,9 +1305,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
max_depth: usize,
|
||||
) {
|
||||
let add_brackets = if !self.ignore_ops {
|
||||
negated_operand
|
||||
|| if let Some(ref op) = op {
|
||||
if self.numbervars && arity == 1 && name.as_str() == "$VAR" {
|
||||
negated_operand ||
|
||||
if let Some(ref op) = op {
|
||||
if self.numbervars && arity == 1 && name == atom!("$VAR") {
|
||||
!self.iter.immediate_leaf_has_property(|addr| {
|
||||
match Number::try_from(addr) {
|
||||
Ok(Number::Integer(n)) => &*n >= &0,
|
||||
@@ -1290,9 +1331,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
self.state_stack.push(TokenOrRedirect::Close);
|
||||
}
|
||||
|
||||
let ct = ClauseType::from(name, arity);
|
||||
|
||||
if self.format_clause(max_depth, arity, ct, Some(op_desc)) && add_brackets {
|
||||
if self.format_clause(max_depth, arity, name, Some(op_desc)) && add_brackets {
|
||||
self.state_stack.push(TokenOrRedirect::Open);
|
||||
|
||||
if let Some(ref op) = &op {
|
||||
@@ -1306,10 +1345,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
#[allow(dead_code)]
|
||||
fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) {
|
||||
let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() {
|
||||
(
|
||||
addr.ip(),
|
||||
Number::arena_from(addr.port() as usize, self.arena),
|
||||
)
|
||||
(addr.ip(), addr.port())
|
||||
} else {
|
||||
let disconnected_atom = atom!("$disconnected_tcp_listener");
|
||||
self.state_stack
|
||||
@@ -1327,7 +1363,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
self.state_stack.pop();
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
||||
NumberFocus::Unfocused(port),
|
||||
max_depth,
|
||||
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port as i64))),
|
||||
None,
|
||||
));
|
||||
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) {
|
||||
if let Some(alias) = stream.options().get_alias() {
|
||||
self.print_atom(alias);
|
||||
@@ -1395,8 +1457,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
);
|
||||
} else {
|
||||
push_space_if_amb!(self, name.as_str(), {
|
||||
let ct = ClauseType::from(name, arity);
|
||||
self.format_clause(max_depth, arity, ct, None);
|
||||
self.format_clause(max_depth, arity, name, None);
|
||||
});
|
||||
}
|
||||
} else if fetch_op_spec(name, arity, self.op_dir).is_some() {
|
||||
@@ -1441,16 +1502,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
);
|
||||
} else {
|
||||
push_space_if_amb!(self, name.as_str(), {
|
||||
let ct = ClauseType::from(name, arity);
|
||||
self.format_clause(max_depth, arity, ct, None);
|
||||
self.format_clause(max_depth, arity, name, None);
|
||||
});
|
||||
}
|
||||
}
|
||||
(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) => {
|
||||
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) => {
|
||||
self.print_list_like(max_depth);
|
||||
@@ -1477,20 +1537,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
}
|
||||
(HeapCellValueTag::Cons, c) => {
|
||||
match_untyped_arena_ptr!(c,
|
||||
(ArenaHeaderTag::F64, f) => {
|
||||
self.print_number(NumberFocus::Unfocused(Number::Float(*f)), &op);
|
||||
}
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
self.print_number(NumberFocus::Unfocused(Number::Integer(n)), &op);
|
||||
self.print_number(max_depth, NumberFocus::Unfocused(Number::Integer(n)), &op);
|
||||
}
|
||||
(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) => {
|
||||
self.print_stream(stream, max_depth);
|
||||
}
|
||||
(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 {
|
||||
loop {
|
||||
if let Some(loc_data) = self.state_stack.pop() {
|
||||
let spec = self.toplevel_spec.take();
|
||||
self.handle_heap_term(spec, false, self.max_depth);
|
||||
|
||||
while let Some(loc_data) = self.state_stack.pop() {
|
||||
match loc_data {
|
||||
TokenOrRedirect::Atom(atom) => self.print_atom(atom),
|
||||
TokenOrRedirect::BarAsOp => append_str!(self, " | "),
|
||||
@@ -1527,6 +1592,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
TokenOrRedirect::CompositeRedirect(max_depth, op) => {
|
||||
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) => {
|
||||
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::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::Space => push_char!(self, ' '),
|
||||
TokenOrRedirect::LeftCurly => 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
|
||||
@@ -1586,7 +1650,6 @@ mod tests {
|
||||
{
|
||||
let printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.arena,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0)
|
||||
@@ -1614,7 +1677,6 @@ mod tests {
|
||||
{
|
||||
let printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.arena,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0)
|
||||
@@ -1637,7 +1699,6 @@ mod tests {
|
||||
{
|
||||
let printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.arena,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0)
|
||||
@@ -1649,7 +1710,6 @@ mod tests {
|
||||
|
||||
let mut printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.arena,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0)
|
||||
@@ -1681,7 +1741,6 @@ mod tests {
|
||||
{
|
||||
let printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.arena,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
@@ -1699,7 +1758,6 @@ mod tests {
|
||||
{
|
||||
let printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.arena,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0),
|
||||
@@ -1715,7 +1773,6 @@ mod tests {
|
||||
{
|
||||
let mut printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.arena,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0)
|
||||
@@ -1746,7 +1803,6 @@ mod tests {
|
||||
{
|
||||
let mut printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.arena,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(0)
|
||||
@@ -1768,7 +1824,6 @@ mod tests {
|
||||
{
|
||||
let printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.arena,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
pstr_loc_as_cell!(0)
|
||||
@@ -1795,7 +1850,6 @@ mod tests {
|
||||
{
|
||||
let printer = HCPrinter::new(
|
||||
&mut wam.machine_st.heap,
|
||||
&mut wam.machine_st.arena,
|
||||
&wam.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
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::instructions::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
use slice_deque::{sdeq, SliceDeque};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::hash::Hash;
|
||||
@@ -108,7 +108,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
self.append_or_prepend,
|
||||
);
|
||||
|
||||
let mut constants = IndexMap::new();
|
||||
let mut constants = IndexMap::with_hasher(FxBuildHasher::default());
|
||||
|
||||
match constant_key {
|
||||
Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
|
||||
@@ -148,15 +148,15 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
index: usize,
|
||||
) {
|
||||
let third_level_index = if self.append_or_prepend.is_append() {
|
||||
sdeq![
|
||||
vec![
|
||||
IndexedChoiceInstruction::Try(external),
|
||||
IndexedChoiceInstruction::Trust(index)
|
||||
]
|
||||
].into()
|
||||
} else {
|
||||
sdeq![
|
||||
vec![
|
||||
IndexedChoiceInstruction::Try(index),
|
||||
IndexedChoiceInstruction::Trust(external)
|
||||
]
|
||||
].into()
|
||||
};
|
||||
|
||||
let indexing_code_len = self.indexing_code.len();
|
||||
@@ -182,9 +182,9 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
index: usize,
|
||||
) {
|
||||
let third_level_index = if self.append_or_prepend.is_append() {
|
||||
sdeq![external, index]
|
||||
vec![external, index].into()
|
||||
} else {
|
||||
sdeq![index, external]
|
||||
vec![index, external].into()
|
||||
};
|
||||
|
||||
let indexing_code_len = self.indexing_code.len();
|
||||
@@ -208,11 +208,11 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs)
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs)
|
||||
@@ -250,7 +250,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
break;
|
||||
}
|
||||
IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
|
||||
let mut constants = IndexMap::new();
|
||||
let mut constants = IndexMap::with_hasher(FxBuildHasher::default());
|
||||
constants.insert(orig_constant, *c);
|
||||
|
||||
*c = IndexingCodePtr::Internal(indexing_code_len);
|
||||
@@ -390,7 +390,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
self.append_or_prepend,
|
||||
);
|
||||
|
||||
let mut structures = IndexMap::new();
|
||||
let mut structures = IndexMap::with_hasher(FxBuildHasher::default());
|
||||
|
||||
match structure_key {
|
||||
Some(OptArgIndexKey::Structure(_, _, name, arity)) => {
|
||||
@@ -430,15 +430,15 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
index: usize,
|
||||
) {
|
||||
let third_level_index = if self.append_or_prepend.is_append() {
|
||||
sdeq![
|
||||
vec![
|
||||
IndexedChoiceInstruction::Try(external),
|
||||
IndexedChoiceInstruction::Trust(index)
|
||||
]
|
||||
].into()
|
||||
} else {
|
||||
sdeq![
|
||||
vec![
|
||||
IndexedChoiceInstruction::Try(index),
|
||||
IndexedChoiceInstruction::Trust(external)
|
||||
]
|
||||
].into()
|
||||
};
|
||||
|
||||
let indexing_code_len = self.indexing_code.len();
|
||||
@@ -464,9 +464,9 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
index: usize,
|
||||
) {
|
||||
let third_level_index = if self.append_or_prepend.is_append() {
|
||||
sdeq![external, index]
|
||||
vec![external, index].into()
|
||||
} else {
|
||||
sdeq![index, external]
|
||||
vec![index, external].into()
|
||||
};
|
||||
|
||||
let indexing_code_len = self.indexing_code.len();
|
||||
@@ -570,9 +570,9 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
*l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
|
||||
|
||||
let third_level_index = if self.append_or_prepend.is_append() {
|
||||
sdeq![o, index]
|
||||
vec![o, index].into()
|
||||
} else {
|
||||
sdeq![index, o]
|
||||
vec![index, o].into()
|
||||
};
|
||||
|
||||
self.indexing_code
|
||||
@@ -582,15 +582,15 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
*l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
|
||||
|
||||
let third_level_index = if self.append_or_prepend.is_append() {
|
||||
sdeq![
|
||||
vec![
|
||||
IndexedChoiceInstruction::Try(o),
|
||||
IndexedChoiceInstruction::Trust(index)
|
||||
]
|
||||
].into()
|
||||
} else {
|
||||
sdeq![
|
||||
vec![
|
||||
IndexedChoiceInstruction::Try(index),
|
||||
IndexedChoiceInstruction::Trust(o)
|
||||
]
|
||||
].into()
|
||||
};
|
||||
|
||||
self.indexing_code
|
||||
@@ -1122,15 +1122,6 @@ pub(crate) fn constant_key_alternatives(
|
||||
}).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)]
|
||||
pub(crate) struct StaticCodeIndices {
|
||||
constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>>,
|
||||
constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
||||
lists: VecDeque<IndexedChoiceInstruction>,
|
||||
structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>>,
|
||||
structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DynamicCodeIndices {
|
||||
constants: IndexMap<Literal, VecDeque<usize>>,
|
||||
constants: IndexMap<Literal, VecDeque<usize>, FxBuildHasher>,
|
||||
lists: VecDeque<usize>,
|
||||
structures: IndexMap<(Atom, usize), VecDeque<usize>>,
|
||||
structures: IndexMap<(Atom, usize), VecDeque<usize>, FxBuildHasher>,
|
||||
}
|
||||
|
||||
pub(crate) trait Indexer {
|
||||
@@ -1156,20 +1147,20 @@ pub(crate) trait Indexer {
|
||||
|
||||
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 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 second_level_index<IndexKey: Eq + Hash>(
|
||||
indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>,
|
||||
indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexMap<IndexKey, IndexingCodePtr>;
|
||||
) -> IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>;
|
||||
|
||||
fn switch_on<IndexKey: Eq + Hash>(
|
||||
instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
|
||||
index: &mut IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>,
|
||||
instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction,
|
||||
index: &mut IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexingCodePtr;
|
||||
|
||||
@@ -1178,7 +1169,7 @@ pub(crate) trait Indexer {
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> 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;
|
||||
}
|
||||
@@ -1189,14 +1180,14 @@ impl Indexer for StaticCodeIndices {
|
||||
#[inline]
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
constants: IndexMap::new(),
|
||||
constants: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
lists: VecDeque::new(),
|
||||
structures: IndexMap::new(),
|
||||
structures: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>> {
|
||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
|
||||
&mut self.constants
|
||||
}
|
||||
|
||||
@@ -1206,7 +1197,7 @@ impl Indexer for StaticCodeIndices {
|
||||
}
|
||||
|
||||
#[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
|
||||
}
|
||||
|
||||
@@ -1219,10 +1210,10 @@ impl Indexer for StaticCodeIndices {
|
||||
}
|
||||
|
||||
fn second_level_index<IndexKey: Eq + Hash>(
|
||||
indices: IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>,
|
||||
indices: IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexMap<IndexKey, IndexingCodePtr> {
|
||||
let mut index_locs = IndexMap::new();
|
||||
) -> IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher> {
|
||||
let mut index_locs = IndexMap::with_hasher(FxBuildHasher::default());
|
||||
|
||||
for (key, mut code) in indices.into_iter() {
|
||||
if code.len() > 1 {
|
||||
@@ -1240,11 +1231,11 @@ impl Indexer for StaticCodeIndices {
|
||||
}
|
||||
|
||||
fn switch_on<IndexKey: Eq + Hash>(
|
||||
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
|
||||
index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>,
|
||||
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction,
|
||||
index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> 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);
|
||||
|
||||
if index.len() > 1 {
|
||||
@@ -1281,13 +1272,13 @@ impl Indexer for StaticCodeIndices {
|
||||
|
||||
#[inline]
|
||||
fn remove_instruction_with_offset(
|
||||
code: &mut SliceDeque<IndexedChoiceInstruction>,
|
||||
code: &mut VecDeque<IndexedChoiceInstruction>,
|
||||
offset: usize,
|
||||
) {
|
||||
for (index, line) in code.iter().enumerate() {
|
||||
if offset == line.offset() {
|
||||
code.remove(index);
|
||||
cap_choice_seq(code);
|
||||
cap_choice_seq(code.make_contiguous());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1305,14 +1296,14 @@ impl Indexer for DynamicCodeIndices {
|
||||
#[inline]
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
constants: IndexMap::new(),
|
||||
constants: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
lists: VecDeque::new(),
|
||||
structures: IndexMap::new(),
|
||||
structures: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>> {
|
||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>, FxBuildHasher> {
|
||||
&mut self.constants
|
||||
}
|
||||
|
||||
@@ -1322,7 +1313,7 @@ impl Indexer for DynamicCodeIndices {
|
||||
}
|
||||
|
||||
#[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
|
||||
}
|
||||
|
||||
@@ -1332,10 +1323,10 @@ impl Indexer for DynamicCodeIndices {
|
||||
}
|
||||
|
||||
fn second_level_index<IndexKey: Eq + Hash>(
|
||||
indices: IndexMap<IndexKey, VecDeque<usize>>,
|
||||
indices: IndexMap<IndexKey, VecDeque<usize>, FxBuildHasher>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexMap<IndexKey, IndexingCodePtr> {
|
||||
let mut index_locs = IndexMap::new();
|
||||
) -> IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher> {
|
||||
let mut index_locs = IndexMap::with_hasher(FxBuildHasher::default());
|
||||
|
||||
for (key, code) in indices.into_iter() {
|
||||
if code.len() > 1 {
|
||||
@@ -1352,11 +1343,11 @@ impl Indexer for DynamicCodeIndices {
|
||||
}
|
||||
|
||||
fn switch_on<IndexKey: Eq + Hash>(
|
||||
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
|
||||
index: &mut IndexMap<IndexKey, VecDeque<usize>>,
|
||||
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction,
|
||||
index: &mut IndexMap<IndexKey, VecDeque<usize>, FxBuildHasher>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> 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);
|
||||
|
||||
if index.len() > 1 {
|
||||
@@ -1390,7 +1381,7 @@ impl Indexer for DynamicCodeIndices {
|
||||
}
|
||||
|
||||
#[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() {
|
||||
if offset == *line {
|
||||
code.remove(index);
|
||||
@@ -1475,17 +1466,20 @@ impl<I: Indexer> CodeOffsets<I> {
|
||||
atom_tbl: &mut AtomTable,
|
||||
) {
|
||||
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) => {
|
||||
clause_index_info.opt_arg_index_key =
|
||||
OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len());
|
||||
|
||||
self.index_structure(name, terms.len(), index);
|
||||
}
|
||||
&Term::Cons(..) | &Term::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) => {
|
||||
let overlapping_constants = self.index_constant(atom_tbl, constant, index);
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
@@ -16,8 +15,9 @@ pub(crate) enum TermRef<'a> {
|
||||
AnonVar(Level),
|
||||
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Term>),
|
||||
PartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
|
||||
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
||||
PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
||||
CompleteString(Level, &'a Cell<RegType>, Atom),
|
||||
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
||||
}
|
||||
|
||||
@@ -28,8 +28,9 @@ impl<'a> TermRef<'a> {
|
||||
| TermRef::Cons(lvl, ..)
|
||||
| TermRef::Literal(lvl, ..)
|
||||
| TermRef::Var(lvl, ..)
|
||||
| TermRef::Clause(lvl, ..) => lvl,
|
||||
TermRef::PartialString(lvl, ..) => lvl,
|
||||
| TermRef::Clause(lvl, ..)
|
||||
| TermRef::CompleteString(lvl, ..)
|
||||
| TermRef::PartialString(lvl, ..) => lvl,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,11 +39,12 @@ impl<'a> TermRef<'a> {
|
||||
pub(crate) enum TermIterState<'a> {
|
||||
AnonVar(Level),
|
||||
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),
|
||||
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
InitialPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
|
||||
FinalPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
|
||||
InitialPartialString(Level, &'a Cell<RegType>, &'a String, &'a 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>),
|
||||
}
|
||||
|
||||
@@ -51,15 +53,17 @@ impl<'a> TermIterState<'a> {
|
||||
match term {
|
||||
Term::AnonVar => TermIterState::AnonVar(lvl),
|
||||
Term::Clause(cell, name, subterms) => {
|
||||
let ct = ClauseType::Named(subterms.len(), *name, CodeIndex::default());
|
||||
TermIterState::Clause(lvl, 0, cell, ct, subterms)
|
||||
TermIterState::Clause(lvl, 0, cell, *name, subterms)
|
||||
}
|
||||
Term::Cons(cell, head, tail) => {
|
||||
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
|
||||
}
|
||||
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
|
||||
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()),
|
||||
}
|
||||
@@ -89,7 +93,8 @@ impl<'a> QueryIterator<'a> {
|
||||
|
||||
fn from_term(term: &'a Term) -> Self {
|
||||
let state = match term {
|
||||
Term::AnonVar | Term::Cons(..) | Term::Literal(..) | Term::PartialString(..) => {
|
||||
Term::AnonVar | Term::Cons(..) | Term::Literal(..) |
|
||||
Term::PartialString(..) | Term::CompleteString(..) => {
|
||||
return QueryIterator {
|
||||
state_stack: vec![],
|
||||
}
|
||||
@@ -98,7 +103,7 @@ impl<'a> QueryIterator<'a> {
|
||||
Level::Root,
|
||||
0,
|
||||
r,
|
||||
ClauseType::from(*name, terms.len()),
|
||||
*name,
|
||||
terms,
|
||||
),
|
||||
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 {
|
||||
match term {
|
||||
&QueryTerm::Clause(ref cell, ClauseType::CallN(arity), ref terms, _) => {
|
||||
let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN(arity), terms);
|
||||
&QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
|
||||
let state = TermIterState::Clause(Level::Root, 1, cell, atom!("$call"), terms);
|
||||
QueryIterator {
|
||||
state_stack: vec![state],
|
||||
}
|
||||
}
|
||||
&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 {
|
||||
state_stack: vec![state],
|
||||
}
|
||||
@@ -160,28 +165,25 @@ impl<'a> Iterator for QueryIterator<'a> {
|
||||
TermIterState::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() {
|
||||
match ct {
|
||||
ClauseType::CallN(_) => {
|
||||
match name {
|
||||
atom!("$call") if lvl == Level::Root => {
|
||||
self.push_subterm(Level::Shallow, &child_terms[0]);
|
||||
}
|
||||
ClauseType::Named(..) => {
|
||||
_ => {
|
||||
return match lvl {
|
||||
Level::Root => None,
|
||||
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
|
||||
lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
self.state_stack.push(TermIterState::Clause(
|
||||
lvl,
|
||||
child_num + 1,
|
||||
cell,
|
||||
ct,
|
||||
name,
|
||||
child_terms,
|
||||
));
|
||||
|
||||
@@ -196,13 +198,13 @@ impl<'a> Iterator for QueryIterator<'a> {
|
||||
}
|
||||
TermIterState::InitialPartialString(lvl, cell, string, tail) => {
|
||||
self.state_stack.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
|
||||
|
||||
if let Some(tail) = tail {
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
}
|
||||
TermIterState::FinalPartialString(lvl, cell, atom, tail) => {
|
||||
return Some(TermRef::PartialString(lvl, cell, atom, tail));
|
||||
}
|
||||
TermIterState::FinalPartialString(lvl, cell, string, tail) => {
|
||||
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
||||
TermIterState::CompleteString(lvl, cell, atom) => {
|
||||
return Some(TermRef::CompleteString(lvl, cell, atom));
|
||||
}
|
||||
TermIterState::FinalCons(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)]
|
||||
}
|
||||
Term::Clause(cell, name, terms) => {
|
||||
let ct = ClauseType::from(*name, terms.len());
|
||||
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
|
||||
vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)]
|
||||
}
|
||||
Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
|
||||
Level::Root,
|
||||
@@ -259,12 +260,19 @@ impl<'a> FactIterator<'a> {
|
||||
head.as_ref(),
|
||||
tail.as_ref(),
|
||||
)],
|
||||
Term::PartialString(cell, string_buf, tail_opt) => {
|
||||
Term::PartialString(cell, string_buf, tail) => {
|
||||
vec![TermIterState::InitialPartialString(
|
||||
Level::Root,
|
||||
cell,
|
||||
*string_buf,
|
||||
tail_opt,
|
||||
string_buf,
|
||||
tail,
|
||||
)]
|
||||
}
|
||||
Term::CompleteString(cell, atom) => {
|
||||
vec![TermIterState::CompleteString(
|
||||
Level::Root,
|
||||
cell,
|
||||
*atom,
|
||||
)]
|
||||
}
|
||||
Term::Literal(cell, constant) => {
|
||||
@@ -291,14 +299,14 @@ impl<'a> Iterator for FactIterator<'a> {
|
||||
TermIterState::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 {
|
||||
self.push_subterm(lvl.child_level(), child_term);
|
||||
}
|
||||
|
||||
match lvl {
|
||||
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) => {
|
||||
@@ -307,12 +315,12 @@ impl<'a> Iterator for FactIterator<'a> {
|
||||
|
||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||
}
|
||||
TermIterState::InitialPartialString(lvl, cell, string_buf, tail_opt) => {
|
||||
if let Some(tail) = tail_opt {
|
||||
TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => {
|
||||
self.push_subterm(Level::Deep, tail);
|
||||
return Some(TermRef::PartialString(lvl, cell, string_buf, tail));
|
||||
}
|
||||
|
||||
return Some(TermRef::PartialString(lvl, cell, string_buf, tail_opt));
|
||||
TermIterState::CompleteString(lvl, cell, atom) => {
|
||||
return Some(TermRef::CompleteString(lvl, cell, atom));
|
||||
}
|
||||
TermIterState::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 {
|
||||
let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
|
||||
let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)));
|
||||
|
||||
@@ -19,6 +19,7 @@ mod fixtures;
|
||||
mod forms;
|
||||
mod heap_iter;
|
||||
pub mod heap_print;
|
||||
mod http;
|
||||
mod indexing;
|
||||
#[macro_use]
|
||||
pub mod instructions {
|
||||
@@ -28,6 +29,7 @@ mod iterators;
|
||||
pub mod machine;
|
||||
mod raw_block;
|
||||
pub mod read;
|
||||
mod repl_helper;
|
||||
mod targets;
|
||||
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)
|
||||
; must_be(chars, Cs),
|
||||
( '$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)
|
||||
)
|
||||
).
|
||||
|
||||
@@ -1122,6 +1122,8 @@ indomain(1).
|
||||
% CountAnd = 1.
|
||||
% ==
|
||||
|
||||
|
||||
|
||||
sat_count(Sat0, N) :-
|
||||
catch((parse_sat(Sat0, Sat),
|
||||
sat_bdd(Sat, BDD),
|
||||
|
||||
153
src/lib/clpz.pl
153
src/lib/clpz.pl
@@ -3,7 +3,7 @@
|
||||
Author: Markus Triska
|
||||
E-mail: triska@metalevel.at
|
||||
WWW: https://www.metalevel.at
|
||||
Copyright (C): 2016-2021 Markus Triska
|
||||
Copyright (C): 2016-2022 Markus Triska
|
||||
|
||||
This library provides CLP(ℤ):
|
||||
|
||||
@@ -123,6 +123,8 @@
|
||||
:- use_module(library(si)).
|
||||
:- use_module(library(freeze)).
|
||||
:- use_module(library(arithmetic)).
|
||||
:- use_module(library(debug)).
|
||||
:- use_module(library(format)).
|
||||
|
||||
% :- use_module(library(types)).
|
||||
|
||||
@@ -194,6 +196,8 @@ type_error(Expectation, Term) :-
|
||||
type_error(Expectation, Term, unknown(Term)-1).
|
||||
|
||||
|
||||
:- meta_predicate(partition(1, ?, ?, ?)).
|
||||
|
||||
partition(Pred, Ls0, As, Bs) :-
|
||||
include(Pred, Ls0, As),
|
||||
exclude(Pred, Ls0, Bs).
|
||||
@@ -214,6 +218,8 @@ partition_([X|Xs], Pred, Ls0, Es0, Gs0) :-
|
||||
include/3 and exclude/3
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
:- meta_predicate(include(1, ?, ?)).
|
||||
|
||||
include(Goal, Ls0, Ls) :-
|
||||
include_(Ls0, Goal, Ls).
|
||||
|
||||
@@ -226,6 +232,7 @@ include_([L|Ls0], Goal, Ls) :-
|
||||
include_(Ls0, Goal, Rest).
|
||||
|
||||
|
||||
:- meta_predicate(exclude(1, ?, ?)).
|
||||
|
||||
exclude(Goal, Ls0, Ls) :-
|
||||
exclude_(Ls0, Goal, Ls).
|
||||
@@ -390,6 +397,7 @@ In total, the arithmetic constraints are:
|
||||
| Expr `mod` Expr | Modulo induced by floored division |
|
||||
| Expr `rem` Expr | Modulo induced by truncated division |
|
||||
| abs(Expr) | Absolute value |
|
||||
| sign(Expr) | Sign (-1, 0, 1) of Expr |
|
||||
| Expr // Expr | Truncated integer division |
|
||||
| Expr div Expr | Floored integer division |
|
||||
|
||||
@@ -2235,8 +2243,8 @@ all_distinct(Ls) :-
|
||||
fd_must_be_list(Ls, all_distinct(Ls)-1),
|
||||
maplist(fd_variable, Ls),
|
||||
make_propagator(pdistinct(Ls), Prop),
|
||||
distinct_attach(Ls, Prop, []),
|
||||
trigger_once(Prop).
|
||||
new_queue(Q0),
|
||||
phrase((distinct_attach(Ls, Prop, []),trigger_prop(Prop),do_queue), [Q0], _).
|
||||
|
||||
%% nvalue(?N, +Vars).
|
||||
%
|
||||
@@ -2564,6 +2572,7 @@ parse_clpz(E, 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^B) => [p(pexp(A, B, R))],
|
||||
m(sign(A)) => [g(R in -1..1), p(psign(A, R))],
|
||||
% bitwise operations
|
||||
m(\A) => [p(pfunction(\, 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_([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) -->
|
||||
{ propagator_state(Propagator, State) },
|
||||
( { State == dead } -> []
|
||||
; { get_attr(State, clpz_aux, queued) } -> []
|
||||
; { bb_get('$clpz_current_propagator', C), C == State } -> []
|
||||
; % passive
|
||||
%{ format("triggering: ~w\n", [Propagator]) },
|
||||
{ put_attr(State, clpz_aux, queued) },
|
||||
@@ -4141,12 +4151,13 @@ no_reactivation(pgcc_single(_,_)).
|
||||
%no_reactivation(scalar_product(_,_,_,_)).
|
||||
|
||||
activate_propagator(propagator(P,State)) -->
|
||||
% { portray_clause(running(P)) },
|
||||
( State == dead -> []
|
||||
; { del_attr(State, clpz_aux) },
|
||||
( { no_reactivation(P) } ->
|
||||
%b_setval('$clpz_current_propagator', State), TODO
|
||||
run_propagator(P, State)
|
||||
%b_setval('$clpz_current_propagator', [])
|
||||
{ bb_b_put('$clpz_current_propagator', State) },
|
||||
run_propagator(P, State),
|
||||
{ bb_b_put('$clpz_current_propagator', []) }
|
||||
; run_propagator(P, State)
|
||||
)
|
||||
).
|
||||
@@ -4192,7 +4203,8 @@ queue_get_arg_(Queue, Which, Element) :-
|
||||
).
|
||||
|
||||
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, _).
|
||||
|
||||
@@ -4387,14 +4399,14 @@ run_propagator(pdifferent(Left,Right,X,_), MState) -->
|
||||
run_propagator(pexclude(Left,Right,X), MState).
|
||||
|
||||
run_propagator(pexclude(Left,Right,X), _) -->
|
||||
{ ( ground(X) ->
|
||||
( ground(X) ->
|
||||
disable_queue,
|
||||
exclude_fire(Left, Right, X),
|
||||
enable_queue
|
||||
; 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) }.
|
||||
|
||||
@@ -4428,8 +4440,8 @@ run_propagator(pgcc(Vs, _, Pairs), _) --> { gcc_global(Vs, Pairs) }.
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
run_propagator(pcircuit(Vs), _MState) -->
|
||||
{ distinct(Vs),
|
||||
propagate_circuit(Vs) }.
|
||||
distinct(Vs),
|
||||
{ propagate_circuit(Vs) }.
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
@@ -5134,7 +5146,6 @@ run_propagator(pmodz(X,Y,Z), MState) -->
|
||||
domain_remove_smaller_than(ZD3, ZMin, ZD5) },
|
||||
fd_put(Z, ZD5, ZPs)
|
||||
% queue_goal(Z in ZMin..ZMax)
|
||||
%/* This doesn't work very well.
|
||||
; { fd_get(Y, _, _, n(YU), _), YU > 0 } ->
|
||||
{ fd_get(Z, ZD1, ZPs),
|
||||
ZMax is YU - 1,
|
||||
@@ -5147,7 +5158,6 @@ run_propagator(pmodz(X,Y,Z), MState) -->
|
||||
domain_remove_smaller_than(ZD1, ZMin, ZD3) },
|
||||
fd_put(Z, ZD3, ZPs)
|
||||
% queue_goal(Z #> YL)
|
||||
% * /
|
||||
; true
|
||||
)
|
||||
)
|
||||
@@ -5484,6 +5494,21 @@ run_propagator(pexp(X,Y,Z), MState) -->
|
||||
; 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)
|
||||
|
||||
@@ -5913,12 +5938,12 @@ max_factor(L1, U1, L2, U2, Max) :-
|
||||
CSPs", AAAI-94, Seattle, WA, USA, pp 362--367, 1994
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
distinct_attach([], _, _).
|
||||
distinct_attach([X|Xs], Prop, Right) :-
|
||||
distinct_attach([], _, _) --> [].
|
||||
distinct_attach([X|Xs], Prop, Right) -->
|
||||
( var(X) ->
|
||||
init_propagator(X, Prop),
|
||||
{ init_propagator(X, Prop),
|
||||
make_propagator(pexclude(Xs,Right,X), P1),
|
||||
init_propagator(X, P1),
|
||||
init_propagator(X, P1) },
|
||||
trigger_prop(P1)
|
||||
; 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).
|
||||
|
||||
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, ?).
|
||||
|
||||
:- dynamic(nat_copy/1).
|
||||
|
||||
with_local_attributes(Vars, Goal, Result) :-
|
||||
catch((Goal,
|
||||
maplist(del_all_attrs, Vars),
|
||||
% reset all attributes, only the result matters
|
||||
throw(local_attributes(Result,Vars))),
|
||||
local_attributes(Result,Vars),
|
||||
% Create a copy where all attributes are removed. Only
|
||||
% the result and its relation to Vars matters. We throw
|
||||
% an exception to undo all modifications to attributes
|
||||
% 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).
|
||||
|
||||
distinct(Vars) :-
|
||||
with_local_attributes(Vars,
|
||||
distinct(Vars) -->
|
||||
{ with_local_attributes(Vars,
|
||||
( difference_arcs(Vars, FreeLeft, FreeRight0),
|
||||
length(FreeLeft, LFL),
|
||||
length(FreeRight0, LFR),
|
||||
@@ -6150,11 +6142,16 @@ distinct(Vars) :-
|
||||
maplist(g_g0, FreeLeft),
|
||||
scc(FreeLeft, g0_successors),
|
||||
maplist(dfs_used, FreeRight),
|
||||
phrase(distinct_goals(FreeLeft), Gs)), Gs),
|
||||
phrase(distinct_goals(FreeLeft), Gs)), Gs) },
|
||||
disable_queue,
|
||||
maplist(call, Gs),
|
||||
neq_nums(Gs),
|
||||
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([V|Vs]) -->
|
||||
{ get_attr(V, edges, Es) },
|
||||
@@ -6169,7 +6166,7 @@ distinct_goals_([flow_to(F,To)|Es], V) -->
|
||||
get_attr(To, lowlink, L2),
|
||||
L1 =\= L2 } ->
|
||||
{ get_attr(To, value, N) },
|
||||
[clpz:neq_num(V, N)]
|
||||
[neq_num(V, N)]
|
||||
; []
|
||||
),
|
||||
distinct_goals_(Es, V).
|
||||
@@ -6361,6 +6358,10 @@ exclude_fire(Left, Right, E) :-
|
||||
all_neq(Left, E),
|
||||
all_neq(Right, E).
|
||||
|
||||
exclude_fire(Left, Right, E) -->
|
||||
all_neq(Left, E),
|
||||
all_neq(Right, E).
|
||||
|
||||
list_contains([X|Xs], Y) :-
|
||||
( X == Y -> true
|
||||
; 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([X|Xs], C) :-
|
||||
neq_num(X, C),
|
||||
@@ -6953,8 +6959,8 @@ circuit(Vs) :-
|
||||
( L =:= 1 -> true
|
||||
; neq_index(Vs, 1),
|
||||
make_propagator(pcircuit(Vs), Prop),
|
||||
distinct_attach(Vs, Prop, []),
|
||||
trigger_once(Prop)
|
||||
new_queue(Q0),
|
||||
phrase((distinct_attach(Vs, Prop, []),trigger_prop(Prop),do_queue), [Q0], _)
|
||||
).
|
||||
|
||||
neq_index([], _).
|
||||
@@ -7134,10 +7140,6 @@ contribution_at(T, Task, Offset-Bs, Contribution) :-
|
||||
?(Contribution) #= B*C
|
||||
).
|
||||
|
||||
nth1(I, Es, E) :-
|
||||
I0 is I-1,
|
||||
nth0(I0, Es, E).
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
%% 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_(prdiv(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_(pmod(X,M,K)) --> [?(X) mod ?(M) #= ?(K)].
|
||||
attribute_goal_(prem(X,Y,Z)) --> [?(X) rem ?(Y) #= ?(Z)].
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
In Scryer Prolog, lists of characters are very efficiently represented,
|
||||
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.
|
||||
|
||||
For predicates that accept an encoding/1 option to specify the encoding
|
||||
@@ -65,8 +65,7 @@
|
||||
|
||||
hex_bytes(Hs, Bytes) :-
|
||||
( ground(Hs) ->
|
||||
must_be(list, Hs),
|
||||
maplist(must_be(atom), Hs),
|
||||
must_be(chars, Hs),
|
||||
( phrase(hex_bytes(Hs), Bytes) ->
|
||||
true
|
||||
; 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),
|
||||
( '$first_non_octet'(Chars, F) ->
|
||||
domain_error(byte_char, F, Context)
|
||||
domain_error(octet_character, F, Context)
|
||||
; true
|
||||
).
|
||||
|
||||
@@ -611,7 +610,7 @@ encoding_chars(octet, Bs, Cs) :-
|
||||
maplist(char_code, Cs, Bs)
|
||||
; Bs = Cs
|
||||
),
|
||||
must_be_byte_chars(Cs, crypto_encoding).
|
||||
must_be_octet_chars(Cs, crypto_encoding).
|
||||
encoding_chars(utf8, Cs, Cs) :-
|
||||
must_be(chars, Cs).
|
||||
|
||||
@@ -652,17 +651,17 @@ ed25519_new_keypair(Pair) :-
|
||||
'$ed25519_new_keypair'(Pair).
|
||||
|
||||
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_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),
|
||||
'$ed25519_sign'(Key, Data, Encoding, Signature0),
|
||||
hex_bytes(Signature, Signature0).
|
||||
|
||||
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),
|
||||
hex_bytes(Signature0, Signature),
|
||||
'$ed25519_verify'(Key, Data, Encoding, Signature).
|
||||
@@ -714,12 +713,17 @@ curve25519_scalar_mult(Scalar, Point, Result) :-
|
||||
'$curve25519_scalar_mult'(ScalarBytes, PointBytes, Result).
|
||||
|
||||
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,
|
||||
N #= N0 + B*256^I0,
|
||||
I #= I0 + 1.
|
||||
N #= N0 + B*256^P0,
|
||||
P #= P0 + 1.
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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_field_length(Curve, L0),
|
||||
L #= 2*L0, % for hex encoding
|
||||
phrase(format_("04~|~`0t~16r~*+~`0t~16r~*+", [X,L,Y,L]), Hex),
|
||||
hex_bytes(Hex, Bytes),
|
||||
'$crypto_curve_scalar_mult'(Name, Scalar, Bytes, SX, SY),
|
||||
number_chars(RX, SX),
|
||||
number_chars(RY, SY).
|
||||
phrase(format_("04~|~`0t~16r~*+~`0t~16r~*+", [X,L,Y,L]), PointHex),
|
||||
hex_bytes(PointHex, PointBytes),
|
||||
once(bytes_integer(ScalarBytes, Scalar)),
|
||||
'$crypto_curve_scalar_mult'(Name, ScalarBytes, PointBytes, [_|Us]),
|
||||
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),
|
||||
@@ -818,16 +826,6 @@ fitting_exponent(N, E0, 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,
|
||||
curve(secp256k1,
|
||||
0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
|
||||
|
||||
122
src/lib/dcgs.pl
122
src/lib/dcgs.pl
@@ -8,19 +8,10 @@
|
||||
]).
|
||||
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(iso_ext)).
|
||||
:- use_module(library(lists), [append/3, member/2]).
|
||||
:- 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, ?, ?).
|
||||
@@ -29,12 +20,14 @@ phrase(GRBody, S0) :-
|
||||
phrase(GRBody, S0, []).
|
||||
|
||||
phrase(GRBody, S0, S) :-
|
||||
load_context(GRBody, Module, GRBody0),
|
||||
( var(GRBody0) ->
|
||||
strip_module(GRBody, M, GRBody1),
|
||||
( var(GRBody) ->
|
||||
instantiation_error(phrase/3)
|
||||
; dcg_body(GRBody0, S0, S, GRBody1, Module) ->
|
||||
call(GRBody1)
|
||||
; type_error(callable, GRBody0, phrase/3)
|
||||
; nonvar(GRBody1),
|
||||
dcg_constr(GRBody1),
|
||||
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.
|
||||
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
|
||||
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),
|
||||
Body = ( Goal1, Goal2 ).
|
||||
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
|
||||
NonTerminal \= ( _, _ ),
|
||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||
dcg_body(GRBody, S0, S, Body, _).
|
||||
dcg_body(GRBody, S0, S, Body).
|
||||
|
||||
% This program uses append/3 as defined in the Prolog prologue.
|
||||
% Expands a DCG rule into a Prolog rule, when no error condition applies.
|
||||
dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :-
|
||||
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),
|
||||
Body = ( Goal1, Goal2 ).
|
||||
dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :-
|
||||
NonTerminal \= ( _, _ ),
|
||||
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) :-
|
||||
NonTerminal =.. NonTerminalUniv,
|
||||
@@ -75,21 +68,21 @@ dcg_non_terminal(NonTerminal, S0, S, Goal) :-
|
||||
dcg_terminals(Terminals, S0, S, S0 = List) :-
|
||||
append(Terminals, S, List).
|
||||
|
||||
dcg_body(Var, S0, S, Body, M) :-
|
||||
dcg_body(Var, S0, S, Body) :-
|
||||
var(Var),
|
||||
module_call_qualified(M, Var, Var1),
|
||||
Body = phrase(Var1, S0, S).
|
||||
dcg_body(GRBody, S0, S, Body, M) :-
|
||||
Body = phrase(Var, S0, S).
|
||||
dcg_body(GRBody, S0, S, Body) :-
|
||||
nonvar(GRBody),
|
||||
dcg_constr(GRBody),
|
||||
dcg_cbody(GRBody, S0, S, Body, M).
|
||||
dcg_body(NonTerminal, S0, S, Goal1, M) :-
|
||||
dcg_cbody(GRBody, S0, S, Body).
|
||||
dcg_body(NonTerminal, S0, S, Goal1) :-
|
||||
nonvar(NonTerminal),
|
||||
\+ dcg_constr(NonTerminal),
|
||||
NonTerminal \= ( _ -> _ ),
|
||||
NonTerminal \= ( \+ _ ),
|
||||
module_call_qualified(M, Goal, Goal1),
|
||||
dcg_non_terminal(NonTerminal, S0, S, Goal).
|
||||
loader:strip_module(NonTerminal, M, NonTerminal0),
|
||||
dcg_non_terminal(NonTerminal0, S0, S, Goal0),
|
||||
module_call_qualified(M, Goal0, Goal1).
|
||||
|
||||
% The following constructs in a grammar rule body
|
||||
% 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 construct to be expanded.
|
||||
dcg_cbody([], S0, S, S0 = S, _M).
|
||||
dcg_cbody([T|Ts], S0, S, Goal, _M) :-
|
||||
dcg_cbody([], S0, S, S0 = S).
|
||||
dcg_cbody([T|Ts], S0, S, Goal) :-
|
||||
must_be(list, [T|Ts]),
|
||||
dcg_terminals([T|Ts], S0, S, Goal).
|
||||
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second ), M) :-
|
||||
dcg_body(GRFirst, S0, S1, First, M),
|
||||
dcg_body(GRSecond, S1, S, Second, M).
|
||||
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or ), M) :-
|
||||
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
|
||||
dcg_body(GRFirst, S0, S1, First),
|
||||
dcg_body(GRSecond, S1, S, Second).
|
||||
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or )) :-
|
||||
\+ subsumes_term(( _ -> _ ), GREither),
|
||||
dcg_body(GREither, S0, S, Either, M),
|
||||
dcg_body(GROr, S0, S, Or, M).
|
||||
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else ), M) :-
|
||||
dcg_body(GREither, S0, S, Either),
|
||||
dcg_body(GROr, S0, S, Or).
|
||||
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
|
||||
subsumes_term(( _GRIf -> _GRThen ), GRCond),
|
||||
dcg_cbody(GRCond, S0, S, Cond, M),
|
||||
dcg_body(GRElse, S0, S, Else, M).
|
||||
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or ), M) :-
|
||||
dcg_body(GREither, S0, S, Either, M),
|
||||
dcg_body(GROr, S0, S, Or, M).
|
||||
dcg_cbody({Goal}, S0, S, ( Goal1, S0 = S ), M) :-
|
||||
module_call_qualified(M, Goal, Goal1).
|
||||
dcg_cbody(call(Cont), S0, S, call(Cont1, S0, S), M) :-
|
||||
module_call_qualified(M, Cont, Cont1).
|
||||
dcg_cbody(phrase(Body), S0, S, phrase(Body1, S0, S), M) :-
|
||||
module_call_qualified(M, Body, Body1).
|
||||
dcg_cbody(!, S0, S, ( !, S0 = S ), _M).
|
||||
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody1,S0,_), S0 = S ), M) :-
|
||||
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).
|
||||
dcg_cbody(GRCond, S0, S, Cond),
|
||||
dcg_body(GRElse, S0, S, Else).
|
||||
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
|
||||
dcg_body(GREither, S0, S, Either),
|
||||
dcg_body(GROr, S0, S, Or).
|
||||
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
|
||||
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
|
||||
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
|
||||
dcg_cbody(!, S0, S, ( !, S0 = S )).
|
||||
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
|
||||
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
|
||||
dcg_body(GRIf, S0, S1, If),
|
||||
dcg_body(GRThen, S1, S, Then).
|
||||
|
||||
user:term_expansion(Term0, Term) :-
|
||||
nonvar(Term0),
|
||||
dcg_rule(Term0, Term).
|
||||
|
||||
% Describes a sequence
|
||||
seq(Xs, Cs0,Cs) :-
|
||||
var(Xs),
|
||||
Cs0 == [],
|
||||
!,
|
||||
Xs = [],
|
||||
Cs0 = Cs.
|
||||
seq([]) --> [].
|
||||
seq([E|Es]) --> [E], seq(Es).
|
||||
|
||||
@@ -151,14 +146,23 @@ seqq([]) --> [].
|
||||
seqq([Es|Ess]) --> seq(Es), seqq(Ess).
|
||||
|
||||
% Describes an arbitrary number of elements
|
||||
...(Cs0,Cs) :-
|
||||
Cs0 == [],
|
||||
!,
|
||||
Cs0 = Cs.
|
||||
... --> [] | [_], ... .
|
||||
|
||||
user:goal_expansion(phrase(GRBody, S, S0), GRBody1) :-
|
||||
load_context(GRBody, M, GRBody0),
|
||||
error_goal(error(E, must_be/2), error(E, must_be/2)).
|
||||
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),
|
||||
catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1, M),
|
||||
error(E, must_be/2),
|
||||
( GRBody1 = throw(error(E, must_be/2)) )
|
||||
).
|
||||
catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1),
|
||||
E,
|
||||
dcgs:error_goal(E, GRBody1)
|
||||
),
|
||||
module_call_qualified(M, GRBody1, GRBody2).
|
||||
|
||||
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.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
type_error/3
|
||||
]).
|
||||
|
||||
|
||||
:- meta_predicate check_(1, ?, ?).
|
||||
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
must_be(Type, Term)
|
||||
|
||||
@@ -28,8 +32,12 @@
|
||||
- boolean
|
||||
- character
|
||||
- chars
|
||||
- in_character
|
||||
- integer
|
||||
- list
|
||||
- octet_character
|
||||
- octet_chars
|
||||
- term
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
must_be(Type, Term) :-
|
||||
@@ -44,9 +52,16 @@ must_be_(var, Term) :-
|
||||
; throw(error(uninstantiation_error(Term), must_be/2))
|
||||
).
|
||||
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_(character, T) :- check_(error:character, character, T).
|
||||
must_be_(in_character, T) :- check_(error:in_character, in_character, T).
|
||||
must_be_(chars, Ls) :-
|
||||
can_be(chars, Ls), % prioritize type errors over instantiation errors
|
||||
must_be(list, Ls),
|
||||
( '$is_partial_string'(Ls) ->
|
||||
% The expected case (success) uses a very fast test.
|
||||
@@ -55,9 +70,27 @@ must_be_(chars, Ls) :-
|
||||
true
|
||||
; 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_(type, Term) :- check_(error:type, type, 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)
|
||||
% uses library(error), so importing it would create a cyclic dependency.
|
||||
@@ -79,6 +112,15 @@ character(C) :-
|
||||
atom(C),
|
||||
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) :-
|
||||
'$skip_max_list'(_, _, Ls, Rs),
|
||||
( var(Rs) ->
|
||||
@@ -90,10 +132,15 @@ type(type).
|
||||
type(integer).
|
||||
type(atom).
|
||||
type(character).
|
||||
type(in_character).
|
||||
type(octet_character).
|
||||
type(octet_chars).
|
||||
type(chars).
|
||||
type(list).
|
||||
type(var).
|
||||
type(boolean).
|
||||
type(term).
|
||||
type(not_less_than_zero).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
can_be(Type, Term)
|
||||
@@ -117,11 +164,45 @@ can_be(Type, 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_(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_(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) :-
|
||||
'$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.
|
||||
|
||||
Predicates for reasoning about files and directories.
|
||||
@@ -65,52 +65,46 @@
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(charsio)).
|
||||
|
||||
list_of_chars(Cs) :-
|
||||
must_be(list, Cs),
|
||||
maplist(must_be(character), Cs).
|
||||
:- use_module(library(dcgs)).
|
||||
|
||||
directory_files(Directory, Files) :-
|
||||
list_of_chars(Directory),
|
||||
must_be(chars, Directory),
|
||||
can_be(list, Files),
|
||||
'$directory_files'(Directory, Files).
|
||||
|
||||
file_size(File, Size) :-
|
||||
file_must_exist(File, file_size/2),
|
||||
list_of_chars(File),
|
||||
can_be(integer, Size),
|
||||
'$file_size'(File, Size).
|
||||
|
||||
file_exists(File) :-
|
||||
list_of_chars(File),
|
||||
must_be(chars, File),
|
||||
'$file_exists'(File).
|
||||
|
||||
directory_exists(Directory) :-
|
||||
list_of_chars(Directory),
|
||||
must_be(chars, Directory),
|
||||
'$directory_exists'(Directory).
|
||||
|
||||
make_directory(Directory) :-
|
||||
list_of_chars(Directory),
|
||||
must_be(chars, Directory),
|
||||
'$make_directory'(Directory).
|
||||
|
||||
make_directory_path(Directory) :-
|
||||
list_of_chars(Directory),
|
||||
must_be(chars, Directory),
|
||||
'$make_directory_path'(Directory).
|
||||
|
||||
delete_file(File) :-
|
||||
file_must_exist(File, delete_file/1),
|
||||
list_of_chars(File),
|
||||
'$delete_file'(File).
|
||||
|
||||
rename_file(File, Renamed) :-
|
||||
file_must_exist(File, rename_file/2),
|
||||
list_of_chars(File),
|
||||
list_of_chars(Renamed),
|
||||
must_be(chars, Renamed),
|
||||
'$rename_file'(File, Renamed).
|
||||
|
||||
delete_directory(Directory) :-
|
||||
directory_must_exist(Directory, delete_directory/1),
|
||||
list_of_chars(Directory),
|
||||
must_be(chars, Directory),
|
||||
'$delete_directory'(Directory).
|
||||
|
||||
file_must_exist(File, Context) :-
|
||||
@@ -150,8 +144,7 @@ working_directory(Dir0, Dir) :-
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
path_canonical(Ps, Cs) :-
|
||||
must_be(list, Ps),
|
||||
maplist(must_be(character), Ps),
|
||||
must_be(chars, Ps),
|
||||
can_be(list, Cs),
|
||||
'$path_canonical'(Ps, Cs).
|
||||
|
||||
@@ -205,20 +198,20 @@ path_segments(Path, Segments) :-
|
||||
'$directory_separator'(Sep),
|
||||
( var(Path) ->
|
||||
must_be(list, Segments),
|
||||
maplist(list_of_chars, Segments),
|
||||
append_with_separator(Segments, Sep, Path)
|
||||
; list_of_chars(Path),
|
||||
maplist(must_be(chars), Segments),
|
||||
phrase(append_with_separator(Segments, Sep), Path)
|
||||
; must_be(chars, Path),
|
||||
path_to_segments(Path, Sep, Segments)
|
||||
).
|
||||
|
||||
append_with_separator([], _, []).
|
||||
append_with_separator([Segment|Segments], Sep, Path) :-
|
||||
append_with_separator_(Segments, Segment, Sep, Path).
|
||||
append_with_separator([], _) --> [].
|
||||
append_with_separator([Segment|Segments], Sep) -->
|
||||
append_with_separator_(Segments, Segment, Sep).
|
||||
|
||||
append_with_separator_([], Segment, _, Segment).
|
||||
append_with_separator_([Segment|Segments], Prev, Sep, Path) :-
|
||||
append(Prev, [Sep|Rest], Path),
|
||||
append_with_separator_(Segments, Segment, Sep, Rest).
|
||||
append_with_separator_([], Segment, _) --> seq(Segment).
|
||||
append_with_separator_([Segment|Segments], Prev, Sep) -->
|
||||
seq(Prev), [Sep],
|
||||
append_with_separator_(Segments, Segment, Sep).
|
||||
|
||||
path_to_segments(Path, Sep, Segments) :-
|
||||
( append(Front, [Sep|Ps], Path) ->
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
:- use_module(library(atts)).
|
||||
:- use_module(library(dcgs)).
|
||||
|
||||
:- meta_predicate freeze(?, 0).
|
||||
:- meta_predicate freeze(-, 0).
|
||||
|
||||
:- 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.
|
||||
|
||||
http_open(+Address, -Stream, +Options)
|
||||
@@ -7,12 +7,16 @@
|
||||
|
||||
Yields Stream to read the body of an HTTP reply from Address.
|
||||
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
|
||||
added in the future to give more control over the connection.
|
||||
Options supported:
|
||||
|
||||
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:
|
||||
|
||||
@@ -23,62 +27,42 @@
|
||||
|
||||
:- module(http_open, [http_open/3]).
|
||||
|
||||
:- use_module(library(sockets)).
|
||||
:- 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)).
|
||||
:- use_module(library(lists)).
|
||||
|
||||
http_open(Address, Stream, Options) :-
|
||||
must_be(list, Options),
|
||||
must_be(list, Address),
|
||||
once(phrase((seq(SchemeCs), "://", seq(Rest)), Address)),
|
||||
atom_chars(Scheme, SchemeCs),
|
||||
chars_host_url(Rest, Host, URL),
|
||||
connect(Scheme, Host, Stream0),
|
||||
format(Stream0, "\
|
||||
GET ~s HTTP/1.0\r\n\
|
||||
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).
|
||||
http_open(Address, Response, Options) :-
|
||||
parse_http_options(Options, OptionValues),
|
||||
( member(method(Method), OptionValues) -> true; Method = get),
|
||||
( member(data(Data), OptionValues) -> true; Data = []),
|
||||
( member(request_headers(RequestHeaders), OptionValues) -> true; RequestHeaders = ['user-agent'("Scryer Prolog")]),
|
||||
( member(status_code(Code), OptionValues) -> true; true),
|
||||
( member(headers(Headers), OptionValues) -> true; true),
|
||||
( member(size(Size), OptionValues) -> member('content-length'(Size), Headers); true),
|
||||
'$http_open'(Address, Response, Method, Code, Data, Headers, RequestHeaders).
|
||||
|
||||
handle_response('2', _, Stream, Stream). % ok
|
||||
handle_response('3', HeaderLines, Stream0, Stream) :- % redirect
|
||||
close(Stream0),
|
||||
once((member(Line, HeaderLines),
|
||||
phrase(("Location: ",seq(Location),"\r\n"), Line))),
|
||||
http_open(Location, Stream, []).
|
||||
parse_http_options(Options, OptionValues) :-
|
||||
maplist(parse_http_options_, Options, OptionValues).
|
||||
|
||||
% Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
|
||||
|
||||
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)
|
||||
parse_http_options_(method(Method), method(Method)) :-
|
||||
( var(Method) ->
|
||||
throw(error(instantiation_error, http_open/3))
|
||||
;
|
||||
member(Method, [get, post, put, delete, patch, head]) -> true
|
||||
;
|
||||
throw(error(domain_error(http_option, method(Method)), _))
|
||||
).
|
||||
|
||||
chars_host_url(Cs, Host, [/|Us]) :-
|
||||
( phrase((seq(Hs),"/",seq(Us)), Cs) ->
|
||||
true
|
||||
; Hs = Cs,
|
||||
Us = []
|
||||
),
|
||||
atom_chars(Host, Hs).
|
||||
parse_http_options_(data(Data), data(Data)) :-
|
||||
( var(Data) ->
|
||||
throw(error(instantiation_error, http_open/3))
|
||||
; true
|
||||
).
|
||||
|
||||
connect(https, Host, Stream) :-
|
||||
socket_client_open(Host:443, Stream0, []),
|
||||
atom_chars(Host, HostChars),
|
||||
tls_client_context(Context, [hostname(HostChars)]),
|
||||
tls_client_negotiate(Context, Stream0, Stream).
|
||||
connect(http, Host, Stream) :-
|
||||
socket_client_open(Host:80, Stream, []).
|
||||
parse_http_options_(request_headers(Headers), request_headers(Headers)) :-
|
||||
( var(Headers) ->
|
||||
throw(error(instantiation_error, http_open/3))
|
||||
; true
|
||||
).
|
||||
|
||||
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)
|
||||
Updated in March 2022 by Adrián Arroyo to use the Hyper backend
|
||||
Part of Scryer Prolog
|
||||
|
||||
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
|
||||
proxy like nginx in front of this server to have access to more advanced features
|
||||
(gzip compression, HTTPS, ...)
|
||||
It is based on Hyper, which allows for HTTP/1.0, HTTP/1.1 and HTTP/2. However,
|
||||
some advanced features that Hyper provides are still not accesible.
|
||||
|
||||
Usage
|
||||
==========
|
||||
@@ -41,37 +41,36 @@
|
||||
Some things that are still missing:
|
||||
- Read forms in multipart format
|
||||
- HTTP Basic Auth
|
||||
- Keep-Alive support
|
||||
- Session handling via cookies
|
||||
- HTML Templating
|
||||
|
||||
I place this code in the public domain. Use it in any way you want.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
:- module(http_server, [
|
||||
http_listen/2,
|
||||
http_headers/2,
|
||||
http_status_code/2,
|
||||
http_body/2,
|
||||
http_redirect/2,
|
||||
http_query/3,
|
||||
url_decode//1
|
||||
http_query/3
|
||||
]).
|
||||
|
||||
:- 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(lists)).
|
||||
:- use_module(library(iso_ext)).
|
||||
:- use_module(library(time)).
|
||||
:- 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) :-
|
||||
must_be(integer, Port),
|
||||
must_be(list, Handlers0),
|
||||
maplist(module_qualification(Module), Handlers0, Handlers),
|
||||
http_listen_(Port, Handlers).
|
||||
|
||||
@@ -79,49 +78,84 @@ module_qualification(M, H0, H) :-
|
||||
H0 =.. [Method, Path, Goal],
|
||||
H =.. [Method, Path, M:Goal].
|
||||
|
||||
% Server initialization
|
||||
http_listen_(Port, Handlers) :-
|
||||
must_be(integer, Port),
|
||||
must_be(list, Handlers),
|
||||
once(socket_server_open(Port, Socket)),
|
||||
format("Listening at port ~d\n", [Port]),
|
||||
accept_loop(Socket, Handlers).
|
||||
phrase(format_("0.0.0.0:~d", [Port]), Addr),
|
||||
'$http_listen'(Addr, HttpListener),!,
|
||||
format("Listening at ~s\n", [Addr]),
|
||||
http_loop(HttpListener, Handlers).
|
||||
|
||||
% Server loop
|
||||
accept_loop(Socket, Handlers) :-
|
||||
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
|
||||
),
|
||||
http_loop(HttpListener, Handlers) :-
|
||||
'$http_accept'(HttpListener, RequestMethod, RequestPath, RequestHeaders, RequestQuery, RequestStream, ResponseHandle),
|
||||
current_time(Time),
|
||||
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(_, _, _),
|
||||
(call(Handler, HttpRequest, HttpResponse) ->
|
||||
send_response(Stream, HttpResponse)
|
||||
; format(Stream, "HTTP/1.0 500 Internal Server Error\r\n\r\n", [])
|
||||
send_response(ResponseHandle, HttpResponse)
|
||||
; (
|
||||
'$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", [])
|
||||
)
|
||||
);(
|
||||
format(Stream, "HTTP/1.0 400 Bad Request\r\n\r\n", []) % bad format
|
||||
)
|
||||
; (
|
||||
'$http_answer'(ResponseHandle, 404, [], ResponseStream),
|
||||
call_cleanup(format(ResponseStream, "Not Found"), close(ResponseStream)))
|
||||
),
|
||||
! % Remove
|
||||
), close(Stream)),
|
||||
accept_loop(Socket, Handlers).
|
||||
http_loop(HttpListener, 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) :-
|
||||
member(H, Handlers),
|
||||
@@ -139,27 +173,6 @@ match_handler(Handlers, Method, Path, Handler) :-
|
||||
var(Var),
|
||||
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) -->
|
||||
{
|
||||
Pattern =.. Parts,
|
||||
@@ -183,76 +196,31 @@ path(Pattern) -->
|
||||
|
||||
path([]) --> [].
|
||||
|
||||
% Send responses
|
||||
send_response(Stream, http_response(StatusCode0, file(Filename), Headers)) :-
|
||||
default(StatusCode0, 200, StatusCode),
|
||||
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
|
||||
overwrite_header("connection"-"Close", Headers, Headers0),
|
||||
write_headers(Stream, Headers0),
|
||||
format(Stream, "\r\n", []),
|
||||
setup_call_cleanup(
|
||||
open(Filename, read, FileStream, [type(binary)]),
|
||||
pipe_bytes(FileStream, Stream),
|
||||
close(FileStream)
|
||||
).
|
||||
string_without(Not, [Char|String]) -->
|
||||
[Char],
|
||||
{
|
||||
\+ member(Char, Not)
|
||||
},
|
||||
string_without(Not, String).
|
||||
|
||||
send_response(Stream, http_response(StatusCode0, text(TextResponse), Headers)) :-
|
||||
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]).
|
||||
string_without(_, []) -->
|
||||
[].
|
||||
|
||||
send_response(Stream, http_response(StatusCode0, binary(BinaryResponse), Headers)) :-
|
||||
default(StatusCode0, 200, StatusCode),
|
||||
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).
|
||||
http_headers(http_request(Headers, _, _), Headers).
|
||||
http_headers(http_response(_, _, Headers), Headers).
|
||||
|
||||
default(Var, Default, Out) :-
|
||||
(var(Var) -> Out = Default
|
||||
; Var = Out
|
||||
).
|
||||
http_body(http_request(_, stream(StreamBody), _), bytes(BytesBody)) :- get_n_chars(StreamBody, _, BytesBody).
|
||||
http_body(http_request(_, stream(StreamBody), _), text(TextBody)) :- get_n_chars(StreamBody, _, TextBody).
|
||||
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([]) --> [].
|
||||
header([Key-Value|Headers]) -->
|
||||
format_("~s: ~s\r\n", [Key, Value]),
|
||||
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).
|
||||
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).
|
||||
|
||||
parse_queries([Key-Value|Queries]) -->
|
||||
string_without("=", Key0),
|
||||
@@ -278,94 +246,9 @@ parse_queries([Key-Value]) -->
|
||||
phrase(url_decode(Value), Value0)
|
||||
}.
|
||||
|
||||
map_parse_header(Header, HeaderKV) :-
|
||||
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(_, []) -->
|
||||
parse_queries([]) -->
|
||||
[].
|
||||
|
||||
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
|
||||
url_decode([Char|Chars]) -->
|
||||
[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,
|
||||
bb_get/2,
|
||||
bb_put/2,
|
||||
@@ -14,8 +9,9 @@
|
||||
partial_string_tail/2,
|
||||
setup_call_cleanup/3,
|
||||
call_nth/2,
|
||||
% variant/2,
|
||||
copy_term_nat/2]).
|
||||
copy_term_nat/2,
|
||||
asserta/2,
|
||||
assertz/2]).
|
||||
|
||||
:- use_module(library(error), [can_be/2,
|
||||
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)).
|
||||
|
||||
:- non_counted_backtracking setup_call_cleanup/3.
|
||||
|
||||
setup_call_cleanup(S, G, C) :-
|
||||
'$get_b_value'(B),
|
||||
'$call'(S),
|
||||
'$call_with_inference_counting'(call(S)),
|
||||
'$set_cp_by_default'(B),
|
||||
'$get_current_block'(Bb),
|
||||
( C = _:CC,
|
||||
'$call_with_default_policy'(var(CC)) ->
|
||||
var(CC) ->
|
||||
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,?)).
|
||||
|
||||
:- non_counted_backtracking scc_helper/3.
|
||||
|
||||
scc_helper(C, G, Bb) :-
|
||||
'$get_cp'(Cp),
|
||||
'$install_scc_cleaner'(C, NBb),
|
||||
call(G),
|
||||
'$call_with_inference_counting'(call(G)),
|
||||
( '$check_cp'(Cp) ->
|
||||
'$reset_block'(Bb),
|
||||
'$call_with_default_policy'(run_cleaners_without_handling(Cp))
|
||||
; '$call_with_default_policy'(true)
|
||||
run_cleaners_without_handling(Cp)
|
||||
; true
|
||||
; '$reset_block'(NBb),
|
||||
'$fail'
|
||||
).
|
||||
scc_helper(_, _, Bb) :-
|
||||
'$reset_block'(Bb),
|
||||
'$get_ball'(Ball),
|
||||
'$erase_ball',
|
||||
'$call_with_default_policy'(run_cleaners_with_handling),
|
||||
'$call_with_default_policy'(throw(Ball)).
|
||||
'$push_ball_stack',
|
||||
run_cleaners_with_handling,
|
||||
'$pop_from_ball_stack',
|
||||
'$unwind_stack'.
|
||||
scc_helper(_, _, _) :-
|
||||
'$get_cp'(Cp),
|
||||
'$call_with_default_policy'(run_cleaners_without_handling(Cp)),
|
||||
run_cleaners_without_handling(Cp),
|
||||
'$fail'.
|
||||
|
||||
:- non_counted_backtracking run_cleaners_with_handling/0.
|
||||
|
||||
run_cleaners_with_handling :-
|
||||
'$get_scc_cleaner'(C),
|
||||
'$get_level'(B),
|
||||
'$call_with_default_policy'(catch(C, _, true)),
|
||||
catch(C, _, true),
|
||||
'$set_cp_by_default'(B),
|
||||
'$call_with_default_policy'(run_cleaners_with_handling).
|
||||
run_cleaners_with_handling.
|
||||
run_cleaners_with_handling :-
|
||||
'$restore_cut_policy'.
|
||||
|
||||
:- non_counted_backtracking run_cleaners_without_handling/1.
|
||||
|
||||
run_cleaners_without_handling(Cp) :-
|
||||
'$get_scc_cleaner'(C),
|
||||
'$get_level'(B),
|
||||
call(C),
|
||||
'$set_cp_by_default'(B),
|
||||
'$call_with_default_policy'(run_cleaners_without_handling(Cp)).
|
||||
run_cleaners_without_handling(Cp).
|
||||
run_cleaners_without_handling(Cp) :-
|
||||
'$set_cp_by_default'(Cp),
|
||||
'$restore_cut_policy'.
|
||||
@@ -120,6 +121,7 @@ run_cleaners_without_handling(Cp) :-
|
||||
% call_with_inference_limit
|
||||
|
||||
:- non_counted_backtracking end_block/4.
|
||||
|
||||
end_block(_, Bb, NBb, _L) :-
|
||||
'$clean_up_block'(NBb),
|
||||
'$reset_block'(Bb).
|
||||
@@ -129,13 +131,19 @@ end_block(B, _Bb, NBb, L) :-
|
||||
'$fail'.
|
||||
|
||||
:- 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),
|
||||
'$call_with_default_policy'(throw(E)).
|
||||
'$pop_from_ball_stack',
|
||||
'$unwind_stack'.
|
||||
|
||||
:- meta_predicate(call_with_inference_limit(0, ?, ?)).
|
||||
|
||||
:- non_counted_backtracking call_with_inference_limit/3.
|
||||
|
||||
call_with_inference_limit(G, L, R) :-
|
||||
( integer(L) ->
|
||||
( L < 0 ->
|
||||
@@ -148,7 +156,7 @@ call_with_inference_limit(G, L, R) :-
|
||||
),
|
||||
'$get_current_block'(Bb),
|
||||
'$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).
|
||||
|
||||
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) :-
|
||||
'$install_new_block'(NBb),
|
||||
'$install_inference_counter'(B, L, Count0),
|
||||
'$call'(G),
|
||||
'$call_with_inference_counting'(call(G)),
|
||||
'$inference_level'(R, B),
|
||||
'$remove_inference_counter'(B, Count1),
|
||||
'$call_with_default_policy'(is(Diff, L - (Count1 - Count0))),
|
||||
'$call_with_default_policy'(end_block(B, Bb, NBb, Diff)).
|
||||
Diff is L - (Count1 - Count0),
|
||||
end_block(B, Bb, NBb, Diff).
|
||||
call_with_inference_limit(_, _, R, Bb, B) :-
|
||||
'$reset_block'(Bb),
|
||||
'$remove_inference_counter'(B, _),
|
||||
( '$get_ball'(Ball),
|
||||
'$push_ball_stack',
|
||||
'$get_level'(Cp),
|
||||
'$set_cp_by_default'(Cp)
|
||||
; '$remove_call_policy_check'(B),
|
||||
'$fail'
|
||||
),
|
||||
'$erase_ball',
|
||||
'$call_with_default_policy'(handle_ile(B, Ball, R)).
|
||||
handle_ile(B, Ball, R).
|
||||
|
||||
partial_string(String, L, L0) :-
|
||||
( String == [] ->
|
||||
@@ -203,33 +211,55 @@ partial_string_tail(String, Tail) :-
|
||||
|
||||
call_nth(Goal, N) :-
|
||||
can_be(integer, N),
|
||||
( integer(N), N =< 0,
|
||||
domain_error(positive_integer, N, call_nth/2)
|
||||
( integer(N) ->
|
||||
( N < 0 ->
|
||||
domain_error(not_less_than_zero, N, call_nth/2)
|
||||
; N > 0
|
||||
)
|
||||
; true
|
||||
),
|
||||
setup_call_cleanup(call_nth_nesting(ID),
|
||||
setup_call_cleanup(call_nth_nesting(C, ID),
|
||||
( Goal,
|
||||
retract(i_call_nth_nesting(ID,N0)),
|
||||
bb_get(ID, N0),
|
||||
N1 is N0 + 1,
|
||||
asserta(i_call_nth_nesting(ID,N1)),
|
||||
bb_put(ID, N1),
|
||||
( integer(N) ->
|
||||
N = N1,
|
||||
!
|
||||
; N = N1
|
||||
)
|
||||
),
|
||||
( retract(i_call_nth_nesting(ID,_)),
|
||||
retract(i_call_nth_counter(ID))
|
||||
( bb_get(i_call_nth_counter, C) ->
|
||||
C1 is C - 1,
|
||||
bb_put(i_call_nth_counter, C1)
|
||||
; true
|
||||
)).
|
||||
|
||||
call_nth_nesting(ID) :-
|
||||
( i_call_nth_counter(ID0) ->
|
||||
ID is ID0 + 1
|
||||
; ID = 0
|
||||
call_nth_nesting(C, ID) :-
|
||||
( bb_get(i_call_nth_counter, C0) ->
|
||||
C is C0 + 1
|
||||
; C = 0
|
||||
),
|
||||
asserta(i_call_nth_nesting(ID, 0)),
|
||||
asserta(i_call_nth_counter(ID)).
|
||||
number_chars(C, Cs),
|
||||
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_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,
|
||||
memberchk/2, reverse/2, length/2, maplist/2,
|
||||
maplist/3, maplist/4, maplist/5, maplist/6,
|
||||
maplist/7, maplist/8, maplist/9, same_length/2, 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,
|
||||
list_min/2, permutation/2]).
|
||||
|
||||
@@ -50,13 +50,20 @@
|
||||
:- meta_predicate foldl(3, ?, ?, ?).
|
||||
:- 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) :-
|
||||
'$skip_max_list'(M, N, Xs0,Xs),
|
||||
!,
|
||||
( 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)
|
||||
; 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(_, N) :-
|
||||
@@ -65,16 +72,29 @@ length(_, N) :-
|
||||
length(_, N) :-
|
||||
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([_|Xs], N, M) :-
|
||||
M1 is M + 1,
|
||||
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, [_|Xs]) :- member(X, Xs).
|
||||
@@ -223,27 +243,82 @@ unify_same(E-V, Prev-Var, E-V) :-
|
||||
).
|
||||
|
||||
|
||||
nth0(N, Es, E) :-
|
||||
can_be(integer, N),
|
||||
can_be(list, Es),
|
||||
( integer(N) ->
|
||||
nth0_index(N, Es, E)
|
||||
; nth0_search(N, Es, E)
|
||||
nth0(N, Es0, E) :-
|
||||
nonvar(N),
|
||||
'$skip_max_list'(Skip, N, Es0,Es1),
|
||||
!,
|
||||
( Skip == N
|
||||
-> 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) :- !.
|
||||
nth0_index(N, [_|Es], E) :-
|
||||
N > 0,
|
||||
N1 is N - 1,
|
||||
nth0_index(N1, Es, E).
|
||||
skipn(N0, Es0,Es) :-
|
||||
N0>0,
|
||||
!, % should not be necessary #1028
|
||||
N1 is N0-1,
|
||||
Es0 = [_|Es1],
|
||||
skipn(N1, Es1,Es).
|
||||
skipn(0, Es,Es).
|
||||
|
||||
nth0_search(N, Es, E) :-
|
||||
nth0_search(0, N, Es, E).
|
||||
|
||||
nth0_search(N, N, [E|_], E).
|
||||
nth0_search(N0, N, [_|Es], E) :-
|
||||
nth0_el(N0,N, E0,E, Es0) :-
|
||||
Es0 == [],
|
||||
!, % indexing
|
||||
N0 = N,
|
||||
E0 = E.
|
||||
nth0_el(N,N, E,E, _).
|
||||
nth0_el(N0,N, _,E, [E0|Es0]) :-
|
||||
N1 is N0+1,
|
||||
nth0_search(N1, N, Es, E).
|
||||
nth0_el(N1,N, E0,E, Es0).
|
||||
|
||||
nth1(N, Es0, E) :-
|
||||
N \== 0,
|
||||
nth0(N, [_|Es0], 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) :-
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
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([A-B|ABs], [A|As], [B|Bs]) :-
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
Our goal is to encourage the use of definite clause grammars (DCGs)
|
||||
for describing strings. The predicates phrase_from_file/[2,3],
|
||||
phrase_to_file/2 and phrase_to_stream/2 let us apply DCGs transparently
|
||||
to files and streams, and therefore decouple side-effects from
|
||||
declarative descriptions.
|
||||
phrase_to_file/[2,3] and phrase_to_stream/2 let us apply DCGs
|
||||
transparently to files and streams, and therefore decouple side-effects
|
||||
from declarative descriptions.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
:- 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_to_file(2, ?)).
|
||||
:- meta_predicate(phrase_to_file(2, ?, ?)).
|
||||
:- meta_predicate(phrase_to_stream(2, ?)).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -90,7 +91,7 @@ phrase_to_stream(GRBody, Stream) :-
|
||||
must_be(chars, Cs),
|
||||
( stream_property(Stream, type(binary)) ->
|
||||
( '$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
|
||||
|
||||
@@ -30,13 +30,10 @@ non(false, true).
|
||||
|
||||
:- meta_predicate(tfilter(2, ?, ?)).
|
||||
|
||||
tfilter(C_2, Es, Fs) :-
|
||||
i_tfilter(Es, C_2, Fs).
|
||||
|
||||
i_tfilter([], _, []).
|
||||
i_tfilter([E|Es], C_2, Fs0) :-
|
||||
tfilter(_, [], []).
|
||||
tfilter(C_2, [E|Es], Fs0) :-
|
||||
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, ?, ?, ?)).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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.
|
||||
|
||||
Currently, two predicates are provided:
|
||||
@@ -10,16 +10,18 @@
|
||||
|
||||
These predicates parse HTML and XML documents, respectively.
|
||||
|
||||
Source must be a stream, specified as stream(S), or a file,
|
||||
specified as file(Name), where Name is a list of characters, or a
|
||||
list of characters with the document contents.
|
||||
Source must be one of:
|
||||
|
||||
- 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,
|
||||
represented as a list of elements where each is of the form:
|
||||
|
||||
* a list of characters, representing text
|
||||
* 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:
|
||||
Key is an atom, and Value is a list of characters
|
||||
- Children is a list of elements as specified here.
|
||||
@@ -61,21 +63,32 @@
|
||||
:- use_module(library(charsio)).
|
||||
|
||||
load_html(Source, Es, Options) :-
|
||||
must_be_source(Source, load_html/3),
|
||||
must_be(list, Options),
|
||||
load_structure_(Source, Es, Options, html).
|
||||
load_xml(Source, Es, Options) :-
|
||||
must_be_source(Source, load_xml/3),
|
||||
must_be(list, Options),
|
||||
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_([C|Cs], [E], Options, What) :-
|
||||
load_(What, [C|Cs], E, Options).
|
||||
load_structure_(file(Fs), [E], Options, What) :-
|
||||
must_be(list, Options),
|
||||
must_be(list, Fs),
|
||||
atom_chars(File, Fs),
|
||||
once(phrase_from_file(seq(Cs), File)),
|
||||
once(phrase_from_file(seq(Cs), Fs)),
|
||||
load_(What, Cs, E, Options).
|
||||
load_structure_(stream(Stream), [E], Options, What) :-
|
||||
must_be(list, Options),
|
||||
get_n_chars(Stream, _, Cs),
|
||||
load_(What, Cs, E, Options).
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
:- module(si, [atom_si/1,
|
||||
integer_si/1,
|
||||
atomic_si/1,
|
||||
list_si/1]).
|
||||
list_si/1,
|
||||
chars_si/1]).
|
||||
|
||||
:- use_module(library(lists)).
|
||||
|
||||
@@ -42,6 +43,16 @@ integer_si(I) :-
|
||||
atomic_si(AC) :-
|
||||
functor(AC,_,0).
|
||||
|
||||
list_si(L) :-
|
||||
\+ \+ length(L, _),
|
||||
sort(L, _).
|
||||
% list_si(L) :-
|
||||
% \+ \+ length(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).
|
||||
|
||||
|
||||
:- meta_predicate start_tabling(?, 0).
|
||||
:- meta_predicate start_tabling(?, :).
|
||||
|
||||
start_tabling(Wrapper,Worker) :-
|
||||
put_new_trie_table_link,
|
||||
|
||||
@@ -119,7 +119,7 @@ report_time(ID) :-
|
||||
time_state(ID, T0),
|
||||
'$cpu_now'(T),
|
||||
Time is T - T0,
|
||||
( bb_get('$first_answer', true) ->
|
||||
( bb_get('$answer_count', 0) ->
|
||||
Pre = " ", Post = ""
|
||||
; Pre = "", Post = " "
|
||||
),
|
||||
|
||||
@@ -26,22 +26,22 @@
|
||||
|
||||
:- use_module(library(http/http_open)).
|
||||
:- use_module(library(sgml)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(xpath)).
|
||||
:- use_module(library(dcgs)).
|
||||
|
||||
link_to_pl_file(File) :-
|
||||
http_open("https://github.com/mthom/scryer-prolog", S, []),
|
||||
load_html(stream(S), DOM, []),
|
||||
xpath(DOM, //a(@href), File),
|
||||
append(_, ".pl", File).
|
||||
phrase((...,".pl"), File).
|
||||
|
||||
Yielding:
|
||||
|
||||
?- link_to_pl_file(File).
|
||||
%@ File = "/mthom/scryer-prolog/blob/master/src/lib/tabling.pl"
|
||||
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/dif.pl"
|
||||
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/freeze.pl"
|
||||
%@ ; ...
|
||||
%@ File = "/mthom/scryer-prolog/blob/master/src/lib/dcgs.pl"
|
||||
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/pio.pl"
|
||||
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/tabling.pl"
|
||||
%@ ; ... .
|
||||
|
||||
Parts of the original functionality may not yet work. Please
|
||||
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> {
|
||||
if n1 == 0 {
|
||||
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> {
|
||||
let f1 = result_f(&n1, rnd_f);
|
||||
let f2 = result_f(&n2, rnd_f);
|
||||
let f1 = result_f(&n1);
|
||||
let f2 = result_f(&n2);
|
||||
|
||||
let stub_gen = || {
|
||||
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 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!(
|
||||
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> {
|
||||
if n2.is_negative() && n1.is_zero() {
|
||||
let stub_gen = move || functor_stub(culprit, 2);
|
||||
|
||||
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)
|
||||
};
|
||||
|
||||
try_numeric_result!(result_f(&n, rnd_f), stub_gen)
|
||||
try_numeric_result!(result_f(&n), stub_gen)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -430,8 +419,8 @@ where
|
||||
functor_stub(is_atom, 2)
|
||||
};
|
||||
|
||||
let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?;
|
||||
let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f);
|
||||
let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
|
||||
let f1 = result_f(&Number::Float(OrderedFloat(f(f1))));
|
||||
|
||||
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)
|
||||
};
|
||||
|
||||
let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?;
|
||||
let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?;
|
||||
let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
|
||||
let f2 = try_numeric_result!(result_f(&n2), stub_gen)?;
|
||||
|
||||
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)
|
||||
};
|
||||
|
||||
let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?;
|
||||
let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?;
|
||||
let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
|
||||
let f2 = try_numeric_result!(result_f(&n2), stub_gen)?;
|
||||
|
||||
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) => {
|
||||
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> {
|
||||
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() {
|
||||
if value.is_forwarded() {
|
||||
if value.get_forwarding_bit() {
|
||||
std::mem::drop(iter);
|
||||
|
||||
let (name, arity) = read_heap_cell!(value,
|
||||
(HeapCellValueTag::Atom, (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)
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
|
||||
let err = self.instantiation_error();
|
||||
return Err(self.error_form(err, stub_gen()));
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
);
|
||||
|
||||
std::mem::drop(iter);
|
||||
|
||||
let evaluable_error = self.evaluable_error(name, arity);
|
||||
let stub = stub_gen();
|
||||
|
||||
return Err(self.error_form(evaluable_error, stub));
|
||||
return Err(self.error_form(evaluable_error, stub_gen()));
|
||||
}
|
||||
|
||||
let value = unmark_cell_bits!(value);
|
||||
|
||||
read_heap_cell!(value,
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 2 {
|
||||
let a1 = self.interms.pop().unwrap();
|
||||
let a2 = self.interms.pop().unwrap();
|
||||
let a1 = self.interms.pop().unwrap();
|
||||
|
||||
match name {
|
||||
atom!("+") => self.interms.push(drop_iter_on_err!(
|
||||
@@ -1184,7 +1182,7 @@ impl MachineState {
|
||||
|
||||
let result = arena_alloc!(
|
||||
drop_iter_on_err!(self, iter, rdiv(r1, r2)),
|
||||
self.arena
|
||||
&mut self.arena
|
||||
);
|
||||
|
||||
self.interms.push(Number::Rational(result));
|
||||
@@ -1278,7 +1276,7 @@ impl MachineState {
|
||||
atom!("\\") => self.interms.push(
|
||||
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);
|
||||
std::mem::drop(iter);
|
||||
@@ -1324,7 +1322,7 @@ impl MachineState {
|
||||
self.interms.push(Number::Fixnum(n));
|
||||
}
|
||||
(HeapCellValueTag::F64, fl) => {
|
||||
self.interms.push(Number::Float(**fl));
|
||||
self.interms.push(Number::Float(*fl));
|
||||
}
|
||||
(HeapCellValueTag::Cons, ptr) => {
|
||||
match_untyped_arena_ptr!(ptr,
|
||||
@@ -1334,9 +1332,6 @@ impl MachineState {
|
||||
(ArenaHeaderTag::Rational, r) => {
|
||||
self.interms.push(Number::Rational(r));
|
||||
}
|
||||
(ArenaHeaderTag::F64, fl) => {
|
||||
self.interms.push(Number::Float(*fl));
|
||||
}
|
||||
_ => {
|
||||
std::mem::drop(iter);
|
||||
|
||||
|
||||
@@ -28,11 +28,13 @@ call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
|
||||
sort(Modules0, Modules),
|
||||
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]) :-
|
||||
catch(Module:verify_attributes(Var, Value, Goals),
|
||||
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
|
||||
Goals = []),
|
||||
error(E, verify_attributes/3),
|
||||
error_handler(Module, E, Goals)),
|
||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||
verify_attrs([], _, _, []).
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use crate::atom_table::*;
|
||||
use crate::codegen::*;
|
||||
use crate::debray_allocator::*;
|
||||
use crate::forms::*;
|
||||
use crate::indexing::{merge_clause_index, remove_index};
|
||||
use crate::instructions::*;
|
||||
@@ -12,8 +11,6 @@ use crate::machine::term_stream::*;
|
||||
use crate::machine::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use slice_deque::{sdeq, SliceDeque};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::mem;
|
||||
@@ -49,13 +46,13 @@ pub(super) fn bootstrapping_compile(
|
||||
|
||||
// throw errors if declaration or query found.
|
||||
pub(super) fn compile_relation(
|
||||
cg: &mut CodeGenerator<DebrayAllocator>,
|
||||
cg: &mut CodeGenerator,
|
||||
tl: &TopLevel,
|
||||
) -> Result<Code, CompilationError> {
|
||||
match tl {
|
||||
&TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
|
||||
&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),
|
||||
}
|
||||
}
|
||||
@@ -89,7 +86,7 @@ pub(super) fn compile_appendix(
|
||||
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 decl_code = compile_relation(&mut cg, &tl)?;
|
||||
@@ -409,7 +406,7 @@ fn merge_indexed_subsequences(
|
||||
|
||||
*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,
|
||||
retraction_info: &mut RetractionInfo,
|
||||
) -> usize {
|
||||
let clause_index_info = skeleton.clauses.remove(target_pos);
|
||||
let clause_clause_loc = skeleton.core.clause_clause_locs.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).unwrap();
|
||||
|
||||
if target_pos < skeleton.core.clause_assert_margin {
|
||||
skeleton.core.clause_assert_margin -= 1;
|
||||
@@ -788,7 +785,7 @@ fn remove_non_leading_clause(
|
||||
|
||||
*o = 0;
|
||||
|
||||
Some(IndexPtr::Index(preceding_choice_instr_loc + 1))
|
||||
Some(IndexPtr::index(preceding_choice_instr_loc + 1))
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
@@ -823,7 +820,7 @@ fn finalize_retract(
|
||||
retraction_info,
|
||||
&compilation_target,
|
||||
key,
|
||||
&code_index,
|
||||
code_index,
|
||||
index_ptr,
|
||||
);
|
||||
}
|
||||
@@ -852,9 +849,9 @@ fn remove_leading_unindexed_clause(
|
||||
retraction_info,
|
||||
);
|
||||
|
||||
Some(IndexPtr::Index(index_ptr))
|
||||
Some(IndexPtr::index(index_ptr))
|
||||
} else {
|
||||
Some(IndexPtr::DynamicUndefined)
|
||||
Some(IndexPtr::dynamic_undefined())
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -887,7 +884,7 @@ fn prepend_compiled_clause(
|
||||
global_clock_tick: usize,
|
||||
) -> IndexPtr {
|
||||
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 head_arg_num = skeleton.clauses[1].opt_arg_index_key.arg_num();
|
||||
@@ -995,7 +992,7 @@ fn prepend_compiled_clause(
|
||||
|
||||
merge_clause_index(
|
||||
target_indexing_line,
|
||||
&mut skeleton.clauses,
|
||||
skeleton.clauses.make_contiguous(),
|
||||
&skeleton.core.retracted_dynamic_clauses,
|
||||
clause_loc + 2, // == skeleton.clauses[0].clause_start
|
||||
AppendOrPrepend::Prepend,
|
||||
@@ -1134,9 +1131,9 @@ fn prepend_compiled_clause(
|
||||
};
|
||||
|
||||
if skeleton.core.is_dynamic {
|
||||
IndexPtr::DynamicIndex(clause_loc)
|
||||
IndexPtr::dynamic_index(clause_loc)
|
||||
} else {
|
||||
IndexPtr::Index(clause_loc)
|
||||
IndexPtr::index(clause_loc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1189,7 +1186,7 @@ fn append_compiled_clause(
|
||||
|
||||
merge_clause_index(
|
||||
target_indexing_line,
|
||||
&mut skeleton.clauses[lower_bound..],
|
||||
&mut skeleton.clauses.make_contiguous()[lower_bound..],
|
||||
&skeleton.core.retracted_dynamic_clauses,
|
||||
clause_loc,
|
||||
AppendOrPrepend::Append,
|
||||
@@ -1212,7 +1209,11 @@ fn append_compiled_clause(
|
||||
);
|
||||
|
||||
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| {
|
||||
if skeleton.core.is_dynamic {
|
||||
IndexPtr::DynamicIndex(p)
|
||||
IndexPtr::dynamic_index(p)
|
||||
} else {
|
||||
IndexPtr::Index(p)
|
||||
IndexPtr::index(p)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1305,8 +1306,8 @@ fn print_overwrite_warning(
|
||||
}
|
||||
}
|
||||
|
||||
match code_ptr {
|
||||
IndexPtr::DynamicUndefined | IndexPtr::Undefined => return,
|
||||
match code_ptr.tag() {
|
||||
IndexPtrTag::DynamicUndefined | IndexPtrTag::Undefined => return,
|
||||
_ if is_dynamic => return,
|
||||
_ => {}
|
||||
}
|
||||
@@ -1338,12 +1339,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
term: Term,
|
||||
settings: CodeGenSettings,
|
||||
) -> 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 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,
|
||||
settings,
|
||||
);
|
||||
@@ -1378,7 +1379,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
let mut code_ptr = code_len;
|
||||
|
||||
let mut clauses = vec![];
|
||||
let mut preprocessor = Preprocessor::new();
|
||||
let mut preprocessor = Preprocessor::new(settings);
|
||||
|
||||
for term in predicates.predicates.drain(0..) {
|
||||
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 mut cg = CodeGenerator::<DebrayAllocator>::new(
|
||||
let mut cg = CodeGenerator::new(
|
||||
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
||||
settings,
|
||||
);
|
||||
@@ -1402,7 +1403,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
)?;
|
||||
|
||||
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() {
|
||||
clause_index_info.clause_start += code_len;
|
||||
@@ -1430,7 +1431,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
skeleton
|
||||
.core
|
||||
.clause_clause_locs
|
||||
.extend_from_slice(&clause_clause_locs[0..]);
|
||||
.extend(&clause_clause_locs.make_contiguous()[0..]);
|
||||
|
||||
self.payload.retraction_info
|
||||
.push_record(RetractionRecord::SkeletonClauseTruncateBack(
|
||||
@@ -1443,7 +1444,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
cg.skeleton
|
||||
.core
|
||||
.clause_clause_locs
|
||||
.extend_from_slice(&clause_clause_locs[0..]);
|
||||
.extend(&clause_clause_locs.make_contiguous()[0..]);
|
||||
|
||||
let skeleton = cg.skeleton;
|
||||
|
||||
@@ -1470,16 +1471,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
);
|
||||
|
||||
let index_ptr = if settings.is_dynamic() {
|
||||
IndexPtr::DynamicIndex(code_ptr)
|
||||
IndexPtr::dynamic_index(code_ptr)
|
||||
} else {
|
||||
IndexPtr::Index(code_ptr)
|
||||
IndexPtr::index(code_ptr)
|
||||
};
|
||||
|
||||
set_code_index(
|
||||
&mut self.payload.retraction_info,
|
||||
&predicates.compilation_target,
|
||||
key,
|
||||
&code_index,
|
||||
code_index,
|
||||
index_ptr,
|
||||
);
|
||||
|
||||
@@ -1491,7 +1492,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
&mut self,
|
||||
compilation_target: &CompilationTarget,
|
||||
key: &PredicateKey,
|
||||
clause_clause_locs: SliceDeque<usize>,
|
||||
mut clause_clause_locs: VecDeque<usize>,
|
||||
) {
|
||||
let listing_src_file_name = self.listing_src_file_name();
|
||||
|
||||
@@ -1515,7 +1516,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
|
||||
skeleton
|
||||
.clause_clause_locs
|
||||
.extend_from_slice(&clause_clause_locs[0..]);
|
||||
.extend(&clause_clause_locs.make_contiguous()[0..]);
|
||||
}
|
||||
None => {
|
||||
let mut skeleton = LocalPredicateSkeleton::new();
|
||||
@@ -1703,7 +1704,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
&mut self.payload.retraction_info,
|
||||
&compilation_target,
|
||||
key,
|
||||
&code_index,
|
||||
code_index,
|
||||
new_code_ptr,
|
||||
);
|
||||
}
|
||||
@@ -1744,7 +1745,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
&mut self.payload.retraction_info,
|
||||
&compilation_target,
|
||||
key,
|
||||
&code_index,
|
||||
code_index,
|
||||
new_code_ptr,
|
||||
);
|
||||
|
||||
@@ -1869,7 +1870,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
skeleton.clauses[target_pos].clause_start;
|
||||
|
||||
let index_ptr_opt = if target_pos == 0 {
|
||||
Some(IndexPtr::Index(clause_loc))
|
||||
Some(IndexPtr::index(clause_loc))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -1968,7 +1969,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
code,
|
||||
later_indexing_loc,
|
||||
0..target_pos - lower_bound,
|
||||
&mut skeleton.clauses[lower_bound..],
|
||||
&mut skeleton.clauses.make_contiguous()[lower_bound..],
|
||||
&skeleton.core.retracted_dynamic_clauses,
|
||||
&mut self.payload.retraction_info,
|
||||
);
|
||||
@@ -1993,7 +1994,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
code,
|
||||
target_indexing_loc,
|
||||
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,
|
||||
&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() => {
|
||||
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()
|
||||
.cloned()
|
||||
.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()
|
||||
.cloned()
|
||||
.collect(),
|
||||
.collect()
|
||||
}
|
||||
None => {
|
||||
unreachable!()
|
||||
}
|
||||
@@ -2381,13 +2384,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
match self.wam_prelude.indices.modules.get_mut(&filename) {
|
||||
Some(ref mut module) => {
|
||||
let index_ptr = code_index.get();
|
||||
let code_index = module.code_dir.entry(key).or_insert(code_index);
|
||||
let code_index = module.code_dir.entry(key)
|
||||
.or_insert(code_index)
|
||||
.clone();
|
||||
|
||||
set_code_index(
|
||||
&mut self.payload.retraction_info,
|
||||
&CompilationTarget::Module(filename),
|
||||
key,
|
||||
&code_index,
|
||||
code_index,
|
||||
index_ptr,
|
||||
);
|
||||
}
|
||||
@@ -2415,3 +2420,54 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
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::machine::get_structure_index;
|
||||
use crate::machine::stack::*;
|
||||
use crate::types::*;
|
||||
|
||||
@@ -248,6 +249,14 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
let hcv = self.target[addr + 1 + i];
|
||||
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) => {
|
||||
*self.value_at_scan() = str_loc_as_cell!(h);
|
||||
|
||||
@@ -57,19 +57,28 @@ impl MachineState {
|
||||
let a2 = self.registers[2];
|
||||
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,
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
debug_assert_eq!(arity, 0);
|
||||
check_atom(self, name, arity)?;
|
||||
}
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||
.get_name_and_arity();
|
||||
|
||||
match name {
|
||||
atom!(">") | atom!("<") | atom!("=") if arity == 2 => {
|
||||
}
|
||||
_ => {
|
||||
let err = self.domain_error(DomainErrorType::Order, a1);
|
||||
return Err(self.error_form(err, stub_gen()));
|
||||
}
|
||||
}
|
||||
check_atom(self, name, arity)?;
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
|
||||
}
|
||||
@@ -164,8 +173,7 @@ impl MachineState {
|
||||
match self.get_number(&at)? {
|
||||
Number::Fixnum(n) => self.unify_fixnum(n, n1),
|
||||
Number::Float(n) => {
|
||||
// TODO: argghh.. allocate floats to their own area.
|
||||
let n = arena_alloc!(n, &mut self.arena);
|
||||
let n = float_alloc!(n.into_inner(), self.arena);
|
||||
self.unify_f64(n, n1)
|
||||
}
|
||||
Number::Integer(n) => self.unify_big_int(n, n1),
|
||||
@@ -190,7 +198,7 @@ impl Machine {
|
||||
let value = self.machine_st.registers[2];
|
||||
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];
|
||||
self.machine_st.unify_atom(atom!("end_of_file"), value);
|
||||
}
|
||||
@@ -362,13 +370,19 @@ impl Machine {
|
||||
debug_assert!(arity == 0);
|
||||
c
|
||||
}
|
||||
(HeapCellValueTag::Str) => {
|
||||
s
|
||||
(HeapCellValueTag::Str, st) => {
|
||||
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) => {
|
||||
match ptr.get_tag() {
|
||||
ArenaHeaderTag::Rational | ArenaHeaderTag::Integer |
|
||||
ArenaHeaderTag::F64 => {
|
||||
ArenaHeaderTag::Rational | ArenaHeaderTag::Integer => {
|
||||
c
|
||||
}
|
||||
_ => {
|
||||
@@ -418,20 +432,20 @@ impl Machine {
|
||||
Literal::Fixnum(n)
|
||||
}
|
||||
(HeapCellValueTag::F64, f) => {
|
||||
Literal::Float(f)
|
||||
Literal::Float(f.as_offset())
|
||||
}
|
||||
(HeapCellValueTag::Atom, (atom, arity)) => {
|
||||
debug_assert_eq!(arity, 0);
|
||||
Literal::Atom(atom)
|
||||
}
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
Literal::Atom(cell_as_atom_cell!(self.machine_st.heap[s]).get_name())
|
||||
}
|
||||
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||
match_untyped_arena_ptr!(cons_ptr,
|
||||
(ArenaHeaderTag::Rational, r) => {
|
||||
Literal::Rational(r)
|
||||
}
|
||||
(ArenaHeaderTag::F64, f) => {
|
||||
Literal::Float(F64Ptr(f))
|
||||
}
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
Literal::Integer(n)
|
||||
}
|
||||
@@ -603,6 +617,7 @@ impl Machine {
|
||||
&mut self.machine_st,
|
||||
try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen)
|
||||
);
|
||||
|
||||
self.machine_st.p += 1;
|
||||
}
|
||||
&Instruction::Mul(ref a1, ref a2, t) => {
|
||||
@@ -681,7 +696,7 @@ impl Machine {
|
||||
|
||||
self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!(
|
||||
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;
|
||||
@@ -694,6 +709,7 @@ impl Machine {
|
||||
&mut self.machine_st,
|
||||
int_floor_div(n1, n2, &mut self.machine_st.arena)
|
||||
);
|
||||
|
||||
self.machine_st.p += 1;
|
||||
}
|
||||
&Instruction::IDiv(ref a1, ref a2, t) => {
|
||||
@@ -704,6 +720,7 @@ impl Machine {
|
||||
&mut self.machine_st,
|
||||
idiv(n1, n2, &mut self.machine_st.arena)
|
||||
);
|
||||
|
||||
self.machine_st.p += 1;
|
||||
}
|
||||
&Instruction::Abs(ref a1, t) => {
|
||||
@@ -715,7 +732,7 @@ impl Machine {
|
||||
&Instruction::Sign(ref a1, t) => {
|
||||
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;
|
||||
}
|
||||
&Instruction::Neg(ref a1, t) => {
|
||||
@@ -1004,23 +1021,14 @@ impl Machine {
|
||||
match self.find_living_dynamic_else(p + next_i) {
|
||||
Some(_) => {
|
||||
self.retry_me_else(next_i);
|
||||
|
||||
try_or_throw!(
|
||||
self.machine_st,
|
||||
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
|
||||
);
|
||||
}
|
||||
None => {
|
||||
self.trust_me();
|
||||
|
||||
try_or_throw!(
|
||||
self.machine_st,
|
||||
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.trust_me();
|
||||
}
|
||||
|
||||
try_or_throw!(
|
||||
self.machine_st,
|
||||
@@ -1029,7 +1037,6 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
self.machine_st.fail = true;
|
||||
}
|
||||
@@ -1085,23 +1092,14 @@ impl Machine {
|
||||
match self.find_living_dynamic_else(p + next_i) {
|
||||
Some(_) => {
|
||||
self.retry_me_else(next_i);
|
||||
|
||||
try_or_throw!(
|
||||
self.machine_st,
|
||||
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
|
||||
);
|
||||
}
|
||||
None => {
|
||||
self.trust_me();
|
||||
|
||||
try_or_throw!(
|
||||
self.machine_st,
|
||||
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.trust_me();
|
||||
}
|
||||
|
||||
try_or_throw!(
|
||||
self.machine_st,
|
||||
@@ -1110,7 +1108,6 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
self.machine_st.fail = true;
|
||||
}
|
||||
@@ -1148,17 +1145,7 @@ impl Machine {
|
||||
);
|
||||
}
|
||||
&Instruction::NeckCut => {
|
||||
let b = self.machine_st.b;
|
||||
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.neck_cut();
|
||||
self.machine_st.p += 1;
|
||||
}
|
||||
&Instruction::GetLevel(r) => {
|
||||
@@ -1324,7 +1311,6 @@ impl Machine {
|
||||
}
|
||||
&Instruction::DefaultCallRead(_) => {
|
||||
try_or_throw!(self.machine_st, self.read());
|
||||
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
}
|
||||
&Instruction::DefaultExecuteRead(_) => {
|
||||
@@ -2380,6 +2366,16 @@ impl Machine {
|
||||
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) => {
|
||||
self.machine_st.p += 1;
|
||||
}
|
||||
@@ -2399,6 +2395,16 @@ impl Machine {
|
||||
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) => {
|
||||
self.machine_st.p = self.machine_st.cp;
|
||||
}
|
||||
@@ -2422,6 +2428,16 @@ impl Machine {
|
||||
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();
|
||||
}
|
||||
@@ -2442,6 +2458,16 @@ impl Machine {
|
||||
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();
|
||||
}
|
||||
@@ -2451,10 +2477,21 @@ impl Machine {
|
||||
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
|
||||
|
||||
read_heap_cell!(d,
|
||||
(HeapCellValueTag::Str | HeapCellValueTag::Lis |
|
||||
HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
|
||||
(HeapCellValueTag::Lis |
|
||||
HeapCellValueTag::PStrLoc |
|
||||
HeapCellValueTag::CStr) => {
|
||||
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)) => {
|
||||
if arity > 0 {
|
||||
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]));
|
||||
|
||||
read_heap_cell!(d,
|
||||
(HeapCellValueTag::Str | HeapCellValueTag::Lis |
|
||||
HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
|
||||
(HeapCellValueTag::Lis |
|
||||
HeapCellValueTag::PStrLoc |
|
||||
HeapCellValueTag::CStr) => {
|
||||
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)) => {
|
||||
if arity > 0 {
|
||||
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]));
|
||||
|
||||
match Number::try_from(d) {
|
||||
Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => {
|
||||
Ok(_) => {
|
||||
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();
|
||||
}
|
||||
@@ -2548,16 +2589,9 @@ impl Machine {
|
||||
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
|
||||
|
||||
match Number::try_from(d) {
|
||||
Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => {
|
||||
Ok(_) => {
|
||||
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();
|
||||
}
|
||||
@@ -2784,6 +2818,19 @@ impl Machine {
|
||||
self.machine_st.s_offset = 0;
|
||||
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) => {
|
||||
self.machine_st.s = HeapPtr::HeapCell(l);
|
||||
self.machine_st.s_offset = 0;
|
||||
@@ -2810,12 +2857,25 @@ impl Machine {
|
||||
let store_v = self.machine_st.store(deref_v);
|
||||
|
||||
read_heap_cell!(store_v,
|
||||
(HeapCellValueTag::Str | HeapCellValueTag::Lis |
|
||||
HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar |
|
||||
HeapCellValueTag::StackVar | HeapCellValueTag::Var |
|
||||
(HeapCellValueTag::Str |
|
||||
HeapCellValueTag::Lis |
|
||||
HeapCellValueTag::PStrLoc |
|
||||
HeapCellValueTag::CStr) => {
|
||||
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();
|
||||
continue;
|
||||
@@ -3527,7 +3587,10 @@ impl Machine {
|
||||
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 {
|
||||
self.machine_st.backtrack();
|
||||
@@ -3539,7 +3602,10 @@ impl Machine {
|
||||
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 {
|
||||
self.machine_st.backtrack();
|
||||
@@ -4059,14 +4125,6 @@ impl Machine {
|
||||
self.clean_up_block();
|
||||
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(_) => {
|
||||
self.machine_st.backtrack();
|
||||
}
|
||||
@@ -4134,6 +4192,46 @@ impl Machine {
|
||||
self.cpu_now();
|
||||
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(_) => {
|
||||
self.current_time();
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
@@ -4178,6 +4276,30 @@ impl Machine {
|
||||
self.set_ball();
|
||||
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, _) => {
|
||||
self.set_cut_point_by_default(r);
|
||||
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);
|
||||
}
|
||||
&Instruction::CallLoadContextModule(_) => {
|
||||
self.load_context_module();
|
||||
self.load_context_module(self.machine_st.registers[1]);
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
}
|
||||
&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);
|
||||
}
|
||||
&Instruction::CallLoadContextStream(_) => {
|
||||
@@ -4862,6 +4984,118 @@ impl Machine {
|
||||
try_or_throw!(self.machine_st, self.add_non_counted_backtracking());
|
||||
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::types::*;
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::heap_iter::FocusedHeapIter;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
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 forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue>
|
||||
where
|
||||
@@ -16,9 +19,8 @@ pub(crate) struct IteratorUMP;
|
||||
|
||||
impl UnmarkPolicy for IteratorUMP {
|
||||
#[inline(always)]
|
||||
fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool {
|
||||
fn unmark(heap: &mut [HeapCellValue], current: usize) {
|
||||
heap[current].set_mark_bit(false);
|
||||
false
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -34,7 +36,7 @@ struct MarkerUMP {}
|
||||
|
||||
impl UnmarkPolicy for MarkerUMP {
|
||||
#[inline(always)]
|
||||
fn unmark(_heap: &mut [HeapCellValue], _current: usize) -> bool { true }
|
||||
fn unmark(_heap: &mut [HeapCellValue], _current: usize) {}
|
||||
|
||||
#[inline(always)]
|
||||
fn mark(heap: &mut [HeapCellValue], current: usize) {
|
||||
@@ -43,7 +45,7 @@ impl UnmarkPolicy for MarkerUMP {
|
||||
|
||||
#[inline(always)]
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -53,10 +55,9 @@ impl UnmarkPolicy for MarkerUMP {
|
||||
iter.current += 1;
|
||||
|
||||
iter.next = iter.heap[iter.current].get_value();
|
||||
|
||||
iter.heap[iter.current].set_value(temp);
|
||||
iter.heap[iter.current].set_mark_bit(true);
|
||||
|
||||
iter.heap[iter.current].set_forwarding_bit(true); // forward the attr vars list.
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -71,6 +72,14 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
|
||||
_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> {
|
||||
fn drop(&mut self) {
|
||||
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 {
|
||||
let orig_heap_len = heap.len();
|
||||
let start = orig_heap_len + 1;
|
||||
let start = orig_heap_len;
|
||||
|
||||
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();
|
||||
|
||||
Self {
|
||||
@@ -104,11 +112,39 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
||||
_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> {
|
||||
let current = self.current;
|
||||
|
||||
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_mark_bit(true);
|
||||
}
|
||||
@@ -117,13 +153,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
||||
}
|
||||
|
||||
fn forward_var(&mut self) -> Option<HeapCellValue> {
|
||||
if self.heap[self.next].get_mark_bit() {
|
||||
return self.backward_and_return();
|
||||
}
|
||||
|
||||
self.heap[self.current].set_forwarding_bit(true);
|
||||
|
||||
if self.heap[self.next].get_forwarding_bit() == Some(true) {
|
||||
if self.heap[self.next].get_forwarding_bit() {
|
||||
return self.backward_and_return();
|
||||
}
|
||||
|
||||
@@ -138,29 +168,36 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
||||
|
||||
fn forward(&mut self) -> Option<HeapCellValue> {
|
||||
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() {
|
||||
HeapCellValueTag::AttrVar => {
|
||||
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 => {
|
||||
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 => {
|
||||
if self.heap[self.next + 1].get_mark_bit() {
|
||||
if self.heap[self.next + 1].get_forwarding_bit() {
|
||||
return self.backward_and_return();
|
||||
}
|
||||
|
||||
let h = self.next;
|
||||
let cell = self.heap[h];
|
||||
|
||||
self.heap[h].set_forwarding_bit(true);
|
||||
self.heap[self.current].set_forwarding_bit(true);
|
||||
|
||||
let arity = cell_as_atom_cell!(self.heap[h]).get_arity();
|
||||
|
||||
for cell in &mut self.heap[h + 1 .. h + arity + 1] {
|
||||
cell.set_mark_bit(true);
|
||||
cell.set_forwarding_bit(true);
|
||||
}
|
||||
|
||||
let last_cell_loc = h + arity;
|
||||
@@ -172,14 +209,13 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
||||
return Some(cell);
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
self.heap[self.current].set_forwarding_bit(true);
|
||||
self.heap[self.next+1].set_mark_bit(true);
|
||||
|
||||
let last_cell_loc = self.next + 1;
|
||||
self.heap[last_cell_loc].set_forwarding_bit(true);
|
||||
|
||||
self.next = self.heap[last_cell_loc].get_value();
|
||||
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 cell = self.heap[h];
|
||||
|
||||
self.heap[self.current].set_forwarding_bit(true);
|
||||
|
||||
if self.heap[h+1].get_mark_bit() {
|
||||
if self.heap[h+1].get_forwarding_bit() {
|
||||
return self.backward_and_return();
|
||||
}
|
||||
|
||||
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.heap[h+1].set_value(self.current);
|
||||
self.heap[h].set_forwarding_bit(true);
|
||||
|
||||
self.current = h+1;
|
||||
self.next = self.heap[last_cell_loc].get_value();
|
||||
self.heap[last_cell_loc].set_value(self.current);
|
||||
self.current = last_cell_loc;
|
||||
} else {
|
||||
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.current = h;
|
||||
|
||||
if self.heap[h].get_forwarding_bit() == Some(true) {
|
||||
if self.heap[h].get_mark_bit() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -221,20 +254,23 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
||||
}
|
||||
HeapCellValueTag::PStrOffset => {
|
||||
let h = self.next;
|
||||
let cell = self.heap[h];
|
||||
|
||||
// mark the Fixnum offset.
|
||||
UMP::mark(self.heap, self.current+1);
|
||||
|
||||
if self.heap[h].get_tag() == HeapCellValueTag::PStr {
|
||||
if self.heap[h+1].get_mark_bit() {
|
||||
let last_cell_loc = h+1;
|
||||
|
||||
if self.heap[last_cell_loc].get_forwarding_bit() {
|
||||
return self.backward_and_return();
|
||||
}
|
||||
|
||||
self.heap[h+1].set_mark_bit(true);
|
||||
self.heap[self.current].set_forwarding_bit(true);
|
||||
if self.heap[h].get_tag() == HeapCellValueTag::PStr {
|
||||
self.heap[last_cell_loc].set_forwarding_bit(true);
|
||||
|
||||
self.next = self.heap[h+1].get_value();
|
||||
self.heap[h+1].set_value(self.current);
|
||||
self.current = h+1;
|
||||
self.next = self.heap[last_cell_loc].get_value();
|
||||
self.heap[last_cell_loc].set_value(self.current);
|
||||
self.current = last_cell_loc;
|
||||
} else {
|
||||
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.current = h;
|
||||
}
|
||||
}
|
||||
HeapCellValueTag::StackVar => {
|
||||
let cell = self.heap[self.current];
|
||||
self.heap[self.current].set_forwarding_bit(true);
|
||||
|
||||
return Some(cell);
|
||||
}
|
||||
_ => {
|
||||
if self.heap[self.current].get_mark_bit() {
|
||||
let current = self.current;
|
||||
tag @ HeapCellValueTag::Atom => {
|
||||
let cell = HeapCellValue::build_with(tag, self.next as u64);
|
||||
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() {
|
||||
return None;
|
||||
}
|
||||
|
||||
return Some(self.heap[current]);
|
||||
}
|
||||
|
||||
_ => {
|
||||
return self.backward_and_return();
|
||||
}
|
||||
}
|
||||
@@ -271,42 +309,23 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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.next = self.current;
|
||||
self.current = temp;
|
||||
}
|
||||
|
||||
self.heap[self.current].set_forwarding_bit(false);
|
||||
|
||||
let unmark_is_no_op = UMP::unmark(self.heap, self.current);
|
||||
UMP::unmark(self.heap, self.current);
|
||||
|
||||
if self.current == self.start {
|
||||
return true;
|
||||
}
|
||||
|
||||
if unmark_is_no_op { // if true, the marker is running.
|
||||
let cell = self.heap[self.current];
|
||||
|
||||
// a cyclic root must be handled specially when marking.
|
||||
if self.next >= self.orig_heap_len && cell.is_ref() {
|
||||
debug_assert!(cell.get_tag() != HeapCellValueTag::PStrOffset);
|
||||
|
||||
self.heap[self.current].set_mark_bit(false);
|
||||
let prev_current = self.heap[self.current].get_value();
|
||||
|
||||
if !self.heap[prev_current].is_forwarded() {
|
||||
return self.backward();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.current -= 1;
|
||||
|
||||
let temp = self.heap[self.current+1].get_value();
|
||||
@@ -713,7 +732,7 @@ mod tests {
|
||||
assert!(wam.machine_st.heap[8].get_mark_bit());
|
||||
|
||||
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")));
|
||||
@@ -743,7 +762,7 @@ mod tests {
|
||||
assert!(wam.machine_st.heap[8].get_mark_bit());
|
||||
|
||||
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")));
|
||||
@@ -773,7 +792,7 @@ mod tests {
|
||||
assert!(wam.machine_st.heap[8].get_mark_bit());
|
||||
|
||||
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")));
|
||||
@@ -803,7 +822,7 @@ mod tests {
|
||||
assert!(wam.machine_st.heap[8].get_mark_bit());
|
||||
|
||||
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")));
|
||||
@@ -922,7 +941,6 @@ mod tests {
|
||||
wam.machine_st.heap.push(list_loc_as_cell!(9));
|
||||
wam.machine_st.heap.push(heap_loc_as_cell!(9));
|
||||
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||
|
||||
wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7.
|
||||
wam.machine_st.heap.push(heap_loc_as_cell!(12));
|
||||
|
||||
@@ -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[1]), 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::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::partial_string::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::types::*;
|
||||
|
||||
use ordered_float::OrderedFloat;
|
||||
use rug::{Integer, Rational};
|
||||
use crate::parser::rug::{Integer, Rational};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
@@ -18,6 +18,9 @@ impl From<Literal> for HeapCellValue {
|
||||
match literal {
|
||||
Literal::Atom(name) => atom_as_cell!(name),
|
||||
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::Integer(bigint_ptr) => {
|
||||
typed_arena_ptr_as_cell!(bigint_ptr)
|
||||
@@ -25,7 +28,7 @@ impl From<Literal> for HeapCellValue {
|
||||
Literal::Rational(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) => {
|
||||
if s == atom!("") {
|
||||
empty_list_as_cell!()
|
||||
@@ -56,7 +59,7 @@ impl TryFrom<HeapCellValue> for Literal {
|
||||
Ok(Literal::Fixnum(n))
|
||||
}
|
||||
(HeapCellValueTag::F64, f) => {
|
||||
Ok(Literal::Float(f))
|
||||
Ok(Literal::Float(f.as_offset()))
|
||||
}
|
||||
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||
match_untyped_arena_ptr!(cons_ptr,
|
||||
@@ -66,9 +69,8 @@ impl TryFrom<HeapCellValue> for Literal {
|
||||
(ArenaHeaderTag::Rational, n) => {
|
||||
Ok(Literal::Rational(n))
|
||||
}
|
||||
(ArenaHeaderTag::F64, f) => {
|
||||
// remove this redundancy.
|
||||
Ok(Literal::Float(F64Ptr(f)))
|
||||
(ArenaHeaderTag::IndexPtr, _ip) => {
|
||||
Ok(Literal::CodeIndex(CodeIndex::from(cons_ptr)))
|
||||
}
|
||||
_ => {
|
||||
Err(())
|
||||
|
||||
@@ -10,8 +10,8 @@ use crate::parser::ast::*;
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexSet;
|
||||
use ref_thread_local::RefThreadLocal;
|
||||
use slice_deque::{sdeq, SliceDeque};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::fs::File;
|
||||
use std::mem;
|
||||
|
||||
@@ -21,12 +21,12 @@ pub(super) fn set_code_index(
|
||||
retraction_info: &mut RetractionInfo,
|
||||
compilation_target: &CompilationTarget,
|
||||
key: PredicateKey,
|
||||
code_index: &CodeIndex,
|
||||
mut code_index: CodeIndex,
|
||||
code_ptr: IndexPtr,
|
||||
) {
|
||||
let record = match compilation_target {
|
||||
CompilationTarget::User => {
|
||||
if IndexPtr::Undefined == code_index.get() {
|
||||
if IndexPtrTag::Undefined == code_index.get().tag() {
|
||||
code_index.set(code_ptr);
|
||||
RetractionRecord::AddedUserPredicate(key)
|
||||
} else {
|
||||
@@ -35,7 +35,7 @@ pub(super) fn set_code_index(
|
||||
}
|
||||
}
|
||||
CompilationTarget::Module(ref module_name) => {
|
||||
if IndexPtr::Undefined == code_index.get() {
|
||||
if IndexPtrTag::Undefined == code_index.get().tag() {
|
||||
code_index.set(code_ptr);
|
||||
RetractionRecord::AddedModulePredicate(*module_name, key)
|
||||
} else {
|
||||
@@ -48,12 +48,10 @@ pub(super) fn set_code_index(
|
||||
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,
|
||||
compilation_target: &CompilationTarget,
|
||||
retraction_info: &mut RetractionInfo,
|
||||
wam_op_dir: &mut OpDir,
|
||||
module_op_exports: &mut ModuleOpExports,
|
||||
op_decl: &OpDecl,
|
||||
) {
|
||||
/*
|
||||
@@ -65,20 +63,21 @@ fn add_op_decl_as_module_export(
|
||||
|
||||
match op_decl.insert_into_op_dir(wam_op_dir) {
|
||||
Some(op_desc) => {
|
||||
retraction_info.push_record(RetractionRecord::ReplacedUserOp(
|
||||
payload.retraction_info.push_record(RetractionRecord::ReplacedUserOp(
|
||||
*op_decl,
|
||||
op_desc,
|
||||
));
|
||||
|
||||
module_op_exports.push((*op_decl, Some(op_desc)));
|
||||
payload.module_op_exports.push((*op_decl, Some(op_desc)));
|
||||
}
|
||||
None => {
|
||||
retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl));
|
||||
module_op_exports.push((*op_decl, None));
|
||||
payload.retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl));
|
||||
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(
|
||||
@@ -117,8 +116,8 @@ pub(super) fn add_op_decl(
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn import_module_exports(
|
||||
retraction_info: &mut RetractionInfo,
|
||||
pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
|
||||
payload: &mut LS::LoaderFieldType,
|
||||
compilation_target: &CompilationTarget,
|
||||
imported_module: &Module,
|
||||
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) {
|
||||
let arena = &mut LS::machine_st(payload).arena;
|
||||
|
||||
let target_code_index = code_dir
|
||||
.entry(key)
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
||||
.or_insert_with(|| CodeIndex::default(arena))
|
||||
.clone();
|
||||
|
||||
set_code_index(
|
||||
retraction_info,
|
||||
&mut payload.retraction_info,
|
||||
compilation_target,
|
||||
key,
|
||||
&target_code_index,
|
||||
target_code_index,
|
||||
src_code_index.get(),
|
||||
);
|
||||
} else {
|
||||
@@ -155,7 +156,7 @@ pub(super) fn import_module_exports(
|
||||
}
|
||||
}
|
||||
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(())
|
||||
}
|
||||
|
||||
fn import_module_exports_into_module(
|
||||
retraction_info: &mut RetractionInfo,
|
||||
fn import_module_exports_into_module<'a, LS: LoadState<'a>>(
|
||||
payload: &mut LS::LoaderFieldType,
|
||||
compilation_target: &CompilationTarget,
|
||||
imported_module: &Module,
|
||||
code_dir: &mut CodeDir,
|
||||
op_dir: &mut OpDir,
|
||||
meta_predicates: &mut MetaPredicateDir,
|
||||
wam_op_dir: &mut OpDir,
|
||||
module_op_exports: &mut ModuleOpExports,
|
||||
) -> Result<(), SessionError> {
|
||||
for export in imported_module.module_decl.exports.iter() {
|
||||
match export {
|
||||
@@ -183,16 +183,18 @@ fn import_module_exports_into_module(
|
||||
}
|
||||
|
||||
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
|
||||
.entry(key)
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
||||
.or_insert_with(|| CodeIndex::default(arena))
|
||||
.clone();
|
||||
|
||||
set_code_index(
|
||||
retraction_info,
|
||||
&mut payload.retraction_info,
|
||||
compilation_target,
|
||||
key,
|
||||
&target_code_index,
|
||||
target_code_index,
|
||||
src_code_index.get(),
|
||||
);
|
||||
} else {
|
||||
@@ -203,12 +205,10 @@ fn import_module_exports_into_module(
|
||||
}
|
||||
}
|
||||
ModuleExport::OpDecl(ref op_decl) => {
|
||||
add_op_decl_as_module_export(
|
||||
add_op_decl_as_module_export::<LS>(
|
||||
payload,
|
||||
op_dir,
|
||||
compilation_target,
|
||||
retraction_info,
|
||||
wam_op_dir,
|
||||
module_op_exports,
|
||||
op_decl,
|
||||
);
|
||||
}
|
||||
@@ -218,14 +218,12 @@ fn import_module_exports_into_module(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn import_qualified_module_exports(
|
||||
retraction_info: &mut RetractionInfo,
|
||||
fn import_qualified_module_exports<'a, LS: LoadState<'a>>(
|
||||
payload: &mut LS::LoaderFieldType,
|
||||
compilation_target: &CompilationTarget,
|
||||
imported_module: &Module,
|
||||
exports: &IndexSet<ModuleExport>,
|
||||
code_dir: &mut CodeDir,
|
||||
op_dir: &mut OpDir,
|
||||
meta_predicates: &mut MetaPredicateDir,
|
||||
wam_prelude: &mut MachinePreludeView,
|
||||
) -> Result<(), SessionError> {
|
||||
for export in imported_module.module_decl.exports.iter() {
|
||||
if !exports.contains(export) {
|
||||
@@ -237,20 +235,22 @@ fn import_qualified_module_exports(
|
||||
let key = (*name, *arity);
|
||||
|
||||
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) {
|
||||
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())
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
|
||||
.clone();
|
||||
|
||||
set_code_index(
|
||||
retraction_info,
|
||||
&mut payload.retraction_info,
|
||||
compilation_target,
|
||||
key,
|
||||
&target_code_index,
|
||||
target_code_index,
|
||||
src_code_index.get(),
|
||||
);
|
||||
} else {
|
||||
@@ -261,7 +261,12 @@ fn import_qualified_module_exports(
|
||||
}
|
||||
}
|
||||
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(())
|
||||
}
|
||||
|
||||
fn import_qualified_module_exports_into_module(
|
||||
retraction_info: &mut RetractionInfo,
|
||||
compilation_target: &CompilationTarget,
|
||||
fn import_qualified_module_exports_into_module<'a, LS: LoadState<'a>>(
|
||||
payload: &mut LS::LoaderFieldType,
|
||||
imported_module: &Module,
|
||||
exports: &IndexSet<ModuleExport>,
|
||||
code_dir: &mut CodeDir,
|
||||
op_dir: &mut OpDir,
|
||||
meta_predicates: &mut MetaPredicateDir,
|
||||
wam_op_dir: &mut OpDir,
|
||||
module_op_exports: &mut ModuleOpExports,
|
||||
) -> Result<(), SessionError> {
|
||||
let payload_compilation_target = payload.compilation_target;
|
||||
|
||||
for export in imported_module.module_decl.exports.iter() {
|
||||
if !exports.contains(export) {
|
||||
continue;
|
||||
@@ -294,16 +299,18 @@ fn import_qualified_module_exports_into_module(
|
||||
}
|
||||
|
||||
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
|
||||
.entry(key)
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
|
||||
.clone();
|
||||
|
||||
set_code_index(
|
||||
retraction_info,
|
||||
compilation_target,
|
||||
&mut payload.retraction_info,
|
||||
&payload_compilation_target,
|
||||
key,
|
||||
&target_code_index,
|
||||
target_code_index,
|
||||
src_code_index.get(),
|
||||
);
|
||||
} else {
|
||||
@@ -314,12 +321,10 @@ fn import_qualified_module_exports_into_module(
|
||||
}
|
||||
}
|
||||
ModuleExport::OpDecl(ref op_decl) => {
|
||||
add_op_decl_as_module_export(
|
||||
add_op_decl_as_module_export::<LS>(
|
||||
payload,
|
||||
op_dir,
|
||||
compilation_target,
|
||||
retraction_info,
|
||||
wam_op_dir,
|
||||
module_op_exports,
|
||||
op_decl,
|
||||
);
|
||||
}
|
||||
@@ -334,12 +339,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
&mut self,
|
||||
compilation_target: CompilationTarget,
|
||||
key: PredicateKey,
|
||||
clause_locs: &SliceDeque<usize>,
|
||||
clause_locs: &VecDeque<usize>,
|
||||
) {
|
||||
let result_opt = self
|
||||
.wam_prelude
|
||||
.indices
|
||||
.get_predicate_skeleton(&compilation_target, &key)
|
||||
.get_predicate_skeleton_mut(&compilation_target, &key)
|
||||
.map(|skeleton| {
|
||||
(
|
||||
clause_locs
|
||||
@@ -396,7 +401,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
pub(super) fn retract_local_clause_clauses(
|
||||
&mut self,
|
||||
clause_clause_compilation_target: CompilationTarget,
|
||||
clause_locs: &SliceDeque<usize>,
|
||||
clause_locs: &VecDeque<usize>,
|
||||
) {
|
||||
let key = (atom!("$clause"), 2);
|
||||
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,
|
||||
clause_clause_compilation_target,
|
||||
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,
|
||||
};
|
||||
|
||||
for (key, code_index) in &removed_module.code_dir {
|
||||
for (key, code_index) in removed_module.code_dir.iter_mut() {
|
||||
match removed_module
|
||||
.local_extensible_predicates
|
||||
.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
|
||||
.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() {
|
||||
match export {
|
||||
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))
|
||||
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));
|
||||
}
|
||||
_ => {}
|
||||
@@ -584,7 +589,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
Some(ref mut module) => module
|
||||
.code_dir
|
||||
.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(),
|
||||
None => {
|
||||
self.add_dynamically_generated_module(module_name);
|
||||
@@ -593,7 +601,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
Some(ref mut module) => module
|
||||
.code_dir
|
||||
.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(),
|
||||
None => {
|
||||
unreachable!()
|
||||
@@ -608,13 +619,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
key: PredicateKey,
|
||||
compilation_target: CompilationTarget,
|
||||
) -> CodeIndex {
|
||||
let arena = &mut LS::machine_st(&mut self.payload).arena;
|
||||
|
||||
match compilation_target {
|
||||
CompilationTarget::User => self
|
||||
.wam_prelude
|
||||
.indices
|
||||
.code_dir
|
||||
.entry(key)
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
|
||||
.clone(),
|
||||
CompilationTarget::Module(module_name) => {
|
||||
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,
|
||||
key: PredicateKey,
|
||||
) -> CodeIndex {
|
||||
let arena = &mut LS::machine_st(&mut self.payload).arena;
|
||||
|
||||
if module_name == atom!("user") {
|
||||
return self
|
||||
.wam_prelude
|
||||
.indices
|
||||
.code_dir
|
||||
.entry(key)
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
|
||||
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
|
||||
.clone();
|
||||
} else {
|
||||
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) => {
|
||||
match self.wam_prelude.indices.modules.get_mut(module_name) {
|
||||
Some(ref mut module) => {
|
||||
let payload: &mut LoadStatePayload<_> = &mut self.payload;
|
||||
|
||||
add_op_decl_as_module_export(
|
||||
add_op_decl_as_module_export::<LS>(
|
||||
&mut self.payload,
|
||||
&mut module.op_dir,
|
||||
&payload.compilation_target,
|
||||
&mut payload.retraction_info,
|
||||
&mut self.wam_prelude.indices.op_dir,
|
||||
&mut payload.module_op_exports,
|
||||
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 {
|
||||
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, _) => {
|
||||
let payload_compilation_target = self.payload.compilation_target;
|
||||
|
||||
@@ -773,7 +786,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
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, _) => {
|
||||
let key = (name, arity);
|
||||
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(
|
||||
&mut self,
|
||||
module_name: Atom,
|
||||
@@ -894,8 +919,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
return;
|
||||
}
|
||||
|
||||
import_module_exports(
|
||||
&mut self.payload.retraction_info,
|
||||
import_module_exports::<LS>(
|
||||
&mut self.payload,
|
||||
&module_compilation_target,
|
||||
builtins,
|
||||
code_dir,
|
||||
@@ -992,14 +1017,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
|
||||
for export in &module.module_decl.exports {
|
||||
if let ModuleExport::OpDecl(ref op_decl) = export {
|
||||
let payload: &mut LoadStatePayload<_> = &mut self.payload;
|
||||
|
||||
add_op_decl_as_module_export(
|
||||
add_op_decl_as_module_export::<LS>(
|
||||
&mut self.payload,
|
||||
&mut module.op_dir,
|
||||
&payload.compilation_target, // this is a Module.
|
||||
&mut payload.retraction_info,
|
||||
&mut self.wam_prelude.indices.op_dir,
|
||||
&mut payload.module_op_exports,
|
||||
op_decl,
|
||||
);
|
||||
}
|
||||
@@ -1018,8 +1039,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
|
||||
match &payload_compilation_target {
|
||||
CompilationTarget::User => {
|
||||
import_module_exports(
|
||||
&mut self.payload.retraction_info,
|
||||
import_module_exports::<LS>(
|
||||
&mut self.payload,
|
||||
&payload_compilation_target,
|
||||
&module,
|
||||
&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) => {
|
||||
match self.wam_prelude.indices.modules.get_mut(defining_module_name) {
|
||||
Some(ref mut target_module) => {
|
||||
let payload: &mut LoadStatePayload<_> = &mut self.payload;
|
||||
|
||||
import_module_exports_into_module(
|
||||
&mut payload.retraction_info,
|
||||
import_module_exports_into_module::<LS>(
|
||||
&mut self.payload,
|
||||
&payload_compilation_target,
|
||||
&module,
|
||||
&mut target_module.code_dir,
|
||||
&mut target_module.op_dir,
|
||||
&mut target_module.meta_predicates,
|
||||
&mut self.wam_prelude.indices.op_dir,
|
||||
&mut payload.module_op_exports,
|
||||
)?;
|
||||
}
|
||||
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) {
|
||||
let payload_compilation_target = self.payload.compilation_target;
|
||||
|
||||
match &payload_compilation_target {
|
||||
let result = match &payload_compilation_target {
|
||||
CompilationTarget::User => {
|
||||
import_qualified_module_exports(
|
||||
&mut self.payload.retraction_info,
|
||||
import_qualified_module_exports::<LS>(
|
||||
&mut self.payload,
|
||||
&payload_compilation_target,
|
||||
&module,
|
||||
&exports,
|
||||
&mut self.wam_prelude.indices.code_dir,
|
||||
&mut self.wam_prelude.indices.op_dir,
|
||||
&mut self.wam_prelude.indices.meta_predicates,
|
||||
)?;
|
||||
&mut self.wam_prelude,
|
||||
)
|
||||
}
|
||||
CompilationTarget::Module(ref defining_module_name) => {
|
||||
match self.wam_prelude.indices.modules.get_mut(defining_module_name) {
|
||||
Some(ref mut target_module) => {
|
||||
let payload: &mut LoadStatePayload<_> = &mut self.payload;
|
||||
|
||||
import_qualified_module_exports_into_module(
|
||||
&mut payload.retraction_info,
|
||||
&payload_compilation_target,
|
||||
import_qualified_module_exports_into_module::<LS>(
|
||||
&mut self.payload,
|
||||
&module,
|
||||
&exports,
|
||||
&mut target_module.code_dir,
|
||||
&mut target_module.op_dir,
|
||||
&mut target_module.meta_predicates,
|
||||
&mut self.wam_prelude.indices.op_dir,
|
||||
&mut payload.module_op_exports,
|
||||
)?;
|
||||
)
|
||||
}
|
||||
None => {
|
||||
// we find ourselves here because we're trying to import
|
||||
// a module into itself as it is being defined.
|
||||
self.wam_prelude.indices.modules.insert(module_name, module);
|
||||
return Err(SessionError::ModuleCannotImportSelf(module_name));
|
||||
}
|
||||
Err(SessionError::ModuleCannotImportSelf(module_name))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.wam_prelude.indices.modules.insert(module_name, module);
|
||||
Ok(())
|
||||
result
|
||||
} else {
|
||||
Err(SessionError::ExistenceError(ExistenceError::Module(module_name)))
|
||||
}
|
||||
@@ -1168,7 +1177,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
indices: self.wam_prelude.indices,
|
||||
code: self.wam_prelude.code,
|
||||
load_contexts: self.wam_prelude.load_contexts,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
subloader.load()?
|
||||
@@ -1231,7 +1240,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
indices: self.wam_prelude.indices,
|
||||
code: self.wam_prelude.code,
|
||||
load_contexts: self.wam_prelude.load_contexts,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
subloader.load()?
|
||||
|
||||
@@ -14,9 +14,9 @@ use crate::parser::ast::*;
|
||||
use crate::types::*;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use slice_deque::{sdeq, SliceDeque};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
@@ -96,7 +96,7 @@ pub(crate) enum RetractionRecord {
|
||||
CompilationTarget,
|
||||
CompilationTarget,
|
||||
PredicateKey,
|
||||
SliceDeque<usize>,
|
||||
VecDeque<usize>,
|
||||
),
|
||||
RemovedSkeleton(CompilationTarget, PredicateKey, PredicateSkeleton),
|
||||
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(super) payload: LS::LoaderFieldType,
|
||||
pub(super) wam_prelude: MachinePreludeView<'a>,
|
||||
@@ -485,10 +543,21 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
|
||||
read_heap_cell!(addr,
|
||||
(HeapCellValueTag::Lis) => {
|
||||
use crate::parser::parser::as_partial_string;
|
||||
|
||||
let tail = term_stack.pop().unwrap();
|
||||
let head = term_stack.pop().unwrap();
|
||||
|
||||
term_stack.push(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
|
||||
match 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) => {
|
||||
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()));
|
||||
}
|
||||
(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 {
|
||||
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
|
||||
} else {
|
||||
@@ -509,31 +599,27 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
term_stack.push(Term::Clause(Cell::default(), name, subterms));
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::PStr, string) => {
|
||||
(HeapCellValueTag::PStr, atom) => {
|
||||
let tail = term_stack.pop().unwrap();
|
||||
|
||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
|
||||
term_stack.push(Term::PartialString(
|
||||
Cell::default(),
|
||||
string,
|
||||
None,
|
||||
));
|
||||
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
||||
} else {
|
||||
term_stack.push(Term::PartialString(
|
||||
Cell::default(),
|
||||
string,
|
||||
Some(Box::new(tail)),
|
||||
atom.as_str().to_owned(),
|
||||
Box::new(tail),
|
||||
));
|
||||
}
|
||||
}
|
||||
(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();
|
||||
|
||||
term_stack.push(Term::PartialString(
|
||||
Cell::default(),
|
||||
string,
|
||||
Some(Box::new(tail)),
|
||||
atom.as_str().to_owned(),
|
||||
Box::new(tail),
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
@@ -701,7 +787,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
module
|
||||
.code_dir
|
||||
.get_mut(&key)
|
||||
.map(|code_idx| code_idx.replace(old_code_idx));
|
||||
.map(|code_idx| code_idx.set(old_code_idx));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
@@ -726,10 +812,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
.indices
|
||||
.code_dir
|
||||
.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) => {
|
||||
// WAS: inner_index_locs) => {
|
||||
if let Some(index_loc) = index_key.switch_on_term_loc() {
|
||||
let indexing_code = match &mut self.wam_prelude.code[index_loc] {
|
||||
Instruction::IndexingCode(indexing_code) => indexing_code,
|
||||
@@ -900,7 +985,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
key,
|
||||
) {
|
||||
Some(skeleton) => {
|
||||
skeleton.clause_clause_locs.truncate_back(len);
|
||||
skeleton.clause_clause_locs.truncate(len);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
@@ -912,8 +997,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
.get_predicate_skeleton_mut(&compilation_target, &key)
|
||||
{
|
||||
Some(skeleton) => {
|
||||
skeleton.clauses.truncate_back(len);
|
||||
skeleton.core.clause_clause_locs.truncate_back(len);
|
||||
skeleton.clauses.truncate(len);
|
||||
skeleton.core.clause_clause_locs.truncate(len);
|
||||
}
|
||||
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);
|
||||
|
||||
if let IndexPtr::Undefined = code_index.get() {
|
||||
if code_index.is_undefined() {
|
||||
set_code_index(
|
||||
&mut self.payload.retraction_info,
|
||||
&compilation_target,
|
||||
key,
|
||||
&code_index,
|
||||
IndexPtr::DynamicUndefined,
|
||||
code_index,
|
||||
IndexPtr::dynamic_undefined(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1358,7 +1443,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
*key,
|
||||
) {
|
||||
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,
|
||||
};
|
||||
@@ -1484,7 +1569,6 @@ impl Machine {
|
||||
let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
|
||||
|
||||
let declare_module = || {
|
||||
// let export_list = export_list?;
|
||||
let exports = loader.extract_module_export_list_from_heap(temp_v!(2))?;
|
||||
|
||||
let module_decl = ModuleDecl {
|
||||
@@ -1837,7 +1921,7 @@ impl Machine {
|
||||
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;
|
||||
}
|
||||
|
||||
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() {
|
||||
self.machine_st.unify_atom(load_context.module, self.machine_st.registers[1]);
|
||||
self.machine_st.unify_atom(load_context.module, target);
|
||||
} else {
|
||||
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 {
|
||||
let key = self
|
||||
.machine_st
|
||||
.read_predicate_key(self.machine_st[temp_v!(3)], self.machine_st[temp_v!(4)]);
|
||||
|
||||
pub(crate) fn compile_assert(&mut self, append_or_prepend: AppendOrPrepend) -> CallResult
|
||||
{
|
||||
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 {
|
||||
@@ -1892,14 +1973,62 @@ impl Machine {
|
||||
_ => CompilationTarget::Module(module_name),
|
||||
};
|
||||
|
||||
let stub_gen = || {
|
||||
match append_or_prepend {
|
||||
AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1),
|
||||
AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1),
|
||||
}
|
||||
};
|
||||
|
||||
let mut compile_assert = || {
|
||||
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
|
||||
Loader::new(self, LiveTermStream::new(ListingSource::User));
|
||||
|
||||
loader.payload.compilation_target = compilation_target;
|
||||
|
||||
let head = loader.read_term_from_heap(temp_v!(1))?;
|
||||
let body = loader.read_term_from_heap(temp_v!(2))?;
|
||||
let head = 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(
|
||||
Cell::default(),
|
||||
@@ -1908,10 +2037,10 @@ impl Machine {
|
||||
);
|
||||
|
||||
// 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(
|
||||
key,
|
||||
(name, arity),
|
||||
asserted_clause,
|
||||
compilation_target,
|
||||
false,
|
||||
@@ -1922,7 +2051,7 @@ impl Machine {
|
||||
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
|
||||
|
||||
loader.compile_clause_clauses(
|
||||
key,
|
||||
(name, arity),
|
||||
compilation_target,
|
||||
std::iter::once((head, body)),
|
||||
append_or_prepend,
|
||||
@@ -1933,14 +2062,30 @@ impl Machine {
|
||||
|
||||
match compile_assert() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => {
|
||||
let stub = match append_or_prepend {
|
||||
AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1),
|
||||
AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1),
|
||||
};
|
||||
let err = self.machine_st.session_error(e);
|
||||
Err(SessionError::CompilationError(
|
||||
CompilationError::InvalidRuleHead |
|
||||
CompilationError::InadmissibleFact
|
||||
)) => {
|
||||
let err = self.machine_st.type_error(
|
||||
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
|
||||
.wam_prelude
|
||||
.indices
|
||||
.get_predicate_skeleton(&compilation_target, &key)
|
||||
.remove_predicate_skeleton(&compilation_target, &key)
|
||||
.map(|skeleton| {
|
||||
loader
|
||||
let mut clause_clause_skeleton = loader
|
||||
.wam_prelude
|
||||
.indices
|
||||
.get_predicate_skeleton(
|
||||
.remove_predicate_skeleton(
|
||||
&clause_clause_compilation_target,
|
||||
&(atom!("$clause"), 2),
|
||||
)
|
||||
.map(|clause_clause_skeleton| {
|
||||
skeleton
|
||||
.core
|
||||
).unwrap();
|
||||
|
||||
let result = skeleton.core
|
||||
.clause_clause_locs
|
||||
.iter()
|
||||
.map(|clause_clause_loc| {
|
||||
@@ -1992,30 +2136,31 @@ impl Machine {
|
||||
.target_pos_of_clause_clause_loc(*clause_clause_loc)
|
||||
.unwrap()
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap()
|
||||
})
|
||||
.unwrap();
|
||||
.collect();
|
||||
|
||||
loader
|
||||
.wam_prelude
|
||||
loader.add_extensible_predicate(
|
||||
key,
|
||||
skeleton,
|
||||
compilation_target,
|
||||
);
|
||||
|
||||
loader.add_extensible_predicate(
|
||||
(atom!("$clause"), 2),
|
||||
clause_clause_skeleton,
|
||||
clause_clause_compilation_target,
|
||||
);
|
||||
|
||||
result
|
||||
}).unwrap();
|
||||
|
||||
loader.wam_prelude
|
||||
.indices
|
||||
.remove_predicate_skeleton(&compilation_target, &key);
|
||||
|
||||
let code_index = loader
|
||||
let mut code_index = loader
|
||||
.get_or_insert_code_index(key, compilation_target);
|
||||
|
||||
code_index.set(IndexPtr::Undefined);
|
||||
|
||||
/*
|
||||
loader
|
||||
.wam_prelude
|
||||
.indices
|
||||
.get_predicate_skeleton_mut(&compilation_target, &key)
|
||||
.map(|skeleton| skeleton.reset());
|
||||
|
||||
*/
|
||||
code_index.set(IndexPtr::undefined());
|
||||
|
||||
loader.payload.compilation_target = clause_clause_compilation_target;
|
||||
|
||||
@@ -2076,7 +2221,7 @@ impl Machine {
|
||||
// the global clock is incremented after each retraction.
|
||||
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,
|
||||
&(atom!("$clause"), 2),
|
||||
) {
|
||||
@@ -2180,7 +2325,7 @@ impl Machine {
|
||||
|
||||
let (predicate_name, arity) = self
|
||||
.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 {
|
||||
atom!("user") => CompilationTarget::User,
|
||||
@@ -2192,21 +2337,25 @@ impl Machine {
|
||||
.get_meta_predicate_spec(predicate_name, arity, &compilation_target)
|
||||
{
|
||||
Some(meta_specs) => {
|
||||
let list_loc = iter_to_heap_list(
|
||||
&mut self.machine_st.heap,
|
||||
let term_loc = self.machine_st.heap.len();
|
||||
|
||||
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 {
|
||||
MetaSpec::Minus => atom_as_cell!(atom!("+")),
|
||||
MetaSpec::Plus => atom_as_cell!(atom!("-")),
|
||||
MetaSpec::Either => atom_as_cell!(atom!("?")),
|
||||
MetaSpec::Colon => atom_as_cell!(atom!(":")),
|
||||
MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
|
||||
fixnum_as_cell!(Fixnum::build_with(*arg_num as i64))
|
||||
}
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
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(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]);
|
||||
}
|
||||
@@ -2298,22 +2447,16 @@ impl Machine {
|
||||
}
|
||||
|
||||
pub(crate) fn builtin_property(&mut self) {
|
||||
let key = self
|
||||
let (name, arity) = self
|
||||
.machine_st
|
||||
.read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]);
|
||||
|
||||
match ClauseType::from(key.0, key.1) {
|
||||
ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN(_) => {
|
||||
return;
|
||||
}
|
||||
ClauseType::Named(arity, name, _) => {
|
||||
if !ClauseType::is_inbuilt(name, arity) { // ClauseType::from(key.0, key.1, &mut self.machine_st.arena) {
|
||||
if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) {
|
||||
self.machine_st.fail = !module.code_dir.contains_key(&(name, arity));
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.machine_st.fail = true;
|
||||
}
|
||||
@@ -2344,14 +2487,19 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {
|
||||
|
||||
#[inline]
|
||||
pub(super) fn load_module(
|
||||
machine_st: &mut MachineState,
|
||||
code_dir: &mut CodeDir,
|
||||
op_dir: &mut OpDir,
|
||||
meta_predicate_dir: &mut MetaPredicateDir,
|
||||
compilation_target: &CompilationTarget,
|
||||
module: &Module,
|
||||
) {
|
||||
import_module_exports(
|
||||
&mut RetractionInfo::new(0),
|
||||
let ts = LiveTermStream::new(ListingSource::User);
|
||||
let payload = LoadStatePayload::new(0, ts);
|
||||
let mut payload = LiveLoadAndMachineState::new(machine_st, payload);
|
||||
|
||||
import_module_exports::<LiveLoadAndMachineState>(
|
||||
&mut payload,
|
||||
&compilation_target,
|
||||
module,
|
||||
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>(
|
||||
&mut self,
|
||||
valid_type: ValidType,
|
||||
@@ -439,6 +452,9 @@ impl MachineState {
|
||||
SessionError::OpIsInfixAndPostFix(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::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
|
||||
let functor_stub = functor_stub(key.0, key.1);
|
||||
@@ -572,16 +588,12 @@ impl MachineError {
|
||||
pub enum CompilationError {
|
||||
Arithmetic(ArithmeticError),
|
||||
ParserError(ParserError),
|
||||
// BadPendingByte,
|
||||
CannotParseCyclicTerm,
|
||||
// ExpandedTermsListNotAList,
|
||||
ExceededMaxArity,
|
||||
ExpectedRel,
|
||||
// ExpectedTopLevelTerm,
|
||||
InadmissibleFact,
|
||||
InadmissibleQueryTerm,
|
||||
InconsistentEntry,
|
||||
// InvalidDoubleQuotesDecl,
|
||||
// InvalidHook,
|
||||
InvalidMetaPredicateDecl,
|
||||
InvalidModuleDecl,
|
||||
InvalidModuleExport,
|
||||
@@ -618,31 +630,24 @@ impl CompilationError {
|
||||
&CompilationError::Arithmetic(..) => {
|
||||
functor!(atom!("arithmetic_error"))
|
||||
}
|
||||
// &CompilationError::BadPendingByte =>
|
||||
// functor!(atom_from_ss!("bad_pending_byte"), atom_tbl),
|
||||
&CompilationError::CannotParseCyclicTerm => {
|
||||
functor!(atom!("cannot_parse_cyclic_term"))
|
||||
}
|
||||
// &CompilationError::ExpandedTermsListNotAList =>
|
||||
// functor!(atom_tbl.build_with_static_str("expanded_terms_list_is_not_a_list")),
|
||||
&CompilationError::ExceededMaxArity => {
|
||||
functor!(atom!("exceeded_max_arity"))
|
||||
}
|
||||
&CompilationError::ExpectedRel => {
|
||||
functor!(atom!("expected_relation"))
|
||||
}
|
||||
// &CompilationError::ExpectedTopLevelTerm =>
|
||||
// functor!(atom_from_ss!("expected_atom_or_cons_or_clause"), atom_tbl),
|
||||
&CompilationError::InadmissibleFact => {
|
||||
&CompilationError::InadmissibleFact => { // TODO: type_error(callable, _).
|
||||
functor!(atom!("inadmissible_fact"))
|
||||
}
|
||||
&CompilationError::InadmissibleQueryTerm => {
|
||||
&CompilationError::InadmissibleQueryTerm => { // TODO: type_error(callable, _).
|
||||
functor!(atom!("inadmissible_query_term"))
|
||||
}
|
||||
&CompilationError::InconsistentEntry => {
|
||||
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 => {
|
||||
functor!(atom!("invalid_meta_predicate_decl"))
|
||||
}
|
||||
@@ -656,7 +661,8 @@ impl CompilationError {
|
||||
functor!(atom!("no_such_module"), [atom(module_name)])
|
||||
}
|
||||
&CompilationError::InvalidRuleHead => {
|
||||
functor!(atom!("invalid_head_of_rule"))
|
||||
|
||||
functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
|
||||
}
|
||||
&CompilationError::InvalidUseModuleDecl => {
|
||||
functor!(atom!("invalid_use_module_declaration"))
|
||||
@@ -785,14 +791,14 @@ impl MachineState {
|
||||
let stub_gen = || functor_stub(atom!("sort"), 2);
|
||||
|
||||
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) {
|
||||
CycleSearchResult::PartialList(..) => {
|
||||
let err = self.instantiation_error();
|
||||
return Err(self.error_form(err, stub_gen()))
|
||||
}
|
||||
CycleSearchResult::NotList(..) => {
|
||||
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
|
||||
let err = self.type_error(ValidType::List, list);
|
||||
return Err(self.error_form(err, stub_gen()));
|
||||
}
|
||||
@@ -800,7 +806,7 @@ impl MachineState {
|
||||
};
|
||||
|
||||
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);
|
||||
Err(self.error_form(err, stub_gen()))
|
||||
}
|
||||
@@ -812,7 +818,7 @@ impl MachineState {
|
||||
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
||||
|
||||
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);
|
||||
Err(self.error_form(err, stub_gen()))
|
||||
}
|
||||
@@ -878,7 +884,7 @@ impl MachineState {
|
||||
let err = self.instantiation_error();
|
||||
Err(self.error_form(err, stub_gen()))
|
||||
}
|
||||
CycleSearchResult::NotList(..) => {
|
||||
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
|
||||
let err = self.type_error(ValidType::List, pairs);
|
||||
Err(self.error_form(err, stub_gen()))
|
||||
}
|
||||
@@ -902,9 +908,7 @@ pub enum ExistenceError {
|
||||
pub enum SessionError {
|
||||
CompilationError(CompilationError),
|
||||
CannotOverwriteBuiltIn(PredicateKey),
|
||||
// CannotOverwriteImport(Atom),
|
||||
ExistenceError(ExistenceError),
|
||||
// InvalidFileName(Atom),
|
||||
ModuleDoesNotContainExport(Atom, PredicateKey),
|
||||
ModuleCannotImportSelf(Atom),
|
||||
NamelessEntry,
|
||||
|
||||
@@ -4,18 +4,18 @@ use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::fixtures::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_state::*;
|
||||
use crate::machine::streams::Stream;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
use modular_bitfield::{BitfieldSpecifier, bitfield};
|
||||
use modular_bitfield::specifiers::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeSet;
|
||||
use std::ops::Deref;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::types::*;
|
||||
@@ -59,9 +59,6 @@ impl PartialOrd<Ref> for HeapCellValue {
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => {
|
||||
// _ if self.is_ref() => {
|
||||
// let h1 = self.get_value();
|
||||
|
||||
match r.get_tag() {
|
||||
RefTag::StackCell => Some(Ordering::Less),
|
||||
_ => {
|
||||
@@ -77,52 +74,157 @@ impl PartialOrd<Ref> for HeapCellValue {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub enum IndexPtr {
|
||||
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
||||
DynamicIndex(usize),
|
||||
Index(usize),
|
||||
Undefined,
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
|
||||
#[bits = 7]
|
||||
pub enum IndexPtrTag {
|
||||
DynamicUndefined = 0b1000101, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
||||
DynamicIndex = 0b1000110,
|
||||
Index = 0b1000111,
|
||||
Undefined = 0b1001000,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>);
|
||||
#[bitfield]
|
||||
#[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 {
|
||||
type Target = Cell<IndexPtr>;
|
||||
type Target = TypedArenaPtr<IndexPtr>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0.deref()
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &TypedArenaPtr<IndexPtr> {
|
||||
&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 {
|
||||
#[inline]
|
||||
pub(super) fn new(ptr: IndexPtr) -> Self {
|
||||
CodeIndex(Rc::new(Cell::new(ptr)))
|
||||
pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self {
|
||||
CodeIndex(arena_alloc!(ptr, arena))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn is_undefined(&self) -> bool {
|
||||
match self.0.get() {
|
||||
IndexPtr::Undefined => true, // | &IndexPtr::DynamicUndefined => true,
|
||||
_ => false,
|
||||
}
|
||||
#[inline(always)]
|
||||
pub(crate) fn default(arena: &mut Arena) -> Self {
|
||||
CodeIndex::new(IndexPtr::undefined(), arena)
|
||||
}
|
||||
|
||||
pub(crate) fn local(&self) -> Option<usize> {
|
||||
match self.0.get() {
|
||||
IndexPtr::Index(i) => Some(i),
|
||||
IndexPtr::DynamicIndex(i) => Some(i),
|
||||
match self.0.tag() {
|
||||
IndexPtrTag::Index => Some(self.0.p() as usize),
|
||||
IndexPtrTag::DynamicIndex => Some(self.0.p() as usize),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn get(&self) -> IndexPtr {
|
||||
*self.0.deref()
|
||||
}
|
||||
|
||||
impl Default for CodeIndex {
|
||||
fn default() -> Self {
|
||||
CodeIndex(Rc::new(Cell::new(IndexPtr::Undefined)))
|
||||
#[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,
|
||||
) -> Option<CodeIndex> {
|
||||
if module == atom!("user") {
|
||||
match ClauseType::from(name, arity) {
|
||||
ClauseType::Named(arity, name, _) => self.code_dir.get(&(name, arity)).cloned(),
|
||||
_ => None,
|
||||
}
|
||||
/*match ClauseType::from(name, arity) {
|
||||
ClauseType::Named(arity, name, _) => */
|
||||
self.code_dir.get(&(name, arity)).cloned()
|
||||
/* _ => None,
|
||||
}*/
|
||||
} else {
|
||||
self.modules
|
||||
.get(&module)
|
||||
.and_then(|module| match ClauseType::from(name, arity) {
|
||||
ClauseType::Named(arity, name, _) => {
|
||||
.and_then(|module|/* |module| match ClauseType::from(name, arity) {
|
||||
ClauseType::Named(arity, name, _) => { */
|
||||
module.code_dir.get(&(name, arity)).cloned()
|
||||
/*
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
} */
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ pub struct MachineState {
|
||||
pub(super) hb: usize,
|
||||
pub(super) block: usize, // an offset into the OR stack.
|
||||
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) interms: Vec<Number>, // intermediate numbers.
|
||||
// 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("block", &self.block)
|
||||
.field("ball", &self.ball)
|
||||
.field("ball_stack", &self.ball_stack)
|
||||
.field("lifted_heap", &self.lifted_heap)
|
||||
.field("interms", &self.interms)
|
||||
.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;
|
||||
}
|
||||
|
||||
#[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 {
|
||||
fn push_var_eq_functors<'a>(
|
||||
heap: &mut Heap,
|
||||
@@ -494,7 +538,7 @@ impl MachineState {
|
||||
|
||||
loop {
|
||||
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],
|
||||
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
||||
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(
|
||||
&mut self.heap,
|
||||
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));
|
||||
}
|
||||
Err(err) => {
|
||||
if let ParserError::UnexpectedEOF = err {
|
||||
if let CompilationError::ParserError(ParserError::UnexpectedEOF) = err {
|
||||
self.eof_action(
|
||||
self.registers[2],
|
||||
stream,
|
||||
@@ -641,7 +689,25 @@ impl MachineState {
|
||||
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(
|
||||
&mut self.heap,
|
||||
&mut self.arena,
|
||||
op_dir,
|
||||
PrinterOutputter::new(),
|
||||
term_to_be_printed,
|
||||
);
|
||||
|
||||
if let HeapCellValueTag::Atom = ignore_ops.get_tag() {
|
||||
let name = cell_as_atom!(ignore_ops);
|
||||
printer.ignore_ops = name == atom!("true");
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
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!();
|
||||
}
|
||||
printer.ignore_ops = ignore_ops;
|
||||
printer.numbervars = numbervars;
|
||||
printer.quoted = quoted;
|
||||
|
||||
match Number::try_from(max_depth) {
|
||||
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(
|
||||
&mut self,
|
||||
input_stream: Stream,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
self.machine_st.read(input_stream, &self.op_dir)
|
||||
}
|
||||
|
||||
pub fn parse_and_write_parsed_term_to_heap(
|
||||
&mut self,
|
||||
term_string: &'static str,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena);
|
||||
self.write_parsed_term_to_heap(stream)
|
||||
}
|
||||
@@ -54,14 +54,13 @@ impl MockWAM {
|
||||
pub fn parse_and_print_term(
|
||||
&mut self,
|
||||
term_string: &'static str,
|
||||
) -> Result<String, ParserError> {
|
||||
) -> Result<String, CompilationError> {
|
||||
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
|
||||
|
||||
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
|
||||
|
||||
let mut printer = HCPrinter::new(
|
||||
&mut self.machine_st.heap,
|
||||
&mut self.machine_st.arena,
|
||||
&self.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(term_write_result.heap_loc),
|
||||
@@ -168,7 +167,7 @@ pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
|
||||
idx
|
||||
);
|
||||
assert!(
|
||||
cell.get_forwarding_bit() != Some(true),
|
||||
!cell.get_forwarding_bit(),
|
||||
"cell {:?} at index {} is forwarded",
|
||||
cell,
|
||||
idx
|
||||
@@ -187,7 +186,7 @@ pub fn all_cells_unmarked(heap: &Heap) {
|
||||
);
|
||||
|
||||
assert!(
|
||||
cell.get_forwarding_bit() != Some(true),
|
||||
!cell.get_forwarding_bit(),
|
||||
"cell {:?} at index {} is still forwarded",
|
||||
cell,
|
||||
idx
|
||||
@@ -200,7 +199,7 @@ pub(crate) fn write_parsed_term_to_heap(
|
||||
machine_st: &mut MachineState,
|
||||
input_stream: Stream,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
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,
|
||||
term_string: &'static str,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
let stream = Stream::from_static_string(term_string, &mut machine_st.arena);
|
||||
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_error = Stream::stderr(&mut machine_st.arena);
|
||||
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let mut wam = Machine {
|
||||
machine_st,
|
||||
indices: IndexStore::new(),
|
||||
@@ -232,6 +236,7 @@ impl Machine {
|
||||
user_output,
|
||||
user_error,
|
||||
load_contexts: vec![],
|
||||
runtime
|
||||
};
|
||||
|
||||
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")) {
|
||||
load_module(
|
||||
&mut wam.machine_st,
|
||||
&mut wam.indices.code_dir,
|
||||
&mut wam.indices.op_dir,
|
||||
&mut wam.indices.meta_predicates,
|
||||
@@ -291,6 +297,7 @@ impl Machine {
|
||||
|
||||
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
|
||||
load_module(
|
||||
&mut wam.machine_st,
|
||||
&mut wam.indices.code_dir,
|
||||
&mut wam.indices.op_dir,
|
||||
&mut wam.indices.meta_predicates,
|
||||
@@ -603,7 +610,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_term_compare() {
|
||||
use ordered_float::OrderedFloat;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
let mut wam = MachineState::new();
|
||||
@@ -771,9 +777,7 @@ mod tests {
|
||||
Some(Ordering::Greater)
|
||||
);
|
||||
|
||||
let one_p_one = typed_arena_ptr_as_cell!(
|
||||
arena_alloc!(OrderedFloat(1.1), &mut wam.arena)
|
||||
);
|
||||
let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena));
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod args;
|
||||
pub mod arithmetic_ops;
|
||||
pub mod attributed_variables;
|
||||
pub mod code_walker;
|
||||
@@ -21,10 +22,12 @@ pub mod streams;
|
||||
pub mod system_calls;
|
||||
pub mod term_stream;
|
||||
|
||||
use crate::arena::*;
|
||||
use crate::arithmetic::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::args::*;
|
||||
use crate::machine::compile::*;
|
||||
use crate::machine::copier::*;
|
||||
use crate::machine::heap::*;
|
||||
@@ -46,6 +49,7 @@ use std::cmp::Ordering;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
|
||||
@@ -60,6 +64,7 @@ pub struct Machine {
|
||||
pub(super) user_output: Stream,
|
||||
pub(super) user_error: Stream,
|
||||
pub(super) load_contexts: Vec<LoadContext>,
|
||||
pub(super) runtime: Runtime,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[inline]
|
||||
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")) {
|
||||
load_module(
|
||||
&mut self.machine_st,
|
||||
&mut self.indices.code_dir,
|
||||
&mut self.indices.op_dir,
|
||||
&mut self.indices.meta_predicates,
|
||||
@@ -283,7 +307,7 @@ impl Machine {
|
||||
}
|
||||
|
||||
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 {
|
||||
let key = (atom!("call"), arity);
|
||||
|
||||
@@ -291,7 +315,7 @@ impl Machine {
|
||||
Some(src_code_index) => {
|
||||
let target_code_index = target_code_dir
|
||||
.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());
|
||||
}
|
||||
@@ -307,6 +331,7 @@ impl Machine {
|
||||
// Import loader's exports into the builtins module so they will be
|
||||
// implicitly included in every further module.
|
||||
load_module(
|
||||
&mut self.machine_st,
|
||||
&mut builtins.code_dir,
|
||||
&mut builtins.op_dir,
|
||||
&mut builtins.meta_predicates,
|
||||
@@ -327,10 +352,10 @@ impl Machine {
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
@@ -389,19 +414,26 @@ impl Machine {
|
||||
|
||||
for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
|
||||
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 {
|
||||
use ref_thread_local::RefThreadLocal;
|
||||
|
||||
let args = MachineArgs::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_error = Stream::stderr(&mut machine_st.arena);
|
||||
|
||||
let runtime = tokio::runtime::Runtime::new()
|
||||
.unwrap();
|
||||
|
||||
let mut wam = Machine {
|
||||
machine_st,
|
||||
indices: IndexStore::new(),
|
||||
@@ -410,6 +442,7 @@ impl Machine {
|
||||
user_output,
|
||||
user_error,
|
||||
load_contexts: vec![],
|
||||
runtime,
|
||||
};
|
||||
|
||||
let mut lib_path = current_dir();
|
||||
@@ -444,6 +477,7 @@ impl Machine {
|
||||
|
||||
if let Some(builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
|
||||
load_module(
|
||||
&mut wam.machine_st,
|
||||
&mut wam.indices.code_dir,
|
||||
&mut wam.indices.op_dir,
|
||||
&mut wam.indices.meta_predicates,
|
||||
@@ -469,6 +503,7 @@ impl Machine {
|
||||
|
||||
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
|
||||
load_module(
|
||||
&mut wam.machine_st,
|
||||
&mut wam.indices.code_dir,
|
||||
&mut wam.indices.op_dir,
|
||||
&mut wam.indices.meta_predicates,
|
||||
@@ -655,18 +690,20 @@ impl Machine {
|
||||
|
||||
#[inline(always)]
|
||||
fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
||||
match idx {
|
||||
IndexPtr::DynamicUndefined => {
|
||||
let compiled_tl_index = idx.p() as usize;
|
||||
|
||||
match idx.tag() {
|
||||
IndexPtrTag::DynamicUndefined => {
|
||||
self.machine_st.fail = true;
|
||||
}
|
||||
IndexPtr::Undefined => {
|
||||
IndexPtrTag::Undefined => {
|
||||
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.call_at_index(arity, compiled_tl_index);
|
||||
}
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
IndexPtrTag::Index => {
|
||||
self.machine_st.call_at_index(arity, compiled_tl_index);
|
||||
}
|
||||
}
|
||||
@@ -676,18 +713,20 @@ impl Machine {
|
||||
|
||||
#[inline(always)]
|
||||
fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
||||
match idx {
|
||||
IndexPtr::DynamicUndefined => {
|
||||
let compiled_tl_index = idx.p() as usize;
|
||||
|
||||
match idx.tag() {
|
||||
IndexPtrTag::DynamicUndefined => {
|
||||
self.machine_st.fail = true;
|
||||
}
|
||||
IndexPtr::Undefined => {
|
||||
IndexPtrTag::Undefined => {
|
||||
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.execute_at_index(arity, compiled_tl_index);
|
||||
}
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
IndexPtrTag::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);
|
||||
}
|
||||
TrailEntryTag::TrailedAttrVarListLink => {
|
||||
let value = HeapCellValue::from_bytes(
|
||||
self.machine_st.trail[i + 1].into_bytes()
|
||||
);
|
||||
let l = self.machine_st.trail[i + 1].get_value() as usize;
|
||||
|
||||
if value.get_value() < self.machine_st.hb {
|
||||
self.machine_st.heap[h] = value;
|
||||
if l < self.machine_st.hb {
|
||||
self.machine_st.heap[h] = list_loc_as_cell!(l);
|
||||
} else {
|
||||
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
||||
}
|
||||
}
|
||||
TrailEntryTag::TrailedBlackboardEntry => {
|
||||
|
||||
@@ -109,6 +109,12 @@ impl<'a> HeapPStrIter<'a> {
|
||||
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> {
|
||||
let mut result = PStrPrefixCmpResult {
|
||||
focus: self.brent_st.hare,
|
||||
@@ -116,7 +122,12 @@ impl<'a> HeapPStrIter<'a> {
|
||||
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.offset = iteratee.offset();
|
||||
|
||||
@@ -130,7 +141,8 @@ impl<'a> HeapPStrIter<'a> {
|
||||
result.offset += c1.len_utf8();
|
||||
}
|
||||
} else {
|
||||
return Some(result);
|
||||
final_result = Some(result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
PStrIteratee::PStrSegment(_, pstr_atom, n) => {
|
||||
@@ -149,7 +161,8 @@ impl<'a> HeapPStrIter<'a> {
|
||||
result.prefix_len += s.len();
|
||||
result.offset += s.len();
|
||||
|
||||
return Some(result);
|
||||
final_result = Some(result);
|
||||
break;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
@@ -157,17 +170,27 @@ impl<'a> HeapPStrIter<'a> {
|
||||
}
|
||||
|
||||
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]
|
||||
pub fn chars(mut self) -> PStrCharsIter<'a> {
|
||||
let item = self.next();
|
||||
PStrCharsIter { iter: self, item }
|
||||
final_result
|
||||
}
|
||||
|
||||
fn walk_hare_to_cycle_end(&mut self) {
|
||||
@@ -223,7 +246,13 @@ impl<'a> HeapPStrIter<'a> {
|
||||
return name == atom!(".") && arity == 2;
|
||||
}
|
||||
(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)) => {
|
||||
arity == 0 && name.as_char().is_some()
|
||||
}
|
||||
@@ -309,7 +338,7 @@ impl<'a> HeapPStrIter<'a> {
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
}
|
||||
(HeapCellValueTag::Str, 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()];
|
||||
|
||||
if self.focus.is_string_terminator(self.heap) {
|
||||
if self.at_string_terminator() {
|
||||
self.focus = empty_list_as_cell!();
|
||||
self.brent_st.hare = iteratee.focus();
|
||||
|
||||
@@ -533,7 +562,6 @@ pub fn compare_pstr_prefixes<'a>(
|
||||
#[inline(always)]
|
||||
fn step(iter: &mut HeapPStrIter, hare: usize) -> Option<PStrIterStep> {
|
||||
let result = iter.step(hare);
|
||||
|
||||
iter.focus = iter.heap[hare];
|
||||
|
||||
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 c1 != c2 {
|
||||
return PStrCmpResult::Ordered(c2.cmp(&c1));
|
||||
return PStrCmpResult::Ordered(c1.cmp(&c2));
|
||||
}
|
||||
|
||||
let n1 = n + c1.len_utf8();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::atom_table::*;
|
||||
use crate::codegen::CodeGenSettings;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
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(
|
||||
mut term: Term,
|
||||
atom_tbl: &mut AtomTable,
|
||||
@@ -279,6 +256,7 @@ fn setup_qualified_import(
|
||||
* -
|
||||
* ?
|
||||
*/
|
||||
|
||||
fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
||||
mut terms: Vec<Term>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
@@ -296,6 +274,7 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
||||
atom!("+") => MetaSpec::Plus,
|
||||
atom!("-") => MetaSpec::Minus,
|
||||
atom!("?") => MetaSpec::Either,
|
||||
atom!(":") => MetaSpec::Colon,
|
||||
_ => 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]
|
||||
fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
name: Atom,
|
||||
terms: Vec<Term>,
|
||||
mut terms: Vec<Term>,
|
||||
call_policy: CallPolicy,
|
||||
) -> QueryTerm {
|
||||
let ct = loader.get_clause_type(name, terms.len());
|
||||
QueryTerm::Clause(Cell::default(), ct, terms, false)
|
||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||
// 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]
|
||||
@@ -506,32 +613,41 @@ fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
module_name: Atom,
|
||||
name: Atom,
|
||||
terms: Vec<Term>,
|
||||
mut terms: Vec<Term>,
|
||||
call_policy: CallPolicy,
|
||||
) -> QueryTerm {
|
||||
let ct = loader.get_qualified_clause_type(module_name, name, terms.len());
|
||||
QueryTerm::Clause(Cell::default(), ct, terms, false)
|
||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||
// supplementary code vector indices are unnecessary for
|
||||
// root-level clauses.
|
||||
terms.pop();
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Preprocessor {
|
||||
queue: VecDeque<VecDeque<Term>>,
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
impl Preprocessor {
|
||||
pub(super) fn new() -> Self {
|
||||
Preprocessor {
|
||||
queue: VecDeque::new(),
|
||||
}
|
||||
ct = ClauseType::Named(arity, name, idx);
|
||||
}
|
||||
|
||||
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
|
||||
_ => Err(CompilationError::InadmissibleFact),
|
||||
}
|
||||
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
|
||||
}
|
||||
|
||||
fn compute_head(&self, term: &Term) -> Vec<Term> {
|
||||
fn compute_head(term: &Term) -> Vec<Term> {
|
||||
let mut vars = IndexSet::new();
|
||||
|
||||
for term in post_order_iter(term) {
|
||||
@@ -546,8 +662,8 @@ impl Preprocessor {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn fabricate_rule_body(&self, vars: &Vec<Term>, body_term: Term) -> Term {
|
||||
let head_term = Term::Clause(Cell::default(), atom!(""), vars.clone());
|
||||
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
|
||||
let head_term = Term::Clause(Cell::default(), atom!(""), vars.iter().cloned().collect());
|
||||
let rule = vec![head_term, body_term];
|
||||
|
||||
Term::Clause(Cell::default(), atom!(":-"), rule)
|
||||
@@ -556,17 +672,17 @@ impl Preprocessor {
|
||||
// the terms form the body of the rule. We create a head, by
|
||||
// gathering variables from the body of terms and recording them
|
||||
// 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
|
||||
// (the arity) as well.
|
||||
let vars = self.compute_head(&body_term);
|
||||
let rule = self.fabricate_rule_body(&vars, body_term);
|
||||
let vars = compute_head(&body_term);
|
||||
let rule = build_rule_body(&vars, body_term);
|
||||
|
||||
(vars, VecDeque::from(vec![rule]))
|
||||
}
|
||||
|
||||
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
||||
let vars = self.compute_head(&body_term);
|
||||
fn build_disjunct(body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
||||
let vars = compute_head(&body_term);
|
||||
let results = unfold_by_str(body_term, atom!(";"))
|
||||
.into_iter()
|
||||
.map(|term| {
|
||||
@@ -578,14 +694,14 @@ impl Preprocessor {
|
||||
let term = subterms.pop().unwrap();
|
||||
let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
|
||||
|
||||
self.fabricate_rule_body(&vars, clause)
|
||||
build_rule_body(&vars, clause)
|
||||
})
|
||||
.collect();
|
||||
|
||||
(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 comma_sym = atom!(",");
|
||||
let cut_sym = Literal::Atom(atom!("!"));
|
||||
@@ -608,7 +724,28 @@ impl Preprocessor {
|
||||
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>>(
|
||||
@@ -621,7 +758,12 @@ impl Preprocessor {
|
||||
if name == atom!("!") || name == atom!("blocked_!") {
|
||||
Ok(QueryTerm::BlockedCut)
|
||||
} 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),
|
||||
@@ -632,7 +774,7 @@ impl Preprocessor {
|
||||
(atom!(";"), 2) => {
|
||||
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);
|
||||
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
@@ -641,7 +783,7 @@ impl Preprocessor {
|
||||
let conq = 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);
|
||||
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
@@ -658,7 +800,7 @@ impl Preprocessor {
|
||||
let terms = vec![prec, conq];
|
||||
|
||||
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);
|
||||
self.queue.push_back(clauses);
|
||||
@@ -685,6 +827,7 @@ impl Preprocessor {
|
||||
module_name,
|
||||
predicate_name,
|
||||
vec![],
|
||||
self.settings.default_call_policy(),
|
||||
)),
|
||||
(
|
||||
Term::Literal(_, Literal::Atom(module_name)),
|
||||
@@ -694,22 +837,29 @@ impl Preprocessor {
|
||||
module_name,
|
||||
name,
|
||||
terms,
|
||||
self.settings.default_call_policy()
|
||||
)),
|
||||
(module_name, predicate_name) => {
|
||||
terms.push(module_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(
|
||||
Cell::default(),
|
||||
ClauseType::CallN(1),
|
||||
vec![term],
|
||||
false,
|
||||
self.settings.default_call_policy(),
|
||||
)),
|
||||
_ => Err(CompilationError::InadmissibleQueryTerm),
|
||||
}
|
||||
@@ -722,10 +872,10 @@ impl Preprocessor {
|
||||
) -> Result<QueryTerm, CompilationError> {
|
||||
match term {
|
||||
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())
|
||||
.map(|mut query_term| {
|
||||
query_term.set_default_caller();
|
||||
query_term.set_call_policy(CallPolicy::Counted);
|
||||
query_term
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -10,8 +10,7 @@ project_attributes(QueryVars, AttrVars) :-
|
||||
; E = error(evaluation_error((Module:project_attributes)/2), _)
|
||||
) ->
|
||||
true
|
||||
; write_term('caught: ', [quoted(false)]),
|
||||
writeq(E),
|
||||
; loader:write_error(E),
|
||||
nl
|
||||
).
|
||||
|
||||
@@ -33,9 +32,9 @@ call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :-
|
||||
|
||||
'$print_attribute_goals_exception'(Module, E) :-
|
||||
( E = error(evaluation_error((Module:attribute_goals)/3), attribute_goals/3)
|
||||
; E = error(existence_error(procedure, attribute_goals/3), attribute_goals/3)
|
||||
-> true
|
||||
; write_term('caught: ', [quoted(false)]),
|
||||
writeq(E),
|
||||
; loader:write_error(E),
|
||||
nl
|
||||
).
|
||||
|
||||
|
||||
@@ -15,16 +15,18 @@ pub use modular_bitfield::prelude::*;
|
||||
use std::cmp::Ordering;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::hash::{Hash};
|
||||
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::net::{TcpStream, Shutdown};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr;
|
||||
|
||||
use native_tls::TlsStream;
|
||||
use hyper::body::{Bytes, Sender};
|
||||
|
||||
#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[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)]
|
||||
pub struct OutputFileStream {
|
||||
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)]
|
||||
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!(CharReader<NamedTcpStream>, NamedTcpStream);
|
||||
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!(StaticStringStream, StaticStringStream);
|
||||
arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream);
|
||||
@@ -388,6 +448,8 @@ pub enum Stream {
|
||||
StaticString(TypedArenaPtr<StreamLayout<StaticStringStream>>),
|
||||
NamedTcp(TypedArenaPtr<StreamLayout<CharReader<NamedTcpStream>>>),
|
||||
NamedTls(TypedArenaPtr<StreamLayout<CharReader<NamedTlsStream>>>),
|
||||
HttpRead(TypedArenaPtr<StreamLayout<CharReader<HttpReadStream>>>),
|
||||
HttpWrite(TypedArenaPtr<StreamLayout<CharReader<HttpWriteStream>>>),
|
||||
Null(StreamOptions),
|
||||
Readline(TypedArenaPtr<StreamLayout<ReadlineStream>>),
|
||||
StandardOutput(TypedArenaPtr<StreamLayout<StandardOutputStream>>),
|
||||
@@ -426,9 +488,9 @@ impl Stream {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn stdin(arena: &mut Arena) -> Stream {
|
||||
pub fn stdin(arena: &mut Arena, add_history: bool) -> Stream {
|
||||
Stream::Readline(arena_alloc!(
|
||||
StreamLayout::new(ReadlineStream::new("")),
|
||||
StreamLayout::new(ReadlineStream::new("", add_history)),
|
||||
arena
|
||||
))
|
||||
}
|
||||
@@ -442,6 +504,8 @@ impl Stream {
|
||||
}
|
||||
ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(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::StaticStringStream => {
|
||||
Stream::StaticString(TypedArenaPtr::new(ptr as *mut _))
|
||||
@@ -452,7 +516,9 @@ impl Stream {
|
||||
ArenaHeaderTag::StandardErrorStream => {
|
||||
Stream::StandardError(TypedArenaPtr::new(ptr as *mut _))
|
||||
}
|
||||
ArenaHeaderTag::NullStream => Stream::Null(StreamOptions::default()),
|
||||
ArenaHeaderTag::Dropped | ArenaHeaderTag::NullStream => {
|
||||
Stream::Null(StreamOptions::default())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -492,6 +558,8 @@ impl Stream {
|
||||
Stream::StaticString(ptr) => ptr.header_ptr(),
|
||||
Stream::NamedTcp(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::Readline(ptr) => ptr.header_ptr(),
|
||||
Stream::StandardOutput(ptr) => ptr.header_ptr(),
|
||||
@@ -507,6 +575,8 @@ impl Stream {
|
||||
Stream::StaticString(ref ptr) => &ptr.options,
|
||||
Stream::NamedTcp(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::Readline(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::NamedTcp(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::Readline(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::NamedTcp(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::Readline(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::NamedTcp(ptr) => ptr.lines_read = value,
|
||||
Stream::NamedTls(ptr) => ptr.lines_read = value,
|
||||
Stream::HttpRead(ptr) => ptr.lines_read = value,
|
||||
Stream::HttpWrite(_) => {}
|
||||
Stream::Null(_) => {}
|
||||
Stream::Readline(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::NamedTcp(ptr) => ptr.lines_read,
|
||||
Stream::NamedTls(ptr) => ptr.lines_read,
|
||||
Stream::HttpRead(ptr) => ptr.lines_read,
|
||||
Stream::HttpWrite(_) => 0,
|
||||
Stream::Null(_) => 0,
|
||||
Stream::Readline(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::NamedTcp(tcp_stream) => (*tcp_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::StaticString(src) => (*src).peek_char(),
|
||||
Stream::Byte(cursor) => (*cursor).peek_char(),
|
||||
Stream::OutputFile(_) |
|
||||
Stream::StandardError(_) |
|
||||
Stream::StandardOutput(_) |
|
||||
Stream::HttpWrite(_) |
|
||||
Stream::Null(_) => Some(Err(std::io::Error::new(
|
||||
ErrorKind::PermissionDenied,
|
||||
StreamError::ReadFromOutputStream,
|
||||
@@ -602,12 +682,14 @@ impl CharRead for Stream {
|
||||
Stream::InputFile(file) => (*file).read_char(),
|
||||
Stream::NamedTcp(tcp_stream) => (*tcp_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::StaticString(src) => (*src).read_char(),
|
||||
Stream::Byte(cursor) => (*cursor).read_char(),
|
||||
Stream::OutputFile(_) |
|
||||
Stream::StandardError(_) |
|
||||
Stream::StandardOutput(_) |
|
||||
Stream::HttpWrite(_) |
|
||||
Stream::Null(_) => Some(Err(std::io::Error::new(
|
||||
ErrorKind::PermissionDenied,
|
||||
StreamError::ReadFromOutputStream,
|
||||
@@ -620,12 +702,14 @@ impl CharRead for Stream {
|
||||
Stream::InputFile(file) => file.put_back_char(c),
|
||||
Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c),
|
||||
Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c),
|
||||
Stream::HttpRead(http_stream) => http_stream.put_back_char(c),
|
||||
Stream::Readline(rl_stream) => rl_stream.put_back_char(c),
|
||||
Stream::StaticString(src) => src.put_back_char(c),
|
||||
Stream::Byte(cursor) => cursor.put_back_char(c),
|
||||
Stream::OutputFile(_) |
|
||||
Stream::StandardError(_) |
|
||||
Stream::StandardOutput(_) |
|
||||
Stream::HttpWrite(_) |
|
||||
Stream::Null(_) => {}
|
||||
}
|
||||
}
|
||||
@@ -635,12 +719,14 @@ impl CharRead for Stream {
|
||||
Stream::InputFile(ref mut file) => file.consume(nread),
|
||||
Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread),
|
||||
Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread),
|
||||
Stream::HttpRead(ref mut http_stream) => http_stream.consume(nread),
|
||||
Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread),
|
||||
Stream::StaticString(ref mut src) => src.consume(nread),
|
||||
Stream::Byte(ref mut cursor) => cursor.consume(nread),
|
||||
Stream::OutputFile(_) |
|
||||
Stream::StandardError(_) |
|
||||
Stream::StandardOutput(_) |
|
||||
Stream::HttpWrite(_) |
|
||||
Stream::Null(_) => {}
|
||||
}
|
||||
}
|
||||
@@ -653,12 +739,14 @@ impl Read for Stream {
|
||||
Stream::InputFile(file) => (*file).read(buf),
|
||||
Stream::NamedTcp(tcp_stream) => (*tcp_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::StaticString(src) => (*src).read(buf),
|
||||
Stream::Byte(cursor) => (*cursor).read(buf),
|
||||
Stream::OutputFile(_)
|
||||
| Stream::StandardError(_)
|
||||
| Stream::StandardOutput(_)
|
||||
| Stream::HttpWrite(_)
|
||||
| Stream::Null(_) => Err(std::io::Error::new(
|
||||
ErrorKind::PermissionDenied,
|
||||
StreamError::ReadFromOutputStream,
|
||||
@@ -678,6 +766,8 @@ impl Write for Stream {
|
||||
Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf),
|
||||
Stream::StandardOutput(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::Readline(_) |
|
||||
Stream::InputFile(..) |
|
||||
@@ -696,6 +786,8 @@ impl Write for Stream {
|
||||
Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(),
|
||||
Stream::StandardError(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::Readline(_) |
|
||||
Stream::InputFile(_) |
|
||||
@@ -776,8 +868,8 @@ impl Stream {
|
||||
pub(crate) fn position(&mut self) -> Option<(u64, usize)> {
|
||||
// returns lines_read, position.
|
||||
let result = match self {
|
||||
Stream::InputFile(ref mut file_stream) => {
|
||||
file_stream.get_mut().file.seek(SeekFrom::Current(0)).ok()
|
||||
Stream::InputFile(file_stream) => {
|
||||
file_stream.position()
|
||||
}
|
||||
Stream::NamedTcp(..)
|
||||
| Stream::NamedTls(..)
|
||||
@@ -801,6 +893,7 @@ impl Stream {
|
||||
} = &mut **stream_layout;
|
||||
|
||||
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() {
|
||||
*past_end_of_stream = position > metadata.len();
|
||||
@@ -816,10 +909,11 @@ impl Stream {
|
||||
Stream::Byte(stream) => stream.past_end_of_stream,
|
||||
Stream::InputFile(stream) => stream.past_end_of_stream,
|
||||
Stream::OutputFile(stream) => stream.past_end_of_stream,
|
||||
// Stream::PausedProlog(stream) => stream.paused_stream.past_end_of_stream(),
|
||||
Stream::StaticString(stream) => stream.past_end_of_stream,
|
||||
Stream::NamedTcp(stream) => stream.past_end_of_stream,
|
||||
Stream::NamedTls(stream) => stream.past_end_of_stream,
|
||||
Stream::HttpRead(stream) => stream.past_end_of_stream,
|
||||
Stream::HttpWrite(stream) => stream.past_end_of_stream,
|
||||
Stream::Null(_) => false,
|
||||
Stream::Readline(stream) => stream.past_end_of_stream,
|
||||
Stream::StandardOutput(stream) => stream.past_end_of_stream,
|
||||
@@ -841,6 +935,8 @@ impl Stream {
|
||||
Stream::StaticString(stream) => stream.past_end_of_stream = value,
|
||||
Stream::NamedTcp(stream) => stream.past_end_of_stream = value,
|
||||
Stream::NamedTls(stream) => stream.past_end_of_stream = value,
|
||||
Stream::HttpRead(stream) => stream.past_end_of_stream = value,
|
||||
Stream::HttpWrite(stream) => stream.past_end_of_stream = value,
|
||||
Stream::Null(_) => {}
|
||||
Stream::Readline(stream) => stream.past_end_of_stream = value,
|
||||
Stream::StandardOutput(stream) => stream.past_end_of_stream = value,
|
||||
@@ -855,6 +951,8 @@ impl Stream {
|
||||
}
|
||||
|
||||
if let Stream::InputFile(stream_layout) = self {
|
||||
let position = stream_layout.position();
|
||||
|
||||
let StreamLayout {
|
||||
past_end_of_stream,
|
||||
stream,
|
||||
@@ -863,7 +961,7 @@ impl Stream {
|
||||
|
||||
match stream.get_ref().file.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()) {
|
||||
Ordering::Equal => AtEndOfStream::At,
|
||||
Ordering::Less => AtEndOfStream::Not,
|
||||
@@ -904,10 +1002,11 @@ impl Stream {
|
||||
Stream::Byte(_)
|
||||
| Stream::Readline(_)
|
||||
| Stream::StaticString(_)
|
||||
| Stream::HttpRead(_)
|
||||
| Stream::InputFile(..) => atom!("read"),
|
||||
Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"),
|
||||
Stream::OutputFile(file) if file.is_append => atom!("append"),
|
||||
Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) => atom!("write"),
|
||||
Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) | Stream::HttpWrite(_) => atom!("write"),
|
||||
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]
|
||||
pub(crate) fn from_file_as_output(
|
||||
file_name: Atom,
|
||||
@@ -988,18 +1115,51 @@ impl Stream {
|
||||
|
||||
#[inline]
|
||||
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) => {
|
||||
tcp_stream.inner_mut().tcp_stream.shutdown(Shutdown::Both)
|
||||
},
|
||||
Stream::NamedTls(ref mut tls_stream) => {
|
||||
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());
|
||||
result
|
||||
Ok(())
|
||||
}
|
||||
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]
|
||||
@@ -1016,6 +1176,7 @@ impl Stream {
|
||||
match self {
|
||||
Stream::NamedTcp(..)
|
||||
| Stream::NamedTls(..)
|
||||
| Stream::HttpRead(..)
|
||||
| Stream::Byte(_)
|
||||
| Stream::Readline(_)
|
||||
| Stream::StaticString(_)
|
||||
@@ -1031,6 +1192,7 @@ impl Stream {
|
||||
| Stream::StandardOutput(_)
|
||||
| Stream::NamedTcp(..)
|
||||
| Stream::NamedTls(..)
|
||||
| Stream::HttpWrite(..)
|
||||
| Stream::Byte(_)
|
||||
| Stream::OutputFile(..) => true,
|
||||
_ => false,
|
||||
@@ -1160,6 +1322,18 @@ impl MachineState {
|
||||
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
|
||||
}
|
||||
@@ -1176,6 +1350,19 @@ impl MachineState {
|
||||
_ => 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!()
|
||||
}
|
||||
@@ -1186,6 +1373,13 @@ impl MachineState {
|
||||
debug_assert_eq!(arity, 0);
|
||||
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!()
|
||||
}
|
||||
@@ -1200,6 +1394,17 @@ impl MachineState {
|
||||
_ => 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!()
|
||||
}
|
||||
@@ -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) => {
|
||||
match_untyped_arena_ptr!(ptr,
|
||||
(ArenaHeaderTag::Stream, stream) => {
|
||||
@@ -1249,6 +1472,12 @@ impl MachineState {
|
||||
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 err = self.permission_error(perm, err_atom, stream_as_cell!(stream));
|
||||
|
||||
return self.error_form(err, stub);
|
||||
self.error_form(err, stub)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -1332,7 +1561,7 @@ impl MachineState {
|
||||
let stub = functor_stub(stub_name, stub_arity);
|
||||
let err = self.permission_error(Permission::Open, atom!("source_sink"), culprit);
|
||||
|
||||
return self.error_form(err, stub);
|
||||
self.error_form(err, stub)
|
||||
}
|
||||
|
||||
pub(crate) fn occupied_alias_permission_error(
|
||||
@@ -1342,24 +1571,22 @@ impl MachineState {
|
||||
stub_arity: usize,
|
||||
) -> MachineStub {
|
||||
let stub = functor_stub(stub_name, stub_arity);
|
||||
let alias_name = atom!("alias");
|
||||
|
||||
let err = self.permission_error(
|
||||
Permission::Open,
|
||||
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 {
|
||||
let stub = functor_stub(stub_name, stub_arity);
|
||||
|
||||
let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]);
|
||||
let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub);
|
||||
|
||||
return self.error_form(err, stub);
|
||||
self.error_form(err, stub)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
($cell:expr) => {{
|
||||
let ptr_u64 = ConsPtr::from_bytes($cell.into_bytes());
|
||||
F64Ptr(TypedArenaPtr::new(
|
||||
ptr_u64.as_ptr() as *mut OrderedFloat<f64>
|
||||
))
|
||||
let offset = $cell.get_value();
|
||||
F64Ptr::from_offset(offset)
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -246,13 +244,6 @@ macro_rules! match_untyped_arena_ptr_pat_body {
|
||||
#[allow(unused_braces)]
|
||||
$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) => {{
|
||||
let payload_ptr = unsafe { std::mem::transmute::<_, *mut Rational>($ptr.payload_offset()) };
|
||||
let $n = TypedArenaPtr::new(payload_ptr);
|
||||
@@ -281,6 +272,26 @@ macro_rules! match_untyped_arena_ptr_pat_body {
|
||||
#[allow(unused_braces)]
|
||||
$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) => {{
|
||||
let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
|
||||
#[allow(unused_braces)]
|
||||
@@ -294,12 +305,20 @@ macro_rules! match_untyped_arena_ptr_pat {
|
||||
| ArenaHeaderTag::OutputFileStream
|
||||
| ArenaHeaderTag::NamedTcpStream
|
||||
| ArenaHeaderTag::NamedTlsStream
|
||||
| ArenaHeaderTag::HttpReadStream
|
||||
| ArenaHeaderTag::HttpWriteStream
|
||||
| ArenaHeaderTag::ReadlineStream
|
||||
| ArenaHeaderTag::StaticStringStream
|
||||
| ArenaHeaderTag::ByteStream
|
||||
| ArenaHeaderTag::StandardOutputStream
|
||||
| ArenaHeaderTag::StandardErrorStream
|
||||
};
|
||||
(IndexPtr) => {
|
||||
ArenaHeaderTag::IndexPtrUndefined |
|
||||
ArenaHeaderTag::IndexPtrDynamicUndefined |
|
||||
ArenaHeaderTag::IndexPtrDynamicIndex |
|
||||
ArenaHeaderTag::IndexPtrIndex
|
||||
};
|
||||
($tag:ident) => {
|
||||
ArenaHeaderTag::$tag
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::parser::char_reader::*;
|
||||
use crate::types::HeapCellValueTag;
|
||||
|
||||
@@ -11,7 +12,7 @@ use std::ops::Neg;
|
||||
use std::rc::Rc;
|
||||
use std::vec::Vec;
|
||||
|
||||
use rug::{Integer, Rational};
|
||||
use crate::parser::rug::{Integer, Rational};
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
@@ -234,12 +235,22 @@ pub enum GenContext {
|
||||
}
|
||||
|
||||
impl GenContext {
|
||||
#[inline]
|
||||
pub fn chunk_num(self) -> usize {
|
||||
match self {
|
||||
GenContext::Head => 0,
|
||||
GenContext::Mid(cn) | GenContext::Last(cn) => cn,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_last(self) -> bool {
|
||||
if let GenContext::Last(_) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
@@ -361,28 +372,28 @@ pub enum ArithmeticError {
|
||||
#[derive(Debug)]
|
||||
pub enum ParserError {
|
||||
BackQuotedString(usize, usize),
|
||||
UnexpectedChar(char, usize, usize),
|
||||
UnexpectedEOF,
|
||||
IO(IOError),
|
||||
IncompleteReduction(usize, usize),
|
||||
InvalidSingleQuotedCharacter(char),
|
||||
LexicalError(lexical::Error),
|
||||
MissingQuote(usize, usize),
|
||||
NonPrologChar(usize, usize),
|
||||
ParseBigInt(usize, usize),
|
||||
LexicalError(lexical::Error),
|
||||
UnexpectedChar(char, usize, usize),
|
||||
UnexpectedEOF,
|
||||
Utf8Error(usize, usize),
|
||||
}
|
||||
|
||||
impl ParserError {
|
||||
pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
|
||||
match self {
|
||||
&ParserError::BackQuotedString(line_num, col_num)
|
||||
| &ParserError::UnexpectedChar(_, line_num, col_num)
|
||||
| &ParserError::IncompleteReduction(line_num, col_num)
|
||||
| &ParserError::MissingQuote(line_num, col_num)
|
||||
| &ParserError::NonPrologChar(line_num, col_num)
|
||||
| &ParserError::ParseBigInt(line_num, col_num)
|
||||
| &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
|
||||
&ParserError::BackQuotedString(line_num, col_num) |
|
||||
&ParserError::IncompleteReduction(line_num, col_num) |
|
||||
&ParserError::MissingQuote(line_num, col_num) |
|
||||
&ParserError::NonPrologChar(line_num, col_num) |
|
||||
&ParserError::ParseBigInt(line_num, col_num) |
|
||||
&ParserError::UnexpectedChar(_, line_num, col_num) |
|
||||
&ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -390,8 +401,6 @@ impl ParserError {
|
||||
pub fn as_atom(&self) -> Atom {
|
||||
match self {
|
||||
ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
|
||||
ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
|
||||
ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"),
|
||||
ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
|
||||
ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"),
|
||||
ParserError::IO(_) => atom!("input_output_error"),
|
||||
@@ -399,6 +408,8 @@ impl ParserError {
|
||||
ParserError::MissingQuote(..) => atom!("missing_quote"),
|
||||
ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
|
||||
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"),
|
||||
}
|
||||
}
|
||||
@@ -466,7 +477,8 @@ pub enum Fixity {
|
||||
#[repr(u64)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct Fixnum {
|
||||
num: B57,
|
||||
num: B56,
|
||||
#[allow(unused)] f: bool,
|
||||
#[allow(unused)] m: bool,
|
||||
#[allow(unused)] tag: B6,
|
||||
}
|
||||
@@ -475,22 +487,23 @@ impl Fixnum {
|
||||
#[inline]
|
||||
pub fn build_with(num: i64) -> Self {
|
||||
Fixnum::new()
|
||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))
|
||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
|
||||
.with_tag(HeapCellValueTag::Fixnum as u8)
|
||||
.with_m(false)
|
||||
//num as u64).with__m(false)
|
||||
.with_f(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> {
|
||||
const UPPER_BOUND: i64 = (1 << 56) - 1;
|
||||
const LOWER_BOUND: i64 = -(1 << 56);
|
||||
const UPPER_BOUND: i64 = (1 << 55) - 1;
|
||||
const LOWER_BOUND: i64 = -(1 << 55);
|
||||
|
||||
if LOWER_BOUND <= num && num <= UPPER_BOUND {
|
||||
Ok(Fixnum::new()
|
||||
.with_m(false)
|
||||
.with_f(false)
|
||||
.with_tag(HeapCellValueTag::Fixnum as u8)
|
||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))) //num as u64 & ((1 << 57) - 1)))
|
||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1)))
|
||||
} else {
|
||||
Err(OutOfBounds {})
|
||||
}
|
||||
@@ -499,7 +512,7 @@ impl Fixnum {
|
||||
#[inline]
|
||||
pub fn get_num(self) -> i64 {
|
||||
let n = self.num() as i64;
|
||||
let (n, overflowed) = (n << 7).overflowing_shr(7); // sign-extend the 57-bit signed fixnum.
|
||||
let (n, overflowed) = (n << 8).overflowing_shr(8);
|
||||
debug_assert_eq!(overflowed, false);
|
||||
n
|
||||
}
|
||||
@@ -518,30 +531,34 @@ impl Neg for Fixnum {
|
||||
pub enum Literal {
|
||||
Atom(Atom),
|
||||
Char(char),
|
||||
CodeIndex(CodeIndex),
|
||||
Fixnum(Fixnum),
|
||||
Integer(TypedArenaPtr<Integer>),
|
||||
Rational(TypedArenaPtr<Rational>),
|
||||
Float(F64Ptr),
|
||||
Float(F64Offset),
|
||||
String(Atom),
|
||||
}
|
||||
|
||||
impl From<F64Ptr> for Literal {
|
||||
#[inline(always)]
|
||||
fn from(ptr: F64Ptr) -> Literal {
|
||||
Literal::Float(ptr.as_offset())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Literal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Literal::Atom(ref atom) => {
|
||||
// if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) {
|
||||
// write!(f, "'{}'", atom)
|
||||
// } else {
|
||||
write!(f, "{}", atom.flat_index())
|
||||
// }
|
||||
}
|
||||
Literal::Char(c) => write!(f, "'{}'", *c as u32),
|
||||
Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64),
|
||||
Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
|
||||
Literal::Integer(ref n) => write!(f, "{}", n),
|
||||
Literal::Rational(ref n) => write!(f, "{}", n),
|
||||
Literal::Float(ref n) => write!(f, "{}", *n),
|
||||
Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
|
||||
// Literal::Usize(integer) => write!(f, "u{}", integer),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -561,7 +578,10 @@ pub enum Term {
|
||||
Clause(Cell<RegType>, Atom, Vec<Term>),
|
||||
Cons(Cell<RegType>, Box<Term>, Box<Term>),
|
||||
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>),
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,14 @@ impl<R> CharReader<R> {
|
||||
pub fn inner_mut(&mut self) -> &mut R {
|
||||
&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 {
|
||||
@@ -96,7 +104,7 @@ impl<R> CharReader<R> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
fn reset_buffer(&mut self) {
|
||||
pub fn reset_buffer(&mut self) {
|
||||
self.buf.clear();
|
||||
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> {
|
||||
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
|
||||
@@ -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)]
|
||||
mod tests {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use lexical::parse_lossy;
|
||||
use ordered_float::*;
|
||||
|
||||
use crate::arena::ArenaAllocated;
|
||||
use crate::atom_table::*;
|
||||
pub use crate::machine::machine_state::*;
|
||||
use crate::parser::ast::*;
|
||||
@@ -367,7 +367,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
||||
if hexadecimal_digit_char!(c) {
|
||||
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
|
||||
} 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 {
|
||||
// on failure, restore the token characters and backslash.
|
||||
// self.reader.put_back_all(token.chars().map(Ok));
|
||||
// self.reader.put_back(Ok('\\'));
|
||||
|
||||
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
|
||||
Err(ParserError::IncompleteReduction(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> {
|
||||
self.return_char(token.pop().unwrap());
|
||||
|
||||
let result = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?);
|
||||
Ok(Token::Literal(Literal::Float(arena_alloc!(
|
||||
result,
|
||||
&mut self.machine_st.arena
|
||||
))))
|
||||
let n = parse_lossy::<f64, _>(token.as_bytes())?;
|
||||
Ok(Token::Literal(Literal::from(float_alloc!(n, self.machine_st.arena))))
|
||||
}
|
||||
|
||||
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())?);
|
||||
Ok(Token::Literal(Literal::Float(arena_alloc!(
|
||||
n,
|
||||
&mut self.machine_st.arena
|
||||
))))
|
||||
let n = parse_lossy::<f64, _>(token.as_bytes())?;
|
||||
Ok(Token::Literal(Literal::from(
|
||||
float_alloc!(n, self.machine_st.arena)
|
||||
)))
|
||||
} else {
|
||||
return Ok(self.vacate_with_float(token)?);
|
||||
}
|
||||
} else {
|
||||
let n = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?);
|
||||
Ok(Token::Literal(Literal::Float(arena_alloc!(
|
||||
n,
|
||||
&mut self.machine_st.arena
|
||||
))))
|
||||
let n = parse_lossy::<f64, _>(token.as_bytes())?;
|
||||
Ok(Token::Literal(Literal::from(
|
||||
float_alloc!(n, self.machine_st.arena)
|
||||
)))
|
||||
}
|
||||
} else {
|
||||
self.return_char('.');
|
||||
|
||||
@@ -7,28 +7,7 @@ macro_rules! char_class {
|
||||
#[macro_export]
|
||||
macro_rules! alpha_char {
|
||||
($c: expr) => {
|
||||
match $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,
|
||||
}
|
||||
$c.is_alphabetic() || $c == '_'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -63,7 +42,7 @@ macro_rules! octet_char {
|
||||
#[macro_export]
|
||||
macro_rules! capital_letter_char {
|
||||
($c: expr) => {
|
||||
('A'..='Z').contains(&$c)
|
||||
$c.is_uppercase()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -174,7 +153,7 @@ macro_rules! octal_digit_char {
|
||||
#[macro_export]
|
||||
macro_rules! binary_digit_char {
|
||||
($c: expr) => {
|
||||
$c >= '0' && $c <= '1'
|
||||
$c == '0' || $c == '1'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -213,7 +192,7 @@ macro_rules! single_quote_char {
|
||||
#[macro_export]
|
||||
macro_rules! small_letter_char {
|
||||
($c: expr) => {
|
||||
('a'..='z').contains(&$c)
|
||||
$c.is_alphabetic() && !$c.is_uppercase()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#[cfg(feature = "num-rug-adapter")]
|
||||
use num_rug_adapter as rug;
|
||||
pub use num_rug_adapter as rug;
|
||||
|
||||
#[cfg(feature = "rug")]
|
||||
pub use rug;
|
||||
|
||||
|
||||
@@ -4,9 +4,7 @@ use crate::parser::ast::*;
|
||||
use crate::parser::char_reader::*;
|
||||
use crate::parser::lexer::*;
|
||||
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use rug::ops::NegAssign;
|
||||
use crate::parser::rug::ops::NegAssign;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::mem;
|
||||
@@ -51,11 +49,10 @@ struct TokenDesc {
|
||||
spec: u32,
|
||||
}
|
||||
|
||||
fn is_partial_string(
|
||||
pub(crate) fn as_partial_string(
|
||||
head: Term,
|
||||
mut tail: Term,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> Result<(Atom, Option<Box<Term>>), Term> {
|
||||
) -> Result<(String, Option<Box<Term>>), Term> {
|
||||
let mut string = match &head {
|
||||
Term::Literal(_, Literal::Atom(atom)) => {
|
||||
if let Some(c) = atom.as_char() {
|
||||
@@ -94,6 +91,15 @@ fn is_partial_string(
|
||||
|
||||
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 = mem::replace(tail_ref, Term::AnonVar);
|
||||
break;
|
||||
@@ -103,21 +109,17 @@ fn is_partial_string(
|
||||
|
||||
match &tail {
|
||||
Term::AnonVar | Term::Var(..) => {
|
||||
let pstr_atom = atom_tbl.build_with(&string);
|
||||
Ok((pstr_atom, Some(Box::new(tail))))
|
||||
Ok((string, Some(Box::new(tail))))
|
||||
}
|
||||
Term::Literal(_, Literal::Atom(atom!("[]"))) => {
|
||||
let pstr_atom = atom_tbl.build_with(&string);
|
||||
Ok((pstr_atom, None))
|
||||
Ok((string, None))
|
||||
}
|
||||
Term::Literal(_, Literal::String(tail)) => {
|
||||
string += tail.as_str();
|
||||
let pstr_atom = atom_tbl.build_with(&string);
|
||||
Ok((pstr_atom, None))
|
||||
Ok((string, None))
|
||||
}
|
||||
_ => {
|
||||
let pstr_atom = atom_tbl.build_with(&string);
|
||||
Ok((pstr_atom, Some(Box::new(tail))))
|
||||
Ok((string, Some(Box::new(tail))))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -414,7 +416,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
||||
TokenType::Term
|
||||
}
|
||||
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
|
||||
}
|
||||
Token::Literal(c) => {
|
||||
@@ -566,24 +568,19 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
||||
let head = subterms.pop().unwrap();
|
||||
|
||||
self.terms.push(
|
||||
match is_partial_string(head, tail, &mut self.lexer.machine_st.atom_tbl) {
|
||||
Ok((string_buf, tail_opt)) => {
|
||||
Term::PartialString(Cell::default(), string_buf, tail_opt)
|
||||
match as_partial_string(head, tail) {
|
||||
Ok((string_buf, Some(tail))) => {
|
||||
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,
|
||||
},
|
||||
);
|
||||
|
||||
/*
|
||||
self.terms.push(Term::Cons(
|
||||
Cell::default(),
|
||||
Box::new(head),
|
||||
Box::new(tail),
|
||||
));
|
||||
*/
|
||||
} else {
|
||||
self.terms
|
||||
.push(Term::Clause(Cell::default(), name, subterms));
|
||||
self.terms.push(Term::Clause(Cell::default(), name, subterms));
|
||||
}
|
||||
|
||||
if let Some(&mut TokenDesc {
|
||||
@@ -743,9 +740,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
||||
|
||||
self.terms.push(match list {
|
||||
Term::Cons(_, head, tail) => {
|
||||
match is_partial_string(*head, *tail, &mut self.lexer.machine_st.atom_tbl) {
|
||||
Ok((string_buf, tail_opt)) => {
|
||||
Term::PartialString(Cell::default(), string_buf, tail_opt)
|
||||
match as_partial_string(*head, *tail) {
|
||||
Ok((string_buf, Some(tail))) => {
|
||||
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,
|
||||
}
|
||||
@@ -823,13 +824,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
||||
|
||||
self.reduce_op(1400);
|
||||
|
||||
if self.stack.len() == 1 {
|
||||
if self.stack.len() <= 1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let idx = self.stack.len() - 2;
|
||||
|
||||
let td = self.stack.remove(idx);
|
||||
|
||||
match td.tt {
|
||||
TokenType::Open | TokenType::OpenCT => {
|
||||
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))
|
||||
}
|
||||
Token::Literal(Literal::Float(n)) => self.negate_number(
|
||||
**n,
|
||||
|n| OrderedFloat(-n.into_inner()),
|
||||
|n, arena| Literal::Float(arena_alloc!(n, arena)),
|
||||
**n.as_ptr(),
|
||||
|n| -n,
|
||||
|n, arena| Literal::from(float_alloc!(n, arena)),
|
||||
),
|
||||
Token::Literal(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]
|
||||
pub fn size(&self) -> 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::parser::*;
|
||||
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::iterators::*;
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::machine_state::MachineState;
|
||||
use crate::machine::streams::*;
|
||||
use crate::parser::char_reader::*;
|
||||
use crate::repl_helper::Helper;
|
||||
use crate::types::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::{Cmd, Config, Editor, KeyEvent};
|
||||
use rustyline::{Config, Editor};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::io::{Cursor, Error, ErrorKind, Read};
|
||||
|
||||
type SubtermDeque = VecDeque<(usize, usize)>;
|
||||
|
||||
// pub(crate) type PrologStream = ParsingStream<Stream>;
|
||||
|
||||
impl MachineState {
|
||||
pub(crate) fn devour_whitespace(
|
||||
&mut self,
|
||||
@@ -41,19 +41,21 @@ impl MachineState {
|
||||
&mut self,
|
||||
mut inner: Stream,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
let (term, num_lines_read) = {
|
||||
let prior_num_lines_read = inner.lines_read();
|
||||
let mut parser = Parser::new(inner, self);
|
||||
|
||||
parser.add_lines_read(prior_num_lines_read);
|
||||
|
||||
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
|
||||
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))
|
||||
.map_err(CompilationError::from)?;
|
||||
|
||||
(term, parser.lines_read() - prior_num_lines_read)
|
||||
};
|
||||
|
||||
inner.add_lines_read(num_lines_read);
|
||||
Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl))
|
||||
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)]
|
||||
pub struct ReadlineStream {
|
||||
rl: Editor<()>,
|
||||
rl: Editor<Helper>,
|
||||
pending_input: Cursor<String>,
|
||||
add_history: bool,
|
||||
}
|
||||
|
||||
impl ReadlineStream {
|
||||
#[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 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() {
|
||||
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 {
|
||||
rl,
|
||||
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]
|
||||
pub fn reset(&mut self) {
|
||||
self.pending_input.get_mut().clear();
|
||||
@@ -143,6 +149,9 @@ impl ReadlineStream {
|
||||
}
|
||||
|
||||
fn save_history(&mut self) {
|
||||
if !self.add_history {
|
||||
return;
|
||||
};
|
||||
if let Some(mut path) = dirs_next::home_dir() {
|
||||
path.push(HISTORY_FILE);
|
||||
if path.exists() {
|
||||
@@ -239,7 +248,7 @@ pub(crate) fn write_term_to_heap(
|
||||
term: &Term,
|
||||
heap: &mut Heap,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> TermWriteResult {
|
||||
) -> Result<TermWriteResult, CompilationError> {
|
||||
let term_writer = TermWriter::new(heap, atom_tbl);
|
||||
term_writer.write_term_to_heap(term)
|
||||
}
|
||||
@@ -290,7 +299,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
||||
match term {
|
||||
&TermRef::Cons(..) => list_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() {
|
||||
empty_list_as_cell!()
|
||||
} 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();
|
||||
|
||||
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();
|
||||
}
|
||||
&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 {
|
||||
heap_loc_as_cell!(heap_loc + 1)
|
||||
} else {
|
||||
@@ -335,7 +348,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
@@ -345,9 +358,9 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
||||
|
||||
continue;
|
||||
}
|
||||
&TermRef::Clause(_, _, ref ct, subterms) => {
|
||||
&TermRef::Clause(_, _, name, subterms) => {
|
||||
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);
|
||||
|
||||
@@ -373,14 +386,18 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
||||
|
||||
continue;
|
||||
}
|
||||
&TermRef::PartialString(lvl, _, ref src, tail) => {
|
||||
if tail.is_some() {
|
||||
allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
|
||||
} else {
|
||||
&TermRef::CompleteString(_, _, ref src) => {
|
||||
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();
|
||||
self.queue.push_back((1, h - 1));
|
||||
|
||||
@@ -388,7 +405,6 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
&TermRef::Var(_, _, ref var) => {
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
if let Some(addr) = self.var_dict.get(var).cloned() {
|
||||
@@ -410,9 +426,9 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
||||
self.modify_head_of_queue(&term, h);
|
||||
}
|
||||
|
||||
TermWriteResult {
|
||||
Ok(TermWriteResult {
|
||||
heap_loc,
|
||||
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
|
||||
),
|
||||
E,
|
||||
( write('caught: '), write(E), nl,
|
||||
( loader:write_error(E), nl,
|
||||
portray_clause([N, Settings, Vs, Gs4, Dss]), nl,
|
||||
false
|
||||
)
|
||||
|
||||
@@ -12,15 +12,15 @@ test_queries_on_setup_call_cleanup :-
|
||||
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;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;G=3), writeq(S+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,E], catch(setup_call_cleanup(S=1, (G=2;G=3,throw(x)), writeq(S+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,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;false),writeq(S+G>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]]),
|
||||
catch((setup_call_cleanup(S=1,(G=2;G=3), writeq(S+G>B)), B=4, !, throw(x)), x, true),
|
||||
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), write_term(S+G, [variable_names(['S'=S,'G'=G])])), [[1,2],[1,3]]),
|
||||
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)), 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),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,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),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),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), 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,(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]]).
|
||||
|
||||
@@ -57,6 +57,7 @@ delegate_task([Arg0|Args], Goals0) :-
|
||||
; member(Arg0, ["-v", "--version"]) -> print_version
|
||||
; member(Arg0, ["-g", "--goal"]) -> gather_goal(g, Args, Goals0)
|
||||
; member(Arg0, ["-f"]) -> disable_init_file
|
||||
; member(Arg0, ["--no-add-history"]) -> ignore_machine_arg
|
||||
; atom_chars(Mod, Arg0),
|
||||
catch(consult(Mod), E, print_exception(E))
|
||||
),
|
||||
@@ -74,6 +75,8 @@ print_help :-
|
||||
write('Run the query GOAL'), nl,
|
||||
write(' -f '),
|
||||
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(' '),
|
||||
halt.
|
||||
|
||||
@@ -94,6 +97,8 @@ gather_goal(Type, Args0, Goals) :-
|
||||
disable_init_file :-
|
||||
asserta('disabled_init_file').
|
||||
|
||||
ignore_machine_arg.
|
||||
|
||||
arg_type(g).
|
||||
arg_type(t).
|
||||
arg_type(g(_)).
|
||||
@@ -124,8 +129,8 @@ run_goals([g(Gs0)|Goals]) :-
|
||||
),
|
||||
run_goals(Goals).
|
||||
run_goals([Goal|_]) :-
|
||||
write('caught: '),
|
||||
write(error(domain_error(arg_type, Goal), run_goals/1)), nl,
|
||||
loader:write_error(error(domain_error(arg_type, Goal), run_goals/1)),
|
||||
nl,
|
||||
halt.
|
||||
|
||||
repl :-
|
||||
@@ -175,23 +180,26 @@ submit_query_and_print_results_(Term, VarList) :-
|
||||
'$get_b_value'(B),
|
||||
bb_put('$report_all', false),
|
||||
bb_put('$report_n_more', 0),
|
||||
'$call'(Term),
|
||||
call(user:Term),
|
||||
write_eqs_and_read_input(B, VarList),
|
||||
!.
|
||||
submit_query_and_print_results_(_, _) :-
|
||||
( bb_get('$answer_count', 0) ->
|
||||
write(' ')
|
||||
; true
|
||||
),
|
||||
write('false.'),
|
||||
nl.
|
||||
|
||||
|
||||
submit_query_and_print_results(Term0, VarList) :-
|
||||
( functor(Term0, call, _) ->
|
||||
Term = Term0 % prevent pre-mature expansion of incomplete goal
|
||||
% in the first argument, which is done by call/N
|
||||
; expand_goal(Term0, user, Term)
|
||||
),
|
||||
setup_call_cleanup(bb_put('$first_answer', true),
|
||||
submit_query_and_print_results_(Term, VarList),
|
||||
bb_put('$first_answer', false)).
|
||||
submit_query_and_print_results(Term, VarList) :-
|
||||
% ( functor(Term0, call, _) ->
|
||||
% Term = Term0 % prevent pre-mature expansion of incomplete goal
|
||||
% % in the first argument, which is done by call/N
|
||||
% ; expand_goal(Term0, user, Term)
|
||||
% ),
|
||||
bb_put('$answer_count', 0),
|
||||
submit_query_and_print_results_(Term, VarList).
|
||||
|
||||
|
||||
needs_bracketing(Value, Op) :-
|
||||
@@ -293,14 +301,17 @@ write_eqs_and_read_input(B, VarList) :-
|
||||
append(Equations, AttrGoals, Goals),
|
||||
% one layer of depth added for (=/2) functor
|
||||
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),
|
||||
term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order.
|
||||
charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated),
|
||||
( bb_get('$first_answer', true) ->
|
||||
write(' '),
|
||||
bb_put('$first_answer', false)
|
||||
bb_get('$answer_count', Count),
|
||||
( Count =:= 0 ->
|
||||
write(' ')
|
||||
; true
|
||||
),
|
||||
Count1 is Count + 1,
|
||||
bb_put('$answer_count', Count1),
|
||||
( B0 == B ->
|
||||
( Goals == [] ->
|
||||
write('true.'), nl
|
||||
@@ -344,7 +355,9 @@ read_input(ThreadedGoals, NewVarList) :-
|
||||
bb_put('$report_all', true),
|
||||
nl, write('; '), false
|
||||
; 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
|
||||
; read_input(ThreadedGoals, NewVarList)
|
||||
).
|
||||
@@ -408,8 +421,7 @@ print_exception(E) :-
|
||||
% "^C".
|
||||
; true
|
||||
),
|
||||
write_term('caught: ', [quoted(false), max_depth(20)]),
|
||||
writeq(E),
|
||||
loader:write_error(E),
|
||||
nl.
|
||||
|
||||
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::streams::*;
|
||||
use crate::parser::ast::Fixnum;
|
||||
use crate::parser::rug::{Integer, Rational};
|
||||
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::TryFrom;
|
||||
@@ -18,58 +15,55 @@ use std::ops::{Add, Sub, SubAssign};
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 6]
|
||||
pub enum HeapCellValueTag {
|
||||
// non-constants / tags with adjoining forwarding bits.
|
||||
Cons = 0b00,
|
||||
F64 = 0b01,
|
||||
Str = 0b000010,
|
||||
Lis = 0b000011,
|
||||
Var = 0b000110,
|
||||
StackVar = 0b000111,
|
||||
AttrVar = 0b010011,
|
||||
PStrLoc = 0b111111,
|
||||
PStrOffset = 0b001110,
|
||||
Str = 0b000011,
|
||||
Lis = 0b000101,
|
||||
Var = 0b000111,
|
||||
StackVar = 0b001001,
|
||||
AttrVar = 0b001011,
|
||||
PStrLoc = 0b001101,
|
||||
PStrOffset = 0b001111,
|
||||
// constants.
|
||||
Fixnum = 0b010010,
|
||||
Char = 0b011011,
|
||||
Atom = 0b001010,
|
||||
PStr = 0b001011,
|
||||
CStr = 0b010110, // a complete string.
|
||||
Cons = 0b0,
|
||||
F64 = 0b010001,
|
||||
Fixnum = 0b010011,
|
||||
Char = 0b010101,
|
||||
Atom = 0b010111,
|
||||
PStr = 0b011001,
|
||||
CStr = 0b011011,
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 6]
|
||||
pub enum HeapCellValueView {
|
||||
// non-constants / tags with adjoining forwarding bits.
|
||||
Cons = 0b00,
|
||||
F64 = 0b01,
|
||||
Str = 0b000010,
|
||||
Lis = 0b000011,
|
||||
Var = 0b000110,
|
||||
StackVar = 0b000111,
|
||||
AttrVar = 0b010011,
|
||||
PStrLoc = 0b111111,
|
||||
PStrOffset = 0b001110,
|
||||
Str = 0b000011,
|
||||
Lis = 0b000101,
|
||||
Var = 0b000111,
|
||||
StackVar = 0b001001,
|
||||
AttrVar = 0b001011,
|
||||
PStrLoc = 0b001101,
|
||||
PStrOffset = 0b001111,
|
||||
// constants.
|
||||
Fixnum = 0b010010,
|
||||
Char = 0b011011,
|
||||
Atom = 0b001010,
|
||||
PStr = 0b001011,
|
||||
CStr = 0b010110,
|
||||
Cons = 0b0,
|
||||
F64 = 0b010001,
|
||||
Fixnum = 0b010011,
|
||||
Char = 0b010101,
|
||||
Atom = 0b010111,
|
||||
PStr = 0b011001,
|
||||
CStr = 0b011011,
|
||||
// trail elements.
|
||||
TrailedHeapVar = 0b011110,
|
||||
TrailedHeapVar = 0b011101,
|
||||
TrailedStackVar = 0b011111,
|
||||
TrailedAttrVarHeapLink = 0b101110,
|
||||
TrailedAttrVarListLink = 0b100010,
|
||||
TrailedAttachedValue = 0b101010,
|
||||
TrailedBlackboardEntry = 0b100110,
|
||||
TrailedBlackboardOffset = 0b100111,
|
||||
TrailedAttrVarHeapLink = 0b100001,
|
||||
TrailedAttrVarListLink = 0b100011,
|
||||
TrailedAttachedValue = 0b100101,
|
||||
TrailedBlackboardEntry = 0b100111,
|
||||
TrailedBlackboardOffset = 0b101001,
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 2]
|
||||
#[bits = 1]
|
||||
pub enum ConsPtrMaskTag {
|
||||
Cons = 0b00,
|
||||
F64 = 0b01,
|
||||
Cons = 0b0,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
@@ -77,6 +71,7 @@ pub enum ConsPtrMaskTag {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ConsPtr {
|
||||
ptr: B61,
|
||||
f: bool,
|
||||
m: bool,
|
||||
tag: ConsPtrMaskTag,
|
||||
}
|
||||
@@ -86,22 +81,28 @@ impl ConsPtr {
|
||||
pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self {
|
||||
ConsPtr::new()
|
||||
.with_ptr(ptr as *const u8 as u64)
|
||||
.with_f(false)
|
||||
.with_m(false)
|
||||
.with_tag(tag)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub fn as_ptr(self) -> *mut u8 {
|
||||
self.ptr() as *mut _
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_tag(self) -> ConsPtrMaskTag {
|
||||
self.tag()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
|
||||
#[bits = 6]
|
||||
pub(crate) enum RefTag {
|
||||
HeapCell = 0b0110,
|
||||
StackCell = 0b111,
|
||||
AttrVar = 0b10011,
|
||||
HeapCell = 0b000111,
|
||||
StackCell = 0b001001,
|
||||
AttrVar = 0b001011,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
@@ -244,66 +245,25 @@ pub struct HeapCellValue {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
|
||||
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());
|
||||
|
||||
f.debug_struct("HeapCellValue")
|
||||
.field("tag", &tag)
|
||||
.field("tag", &HeapCellValueTag::Cons)
|
||||
.field("ptr", &cons_ptr.ptr())
|
||||
.field("m", &cons_ptr.m())
|
||||
.field("f", &cons_ptr.f())
|
||||
.finish()
|
||||
}
|
||||
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]
|
||||
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
|
||||
HeapCellValue::from(arena_ptr.header_ptr() as u64)
|
||||
@@ -351,11 +311,9 @@ impl<T> From<TypedArenaPtr<T>> for HeapCellValue {
|
||||
impl From<F64Ptr> for HeapCellValue {
|
||||
#[inline]
|
||||
fn from(f64_ptr: F64Ptr) -> HeapCellValue {
|
||||
HeapCellValue::from_bytes(
|
||||
ConsPtr::from(f64_ptr.as_ptr() as u64)
|
||||
.with_tag(ConsPtrMaskTag::F64)
|
||||
.with_m(false)
|
||||
.into_bytes(),
|
||||
HeapCellValue::build_with(
|
||||
HeapCellValueTag::F64,
|
||||
f64_ptr.as_offset().to_u64(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -375,8 +333,10 @@ impl From<ConsPtr> for HeapCellValue {
|
||||
impl<'a> From<(Number, &mut Arena)> for HeapCellValue {
|
||||
#[inline(always)]
|
||||
fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue {
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
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::Rational(n) => HeapCellValue::from(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]
|
||||
pub fn is_ref(self) -> bool {
|
||||
match self.get_tag() {
|
||||
@@ -486,14 +441,16 @@ impl HeapCellValue {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_compound(self) -> bool {
|
||||
pub fn is_compound(self, heap: &[HeapCellValue]) -> bool {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Str
|
||||
| HeapCellValueTag::Lis
|
||||
| HeapCellValueTag::CStr
|
||||
| HeapCellValueTag::PStr
|
||||
| HeapCellValueTag::PStrLoc
|
||||
| HeapCellValueTag::PStrOffset => {
|
||||
HeapCellValueTag::Str => {
|
||||
cell_as_atom_cell!(heap[self.get_value()]).get_arity() > 0
|
||||
}
|
||||
HeapCellValueTag::Lis |
|
||||
HeapCellValueTag::CStr |
|
||||
HeapCellValueTag::PStr |
|
||||
HeapCellValueTag::PStrLoc |
|
||||
HeapCellValueTag::PStrOffset => {
|
||||
true
|
||||
}
|
||||
HeapCellValueTag::Atom => {
|
||||
@@ -549,7 +506,6 @@ impl HeapCellValue {
|
||||
Ok(tag) => tag,
|
||||
Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
|
||||
ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
|
||||
ConsPtrMaskTag::F64 => HeapCellValueTag::F64,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -588,46 +544,39 @@ impl HeapCellValue {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_forwarding_bit(self) -> Option<bool> {
|
||||
#[inline(always)]
|
||||
pub fn get_forwarding_bit(self) -> bool {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Cons // the list of non-forwardable cell tags.
|
||||
| HeapCellValueTag::F64
|
||||
// | HeapCellValueTag::Atom
|
||||
// | HeapCellValueTag::PStr
|
||||
| HeapCellValueTag::Fixnum
|
||||
| HeapCellValueTag::Char => None,
|
||||
_ => Some(self.f()),
|
||||
HeapCellValueTag::Cons => ConsPtr::from_bytes(self.into_bytes()).f(),
|
||||
_ => self.f()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub fn set_forwarding_bit(&mut self, f: bool) {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Cons // the list of non-forwardable cell tags.
|
||||
| HeapCellValueTag::F64
|
||||
// | HeapCellValueTag::Atom
|
||||
// | HeapCellValueTag::PStr
|
||||
| HeapCellValueTag::Fixnum
|
||||
| HeapCellValueTag::Char => {}
|
||||
HeapCellValueTag::Cons => {
|
||||
let value = ConsPtr::from_bytes(self.into_bytes()).with_f(f);
|
||||
*self = HeapCellValue::from_bytes(value.into_bytes());
|
||||
}
|
||||
_ => self.set_f(f),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub fn get_mark_bit(self) -> bool {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Cons | HeapCellValueTag::F64 => {
|
||||
HeapCellValueTag::Cons => {
|
||||
ConsPtr::from_bytes(self.into_bytes()).m()
|
||||
}
|
||||
_ => self.m(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub fn set_mark_bit(&mut self, m: bool) {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Cons | HeapCellValueTag::F64 => {
|
||||
HeapCellValueTag::Cons => {
|
||||
let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m);
|
||||
*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() {
|
||||
Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
|
||||
Some(TermOrderCategory::Integer)
|
||||
@@ -654,9 +603,19 @@ impl HeapCellValue {
|
||||
})
|
||||
}
|
||||
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc |
|
||||
HeapCellValueTag::CStr | HeapCellValueTag::Str => {
|
||||
HeapCellValueTag::CStr => {
|
||||
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
|
||||
}
|
||||
@@ -681,7 +640,7 @@ const_assert!(mem::size_of::<HeapCellValue>() == 8);
|
||||
|
||||
#[bitfield]
|
||||
#[repr(u64)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct UntypedArenaPtr {
|
||||
ptr: B61,
|
||||
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 {
|
||||
#[inline]
|
||||
fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {
|
||||
|
||||
@@ -65,6 +65,7 @@ pub fn run_top_level_test_with_args<
|
||||
Command::cargo_bin(SCRYER_PROLOG)
|
||||
.unwrap()
|
||||
.arg("-f")
|
||||
.arg("--no-add-history")
|
||||
.args(args)
|
||||
.write_stdin(stdin)
|
||||
.assert()
|
||||
|
||||
@@ -29,12 +29,7 @@ fn do_not_duplicate_path_components() {
|
||||
['tests-pl/issue852-throw_e.pl'].\n\
|
||||
halt.\n\
|
||||
",
|
||||
"\
|
||||
caught: e\n\
|
||||
false.\n\
|
||||
caught: e\n\
|
||||
false.\n\
|
||||
",
|
||||
" throw(e).\n false.\n throw(e).\n false.\n",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -170,6 +165,6 @@ fn ignored_constraint() {
|
||||
fn call_0() {
|
||||
load_module_test(
|
||||
"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() {
|
||||
load_module_test(
|
||||
"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() {
|
||||
load_module_test(
|
||||
"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(
|
||||
&["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