Merge branch 'master' into library-use-case
This commit is contained in:
52
.github/actions/setup-rust/action.yml
vendored
Normal file
52
.github/actions/setup-rust/action.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: 'Setup Rust'
|
||||
inputs:
|
||||
rust-version:
|
||||
required: true
|
||||
type: string
|
||||
targets:
|
||||
required: true
|
||||
type: string
|
||||
components:
|
||||
required: false
|
||||
default:
|
||||
cache-context:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
id: toolchain
|
||||
with:
|
||||
toolchain: ${{ inputs.rust-version }}
|
||||
targets: ${{ inputs.targets }}
|
||||
components: ${{ inputs.components }}
|
||||
|
||||
- name: Install i686 dependencies
|
||||
if: "contains(inputs.targets,'i686')"
|
||||
shell: bash
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install libssl-dev:i386 gcc-multilib clang -y
|
||||
echo "CC=clang" >> $GITHUB_ENV
|
||||
echo "PKG_CONFIG_SYSROOT_DIR=/" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ inputs.cache-context }}_${{ inputs.targets }}_rustc-${{ steps.toolchain.outputs.cachekey }}_cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
# Remove build artifacts for the current crate, since it will be rebuilt every
|
||||
# run anyway, but keep dependency artifacts to cache them.
|
||||
# Must be placed after actions/cache so its post step runs first.
|
||||
- uses: pyTooling/Actions/with-post-step@v0.4.6
|
||||
with:
|
||||
main: bash ./.github/actions/setup-rust/cleanup.sh
|
||||
post: bash ./.github/actions/setup-rust/cleanup.sh
|
||||
13
.github/actions/setup-rust/cleanup.sh
vendored
Executable file
13
.github/actions/setup-rust/cleanup.sh
vendored
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
echo Cleanup workspace build artifacts and extra target output
|
||||
|
||||
# clean just the direct members of the current workspace, use cargo metadata to generalize to all rust projects
|
||||
cargo clean -p `cargo metadata --no-deps --offline --format-version 1 | jq -r '[.workspace_members[]|split(" ")|.[0]]|join(" ")'`
|
||||
|
||||
# remove directories in /target/ that are not named `debug` or `release`
|
||||
before=`du -s target | awk '{print $1}'`
|
||||
find ./target -maxdepth 1 -type d ! -name debug ! -name release ! -name target -exec rm -r {} \;
|
||||
after=`du -s target | awk '{print $1}'`
|
||||
echo Deleted $(($before - $after)) bytes from target directory
|
||||
109
.github/workflows/ci.yml
vendored
109
.github/workflows/ci.yml
vendored
@@ -10,47 +10,26 @@ on:
|
||||
- cron: '0 0 * * 3' # At 12:00 AM, only on Wednesday
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
style:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
id: toolchain
|
||||
- name: Setup Rust
|
||||
uses: ./.github/actions/setup-rust
|
||||
with:
|
||||
toolchain: nightly
|
||||
rust-version: nightly
|
||||
targets: x86_64-unknown-linux-gnu
|
||||
components: clippy, rustfmt
|
||||
- run: cargo install cargo2junit --force
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: style_rustc-${{ steps.toolchain.outputs.cachekey }}_cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
cache-context: style
|
||||
|
||||
- name: Check formatting
|
||||
run: cargo fmt --check
|
||||
- name: Check clippy
|
||||
run: cargo clippy --no-deps --all-targets
|
||||
- name: Test and report
|
||||
run: |
|
||||
RUSTC_BOOTSTRAP=1 cargo test --all -- -Z unstable-options --format json --report-time | cargo2junit > cargo_test_results.xml
|
||||
- name: Publish cargo test results artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cargo-test-results
|
||||
path: cargo_test_results.xml
|
||||
- name: Publish cargo test summary
|
||||
uses: EnricoMi/publish-unit-test-result-action/composite@master
|
||||
with:
|
||||
check_name: Cargo test summary
|
||||
files: cargo_test_results.xml
|
||||
fail_on: nothing
|
||||
comment_mode: off
|
||||
|
||||
build-test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -75,34 +54,19 @@ jobs:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
id: toolchain
|
||||
- name: Setup Rust
|
||||
uses: ./.github/actions/setup-rust
|
||||
with:
|
||||
toolchain: ${{ matrix.rust-version }}
|
||||
rust-version: ${{ matrix.rust-version }}
|
||||
targets: ${{ matrix.target }}
|
||||
- name: Install i686 dependencies
|
||||
if: "contains(matrix.target,'i686')"
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install libssl-dev:i386 gcc-multilib clang -y
|
||||
echo "CC=clang" >> $GITHUB_ENV
|
||||
echo "PKG_CONFIG_SYSROOT_DIR=/" >> $GITHUB_ENV
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ matrix.os }}_${{ matrix.target }}_rustc-${{ steps.toolchain.outputs.cachekey }}_cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
cache-context: ${{ matrix.os }}
|
||||
|
||||
# Build and test.
|
||||
- name: Build library
|
||||
run: cargo rustc --lib --target ${{ matrix.target }} ${{ matrix.args }} --verbose
|
||||
- name: Test
|
||||
run: cargo test --target ${{ matrix.target }} ${{ matrix.args }} --all --verbose || echo "::warning ::Tests failed"
|
||||
continue-on-error: ${{ contains(matrix.target,'wasm32') }} # allow wasm builds to fail tests for now
|
||||
run: cargo test --target ${{ matrix.target }} ${{ matrix.args }} --all --verbose
|
||||
|
||||
# On stable rust builds, build a binary and publish as a github actions
|
||||
# artifact. These binaries could be useful for testing the pipeline but
|
||||
@@ -166,6 +130,53 @@ jobs:
|
||||
fail_on: nothing
|
||||
comment_mode: off
|
||||
|
||||
report:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Rust
|
||||
uses: ./.github/actions/setup-rust
|
||||
with:
|
||||
rust-version: nightly
|
||||
targets: x86_64-unknown-linux-gnu
|
||||
cache-context: report
|
||||
- run: |
|
||||
cargo install cargo2junit --force
|
||||
# cargo install iai-callgrind-runner --force --version `cargo metadata --format-version 1 | jq -r '.resolve.nodes[].id|split(" ")|select(.[0]=="iai-callgrind")|.[1]'`
|
||||
cargo install iai-callgrind-runner --force --git https://github.com/iai-callgrind/iai-callgrind --rev c77bc3c83d7f4e976cc42d4597236a8db259e772
|
||||
sudo apt install valgrind -y
|
||||
|
||||
- name: Test and report
|
||||
run: |
|
||||
RUSTC_BOOTSTRAP=1 cargo test --all -- -Z unstable-options --format json --report-time | cargo2junit > cargo_test_results.xml
|
||||
- name: Publish cargo test results artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cargo-test-results
|
||||
path: cargo_test_results.xml
|
||||
- name: Publish cargo test summary
|
||||
uses: EnricoMi/publish-unit-test-result-action/composite@master
|
||||
with:
|
||||
check_name: Cargo test summary
|
||||
files: cargo_test_results.xml
|
||||
fail_on: nothing
|
||||
comment_mode: off
|
||||
|
||||
- run: cargo build --all-targets --release
|
||||
- run: cargo test --bench setup --release
|
||||
- run: cargo bench --bench run_iai -- --save-summary=json
|
||||
- run: cargo bench --bench run_criterion
|
||||
- run: cargo bench --bench run_criterion -- --profile-time 60
|
||||
|
||||
- name: Publish benchmark results
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: benchmark-results
|
||||
path: |
|
||||
target/criterion/*
|
||||
target/iai/*
|
||||
target/benchmark_inference_counts.json
|
||||
|
||||
# Publish binaries when building for a tag
|
||||
release:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
541
Cargo.lock
generated
541
Cargo.lock
generated
@@ -17,6 +17,19 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.2"
|
||||
@@ -41,12 +54,30 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anes"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "1.0.8"
|
||||
@@ -100,6 +131,15 @@ version = "0.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.3"
|
||||
@@ -213,6 +253,12 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
@@ -225,6 +271,12 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
@@ -254,6 +306,58 @@ dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"ciborium-ll",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-io"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-ll"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"half",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
version = "4.5.0"
|
||||
@@ -275,16 +379,6 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_log"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f"
|
||||
dependencies = [
|
||||
"log",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
@@ -301,6 +395,15 @@ version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "cpp_demangle"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpu-time"
|
||||
version = "1.0.0"
|
||||
@@ -320,6 +423,75 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
|
||||
dependencies = [
|
||||
"anes",
|
||||
"cast",
|
||||
"ciborium",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"is-terminal",
|
||||
"itertools",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"oorandom",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.20.0"
|
||||
@@ -472,6 +644,15 @@ dependencies = [
|
||||
"num-order",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "debugid"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
|
||||
dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_deref"
|
||||
version = "1.1.1"
|
||||
@@ -563,6 +744,12 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.3"
|
||||
@@ -611,6 +798,18 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "findshlibs"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@@ -827,13 +1026,19 @@ dependencies = [
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
@@ -990,6 +1195,35 @@ dependencies = [
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iai-callgrind"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/iai-callgrind/iai-callgrind.git?rev=c77bc3c83d7f4e976cc42d4597236a8db259e772#c77bc3c83d7f4e976cc42d4597236a8db259e772"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"iai-callgrind-macros",
|
||||
"iai-callgrind-runner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iai-callgrind-macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/iai-callgrind/iai-callgrind.git?rev=c77bc3c83d7f4e976cc42d4597236a8db259e772#c77bc3c83d7f4e976cc42d4597236a8db259e772"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.37",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iai-callgrind-runner"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/iai-callgrind/iai-callgrind.git?rev=c77bc3c83d7f4e976cc42d4597236a8db259e772#c77bc3c83d7f4e976cc42d4597236a8db259e772"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.57"
|
||||
@@ -1033,6 +1267,34 @@ dependencies = [
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad227c3af19d4914570ad36d30409928b75967c298feb9ea1969db3a610bb14e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inferno"
|
||||
version = "0.11.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c50453ec3a6555fad17b1cd1a80d16af5bc7cb35094f64e429fd46549018c6a3"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"indexmap 2.0.1",
|
||||
"is-terminal",
|
||||
"itoa",
|
||||
"log",
|
||||
"num-format",
|
||||
"once_cell",
|
||||
"quick-xml",
|
||||
"rgb",
|
||||
"str_stack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
@@ -1048,6 +1310,17 @@ version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
@@ -1103,7 +1376,7 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"arrayvec 0.5.2",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"ryu",
|
||||
@@ -1147,9 +1420,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.7"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
|
||||
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -1217,6 +1490,24 @@ version = "2.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
@@ -1376,6 +1667,16 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-format"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
|
||||
dependencies = [
|
||||
"arrayvec 0.7.4",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-modular"
|
||||
version = "0.6.1"
|
||||
@@ -1393,9 +1694,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.16"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
|
||||
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
@@ -1425,6 +1726,12 @@ version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
@@ -1433,9 +1740,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.57"
|
||||
version = "0.10.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
|
||||
checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"cfg-if",
|
||||
@@ -1465,9 +1772,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.93"
|
||||
version = "0.9.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d"
|
||||
checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -1658,6 +1965,56 @@ version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"plotters-backend",
|
||||
"plotters-svg",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters-backend"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
|
||||
|
||||
[[package]]
|
||||
name = "plotters-svg"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
|
||||
dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pprof"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef5c97c51bd34c7e742402e216abdeb44d415fbe6ae41d56b114723e953711cb"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"cfg-if",
|
||||
"criterion",
|
||||
"findshlibs",
|
||||
"inferno",
|
||||
"libc",
|
||||
"log",
|
||||
"nix 0.26.4",
|
||||
"once_cell",
|
||||
"parking_lot 0.12.1",
|
||||
"smallvec",
|
||||
"symbolic-demangle",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
@@ -1697,6 +2054,30 @@ dependencies = [
|
||||
"termtree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.20+deprecated"
|
||||
@@ -1712,6 +2093,15 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
@@ -1767,6 +2157,26 @@ dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
@@ -1874,6 +2284,15 @@ dependencies = [
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
@@ -1933,9 +2352,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.14"
|
||||
version = "0.38.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f"
|
||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"errno",
|
||||
@@ -2042,8 +2461,8 @@ dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
"cpu-time",
|
||||
"criterion",
|
||||
"crossterm",
|
||||
"crrl",
|
||||
"ctrlc",
|
||||
@@ -2056,7 +2475,9 @@ dependencies = [
|
||||
"getrandom",
|
||||
"git-version",
|
||||
"hostname",
|
||||
"indexmap",
|
||||
"iai-callgrind",
|
||||
"indexmap 1.9.3",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"lexical",
|
||||
"libc",
|
||||
@@ -2068,6 +2489,7 @@ dependencies = [
|
||||
"num-order",
|
||||
"ordered-float",
|
||||
"phf 0.9.0",
|
||||
"pprof",
|
||||
"predicates-core",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2351,6 +2773,12 @@ version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
@@ -2363,6 +2791,12 @@ version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
|
||||
|
||||
[[package]]
|
||||
name = "str_stack"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb"
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.7"
|
||||
@@ -2420,6 +2854,29 @@ version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||
|
||||
[[package]]
|
||||
name = "symbolic-common"
|
||||
version = "12.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "405af7bd5edd866cef462e22ef73f11cf9bf506c9d62824fef8364eb69d4d4ad"
|
||||
dependencies = [
|
||||
"debugid",
|
||||
"memmap2",
|
||||
"stable_deref_trait",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symbolic-demangle"
|
||||
version = "12.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bcd041ccfb77d9c70639efcd5b804b508ac7a273e9224d227379e225625daf9"
|
||||
dependencies = [
|
||||
"cpp_demangle",
|
||||
"rustc-demangle",
|
||||
"symbolic-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
@@ -2498,6 +2955,16 @@ dependencies = [
|
||||
"syn 2.0.37",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
@@ -2751,6 +3218,12 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
@@ -3056,3 +3529,23 @@ name = "xmlparser"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.37",
|
||||
]
|
||||
|
||||
39
Cargo.toml
39
Cargo.toml
@@ -85,19 +85,21 @@ tokio = { version = "1.28.2", features = ["full"] }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
getrandom = { version = "0.2.10", features = ["js"] }
|
||||
tokio = { version = "1.28.2", features = ["sync", "macros", "io-util", "rt", "time"] }
|
||||
tokio = { version = "1.28.2", features = [
|
||||
"sync",
|
||||
"macros",
|
||||
"io-util",
|
||||
"rt",
|
||||
"time",
|
||||
] }
|
||||
|
||||
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "1.0"
|
||||
wasm-bindgen = "0.2.87"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
serde-wasm-bindgen = "0.5"
|
||||
web-sys = { version = "0.3", features = [
|
||||
"Document",
|
||||
"Window",
|
||||
"Element",
|
||||
]}
|
||||
web-sys = { version = "0.3", features = ["Document", "Window", "Element", "Performance"] }
|
||||
js-sys = "0.3"
|
||||
|
||||
[target.'cfg(target_os = "wasi")'.dependencies]
|
||||
ring-wasi = { version = "0.16.25" }
|
||||
@@ -110,6 +112,27 @@ assert_cmd = "1.0.3"
|
||||
predicates-core = "1.0.2"
|
||||
maplit = "1.0.2"
|
||||
serial_test = "2.0.0"
|
||||
iai-callgrind = { git = "https://github.com/iai-callgrind/iai-callgrind.git", rev = "c77bc3c83d7f4e976cc42d4597236a8db259e772" }
|
||||
criterion = "0.5.1"
|
||||
|
||||
[target.'cfg(not(target_os = "windows"))'.dev-dependencies]
|
||||
pprof = { version = "0.13.0", features = ["criterion", "flamegraph"] }
|
||||
|
||||
[patch.crates-io]
|
||||
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" }
|
||||
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" }
|
||||
|
||||
[profile.bench]
|
||||
lto = true
|
||||
opt-level = 3
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 3
|
||||
|
||||
[[bench]]
|
||||
name = "run_criterion"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "run_iai"
|
||||
harness = false
|
||||
|
||||
10
INDEX.dj
10
INDEX.dj
@@ -5,13 +5,6 @@
|
||||
X = "Scryer Prolog!".
|
||||
```
|
||||
|
||||
``` =html
|
||||
<div style="border: solid #00007f 3px;padding-left: 15px;padding-right: 15px;font-style: italic;background-color: #00007f30;">
|
||||
<h4>Scryer Prolog Meetup 2023</h4>
|
||||
<p>The first annual Scryer Prolog meetup is going to happen in Düsseldorf (Germany) on the 9th and 10th of November 2023. Join us to discover the present and future of Scryer Prolog! Participation is free, registration not required. <a href="https://hsd-pbsa.de/veranstaltung/scryer-prolog-meetup-2023/">More details here.</a></p>
|
||||
</div>
|
||||
```
|
||||
|
||||
{width=128 style=float:right;} [Scryer Prolog](https://github.com/mthom/scryer-prolog) is a free software ISO Prolog system intended to be an industrial
|
||||
strength production environment *and* a testbed for bleeding edge research in
|
||||
logic and constraint programming.
|
||||
@@ -28,6 +21,7 @@ Some of the Scryer Prolog features are:
|
||||
* [Cryptographical predicates](/crypto.html)
|
||||
* [Foreign Function Interface](/ffi.html)
|
||||
* WebAssembly support
|
||||
* Usable as a library
|
||||
* WAM based engine, cross-platform made in Rust
|
||||
* _and more..._
|
||||
|
||||
@@ -80,4 +74,4 @@ an [issue](https://github.com/mthom/scryer-prolog/issues).
|
||||
|
||||
To get in touch with the Scryer Prolog community, participate in
|
||||
[discussions](https://github.com/mthom/scryer-prolog/discussions)
|
||||
or visit our #scryer IRC channel on [Libera](https://libera.chat)!
|
||||
or visit our #scryer IRC channel on [Libera](https://libera.chat)!
|
||||
|
||||
@@ -6,7 +6,10 @@ source industrial strength production environment that is also a
|
||||
testbed for bleeding edge research in logic and constraint
|
||||
programming, which is itself written in a high-level language.
|
||||
|
||||
As of July 2023, **Scryer Prolog passes all [syntactic conformity tests](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing)**.
|
||||
**Scryer Prolog passes all tests** of
|
||||
[syntactic conformity](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing),
|
||||
[`variable_names/1`](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/variable_names) and
|
||||
[`dif/2`](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/dif).
|
||||
|
||||
The homepage of the project is: [**https://www.scryer.pl**](https://www.scryer.pl)
|
||||
|
||||
|
||||
95
benches/README.md
Normal file
95
benches/README.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# About benches
|
||||
|
||||
The `benches` directory contains benchmarks that test scryer-prolog performance.
|
||||
|
||||
Benchmarks are run via two harnesses:
|
||||
|
||||
* `criterion` - criterion performs statistical analysis of benchmark runs and is
|
||||
great for benchmarking locally.
|
||||
* `iai-callgrind` - this runs the benchmark with callgrind, which is able to
|
||||
precisely track the number of instructions executed during the run. This is
|
||||
especially helpful in a public CI runner context where neighboring VMs can
|
||||
cause a very high wall time variance. While instructions executed is only
|
||||
correlated with the desired metric (wall time), this is a good tradeoff for CI
|
||||
where that metric is unreliable.
|
||||
|
||||
Run benchmarks with the following commands:
|
||||
|
||||
```
|
||||
cargo bench --bench run_criterion
|
||||
|
||||
# run a particular criterion benchmark
|
||||
cargo bench --bench run_criterion -- <benchmark_name>
|
||||
|
||||
# run in profiling mode which outputs flamegraphs. Set profile time in seconds:
|
||||
cargo bench --bench run_criterion -- --profile-time <time>
|
||||
|
||||
# to run iai, you need valgrind installed and to install iai-callgrind-runner
|
||||
# at the same version as is in Cargo.toml:
|
||||
cargo install iai-callgrind-runner --version 0.7.3
|
||||
|
||||
cargo bench --bench run_iai
|
||||
```
|
||||
|
||||
For consistency, both runners -- `run_iai.rs` and `run_criterion.rs` -- import
|
||||
the same setup code from `setup.rs`.
|
||||
|
||||
## Setup
|
||||
|
||||
`setup.rs` contains the setup code to run benchmarks. `fn prolog_benches()` at
|
||||
the top of the file is where the benchmarks are defined.
|
||||
|
||||
Benchmarks are organized around running queries against a prolog module file.
|
||||
Before a benchmark starts, `benchmark.setup()` is called which reads the module
|
||||
file and initializes a new `scryer_prolog::machine::Machine`.
|
||||
|
||||
Each benchmark measurement is done by running a query against the machine. In
|
||||
the case of criterion each query is run many times, in the case of iai it's run
|
||||
once.
|
||||
|
||||
## Adding benchmarks
|
||||
|
||||
This design is meant to suppoort defining lots of benchmarks.
|
||||
|
||||
To add a new benchmark:
|
||||
|
||||
* Add a new file `benches/[module].pl` that contains setup prolog code. Import
|
||||
libraries, define predicates, etc.
|
||||
* Add a new section in `setup.rs::prolog_benchmarks()` that refers to to the
|
||||
file and write a query to be benchmarked.
|
||||
* If the query mutates the machine, then use `Strategy::Fresh` so the criterion
|
||||
benchmark will recreate a new machine for each benchmark run, otherwise use
|
||||
`Strategy::Reuse` which has lower overhead. (This is not used by the iai
|
||||
benchmark because it only runs once anyway.)
|
||||
|
||||
Some tips:
|
||||
|
||||
* The goal of benchmarking is to know if a library or engine change improved
|
||||
performance or not.
|
||||
* Once a benchmark is defined and named, avoid changing it's definition. If a
|
||||
benchmark needs to change to be more useful, give the new definition a new
|
||||
name instead. This will prevent charts from showing wild changes in
|
||||
performance just because the definition changed (see previous).
|
||||
* Aim for queries to execute in less than 0.5s realtime. Longer runtimes make it
|
||||
easier for humans to see big differences, but benchmarks either run 10x slower
|
||||
(iai) or execute repeatedly to attain statistical significance (criterion) and
|
||||
in both cases benchmarking queries that take longer than about 0.5s are
|
||||
cumbersome to run.
|
||||
* Consider that the library runtime actually parses the text output of the top
|
||||
level. So don't use custom outputs or it will fail to parse. Also keep the
|
||||
output small so it doesn't just benchmark the ouput parsing code.
|
||||
* DO test the output of the benchmark run, we don't want to count broken
|
||||
benchmarks.
|
||||
|
||||
## CI
|
||||
|
||||
Both benchmark harnesses are run in `.github/workflows/ci.yaml` in the `report`
|
||||
job, and the results are published as build artifacts.
|
||||
|
||||
## Todo
|
||||
|
||||
- [ ] Currently, the execution time to load a module is not benchmarked. It
|
||||
would be nice to have at least one benchmark for loading a module (probably a
|
||||
big one).
|
||||
- [ ] Write a new action that downloads the test and benchmark results
|
||||
artifacts, plots them over time, and publishes a report to github pages.
|
||||
41
benches/csv.pl
Normal file
41
benches/csv.pl
Normal file
File diff suppressed because one or more lines are too long
130
benches/edges.pl
Normal file
130
benches/edges.pl
Normal file
@@ -0,0 +1,130 @@
|
||||
:- use_module(library(clpb)).
|
||||
:- use_module(library(assoc)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(pairs)).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Contiguous United States and DC as they appear in SGB:
|
||||
http://www-cs-faculty.stanford.edu/~uno/sgb.html
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
edge(al, fl).
|
||||
edge(al, ga).
|
||||
edge(al, ms).
|
||||
edge(al, tn).
|
||||
edge(ar, la).
|
||||
edge(ar, mo).
|
||||
edge(ar, ms).
|
||||
edge(ar, ok).
|
||||
edge(ar, tn).
|
||||
edge(ar, tx).
|
||||
edge(az, ca).
|
||||
edge(az, nm).
|
||||
edge(az, nv).
|
||||
edge(az, ut).
|
||||
edge(ca, nv).
|
||||
edge(ca, or).
|
||||
edge(co, ks).
|
||||
edge(co, ne).
|
||||
edge(co, nm).
|
||||
edge(co, ok).
|
||||
edge(co, ut).
|
||||
edge(co, wy).
|
||||
edge(ct, ma).
|
||||
edge(ct, ny).
|
||||
edge(ct, ri).
|
||||
edge(dc, md).
|
||||
edge(dc, va).
|
||||
edge(de, md).
|
||||
edge(de, nj).
|
||||
edge(de, pa).
|
||||
edge(fl, ga).
|
||||
edge(ga, nc).
|
||||
edge(ga, sc).
|
||||
edge(ga, tn).
|
||||
edge(ia, il).
|
||||
edge(ia, mn).
|
||||
edge(ia, mo).
|
||||
edge(ia, ne).
|
||||
edge(ia, sd).
|
||||
edge(ia, wi).
|
||||
edge(id, mt).
|
||||
edge(id, nv).
|
||||
edge(id, or).
|
||||
edge(id, ut).
|
||||
edge(id, wa).
|
||||
edge(id, wy).
|
||||
edge(il, in).
|
||||
edge(il, ky).
|
||||
edge(il, mo).
|
||||
edge(il, wi).
|
||||
edge(in, ky).
|
||||
edge(in, mi).
|
||||
edge(in, oh).
|
||||
edge(ks, mo).
|
||||
edge(ks, ne).
|
||||
edge(ks, ok).
|
||||
edge(ky, mo).
|
||||
edge(ky, oh).
|
||||
edge(ky, tn).
|
||||
edge(ky, va).
|
||||
edge(ky, wv).
|
||||
edge(la, ms).
|
||||
edge(la, tx).
|
||||
edge(ma, nh).
|
||||
edge(ma, ny).
|
||||
edge(ma, ri).
|
||||
edge(ma, vt).
|
||||
edge(md, pa).
|
||||
edge(md, va).
|
||||
edge(md, wv).
|
||||
edge(me, nh).
|
||||
edge(mi, oh).
|
||||
edge(mi, wi).
|
||||
edge(mn, nd).
|
||||
edge(mn, sd).
|
||||
edge(mn, wi).
|
||||
edge(mo, ne).
|
||||
edge(mo, ok).
|
||||
edge(mo, tn).
|
||||
edge(ms, tn).
|
||||
edge(mt, nd).
|
||||
edge(mt, sd).
|
||||
edge(mt, wy).
|
||||
edge(nc, sc).
|
||||
edge(nc, tn).
|
||||
edge(nc, va).
|
||||
edge(nd, sd).
|
||||
edge(ne, sd).
|
||||
edge(ne, wy).
|
||||
edge(nh, vt).
|
||||
edge(nj, ny).
|
||||
edge(nj, pa).
|
||||
edge(nm, ok).
|
||||
edge(nm, tx).
|
||||
edge(nv, or).
|
||||
edge(nv, ut).
|
||||
edge(ny, pa).
|
||||
edge(ny, vt).
|
||||
edge(oh, pa).
|
||||
edge(oh, wv).
|
||||
edge(ok, tx).
|
||||
edge(or, wa).
|
||||
edge(pa, wv).
|
||||
edge(sd, wy).
|
||||
edge(tn, va).
|
||||
edge(ut, wy).
|
||||
edge(va, wv).
|
||||
|
||||
independent_set(G, *(NBs)) :-
|
||||
findall(U-V, (edge(U, V),G@<U), Edges),
|
||||
setof(U, V^(member(U-V, Edges);member(V-U, Edges)), Nodes),
|
||||
pairs_keys_values(Pairs, Nodes, _),
|
||||
list_to_assoc(Pairs, Assoc),
|
||||
maplist(not_both(Assoc), Edges, NBs).
|
||||
|
||||
not_both(Assoc, U-V, ~BU + ~BV) :-
|
||||
get_assoc(U, Assoc, BU),
|
||||
get_assoc(V, Assoc, BV).
|
||||
|
||||
independent_set_count(G, Count) :- independent_set(G, Sat), sat_count(Sat, Count).
|
||||
2
benches/numlist.pl
Normal file
2
benches/numlist.pl
Normal file
@@ -0,0 +1,2 @@
|
||||
:- use_module(library(between)).
|
||||
run_numlist(Upper, Head) :- numlist(1, Upper, L), L = [Head|_].
|
||||
36
benches/run_criterion.rs
Normal file
36
benches/run_criterion.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use pprof::criterion::{Output, PProfProfiler};
|
||||
|
||||
mod setup;
|
||||
|
||||
fn bench_criterion(c: &mut Criterion) {
|
||||
for (&name, bench) in setup::prolog_benches().iter() {
|
||||
match bench.strategy {
|
||||
setup::Strategy::Fresh => c.bench_function(name, |b| {
|
||||
b.iter_batched(|| bench.setup(), |mut r| r(), BatchSize::LargeInput)
|
||||
}),
|
||||
setup::Strategy::Reuse => c.bench_function(name, |b| b.iter(bench.setup())),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn config() -> Criterion {
|
||||
Criterion::default()
|
||||
.sample_size(20)
|
||||
.with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn config() -> Criterion {
|
||||
Criterion::default().sample_size(20)
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
name = benches;
|
||||
config = config();
|
||||
targets = bench_criterion
|
||||
);
|
||||
criterion_main!(benches);
|
||||
18
benches/run_iai.rs
Normal file
18
benches/run_iai.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
|
||||
use scryer_prolog::machine::parsed_results::QueryResolution;
|
||||
|
||||
mod setup;
|
||||
|
||||
#[library_benchmark]
|
||||
#[bench::count_edges(setup::prolog_benches()["count_edges"].setup())]
|
||||
#[bench::numlist(setup::prolog_benches()["numlist"].setup())]
|
||||
#[bench::csv_codename(setup::prolog_benches()["csv_codename"].setup())]
|
||||
fn bench(mut run: impl FnMut() -> QueryResolution) -> QueryResolution {
|
||||
run()
|
||||
}
|
||||
|
||||
library_benchmark_group!(
|
||||
name = benches;
|
||||
benchmarks = bench
|
||||
);
|
||||
main!(library_benchmark_groups = benches);
|
||||
132
benches/setup.rs
Normal file
132
benches/setup.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
use std::{collections::BTreeMap, fs, path::Path};
|
||||
|
||||
use maplit::btreemap;
|
||||
use scryer_prolog::machine::{
|
||||
parsed_results::{QueryResolution, Value},
|
||||
Machine,
|
||||
};
|
||||
|
||||
pub fn prolog_benches() -> BTreeMap<&'static str, PrologBenchmark> {
|
||||
[
|
||||
(
|
||||
"count_edges", // name of the benchmark
|
||||
"benches/edges.pl", // name of the prolog module file to load. use the same file in multiple benchmarks
|
||||
"independent_set_count(ky, Count).", // query to benchmark in the context of the loaded module. consider making the query adjustable to tune the run time to ~0.1s
|
||||
Strategy::Reuse,
|
||||
btreemap! { "Count" => Value::try_from("2869176".to_string()).unwrap() },
|
||||
),
|
||||
(
|
||||
"numlist",
|
||||
"benches/numlist.pl",
|
||||
"run_numlist(1000000, Head).",
|
||||
Strategy::Reuse,
|
||||
btreemap! { "Head" => Value::try_from("1".to_string()).unwrap()},
|
||||
),
|
||||
(
|
||||
"csv_codename",
|
||||
"benches/csv.pl",
|
||||
"get_codename(\"0020\",Name).",
|
||||
Strategy::Reuse,
|
||||
btreemap! { "Name" => Value::try_from("SPACE".to_string()).unwrap()},
|
||||
),
|
||||
]
|
||||
.map(|b| {
|
||||
(
|
||||
b.0,
|
||||
PrologBenchmark {
|
||||
name: b.0,
|
||||
filename: b.1,
|
||||
query: b.2,
|
||||
strategy: b.3,
|
||||
bindings: b.4,
|
||||
},
|
||||
)
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
pub enum Strategy {
|
||||
#[allow(dead_code)]
|
||||
Fresh,
|
||||
Reuse,
|
||||
}
|
||||
|
||||
pub struct PrologBenchmark {
|
||||
pub name: &'static str,
|
||||
pub filename: &'static str,
|
||||
pub query: &'static str,
|
||||
pub strategy: Strategy,
|
||||
pub bindings: BTreeMap<&'static str, Value>,
|
||||
}
|
||||
|
||||
impl PrologBenchmark {
|
||||
pub fn make_machine(&self) -> Machine {
|
||||
let program = fs::read_to_string(self.filename).unwrap();
|
||||
let module_name = Path::new(self.filename)
|
||||
.file_stem()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap();
|
||||
let mut machine = Machine::new_lib();
|
||||
machine.load_module_string(module_name, program);
|
||||
machine
|
||||
}
|
||||
|
||||
pub fn setup(&self) -> impl FnMut() -> QueryResolution {
|
||||
let mut machine = self.make_machine();
|
||||
let query = self.query;
|
||||
move || {
|
||||
use criterion::black_box;
|
||||
black_box(machine.run_query(black_box(query.to_string()))).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
fn validate_benchmarks() {
|
||||
use super::prolog_benches;
|
||||
use scryer_prolog::machine::parsed_results::{QueryMatch, QueryResolution};
|
||||
use std::{fmt::Write, fs};
|
||||
|
||||
struct BenchResult {
|
||||
pub name: &'static str,
|
||||
pub setup_inference_count: u64,
|
||||
pub query_inference_count: u64,
|
||||
}
|
||||
|
||||
let mut results: Vec<BenchResult> = vec![];
|
||||
|
||||
for (_, r) in prolog_benches() {
|
||||
let mut machine = r.make_machine();
|
||||
let setup_inference_count = machine.get_inference_count();
|
||||
|
||||
let result = machine.run_query(r.query.to_string()).unwrap();
|
||||
let query_inference_count = machine.get_inference_count() - setup_inference_count;
|
||||
|
||||
let expected = QueryResolution::Matches(vec![QueryMatch::from(r.bindings.clone())]);
|
||||
assert_eq!(result, expected, "validating benchmark {}", r.name);
|
||||
|
||||
results.push(BenchResult {
|
||||
name: r.name,
|
||||
setup_inference_count,
|
||||
query_inference_count,
|
||||
})
|
||||
}
|
||||
|
||||
let mut json: String = Default::default();
|
||||
json.push('[');
|
||||
for r in results {
|
||||
json.push('\n');
|
||||
write!(
|
||||
json,
|
||||
r#"{{"name":"{}","setup_inference_count":{},"query_inference_count":{}}},"#,
|
||||
r.name, r.setup_inference_count, r.query_inference_count
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
json.pop(); // trailing comma
|
||||
json.push_str("\n]");
|
||||
fs::write("target/benchmark_inference_counts.json", json).expect("Unable to write file");
|
||||
}
|
||||
}
|
||||
@@ -329,6 +329,8 @@ enum SystemClauseType {
|
||||
InstallSCCCleaner,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$install_inference_counter")))]
|
||||
InstallInferenceCounter,
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$inference_count")))]
|
||||
InferenceCount,
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$lh_length")))]
|
||||
LiftedHeapLength,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$load_library_as_stream")))]
|
||||
@@ -573,6 +575,8 @@ enum SystemClauseType {
|
||||
ForeignCall,
|
||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$define_foreign_struct")))]
|
||||
DefineForeignStruct,
|
||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$js_eval")))]
|
||||
JsEval,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$predicate_defined")))]
|
||||
PredicateDefined,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))]
|
||||
@@ -1720,6 +1724,7 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::CallHeadIsDynamic |
|
||||
&Instruction::CallInstallSCCCleaner |
|
||||
&Instruction::CallInstallInferenceCounter |
|
||||
&Instruction::CallInferenceCount |
|
||||
&Instruction::CallLiftedHeapLength |
|
||||
&Instruction::CallLoadLibraryAsStream |
|
||||
&Instruction::CallModuleExists |
|
||||
@@ -1774,6 +1779,7 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::CallLoadForeignLib |
|
||||
&Instruction::CallForeignCall |
|
||||
&Instruction::CallDefineForeignStruct |
|
||||
&Instruction::CallJsEval |
|
||||
&Instruction::CallPredicateDefined |
|
||||
&Instruction::CallStripModule |
|
||||
&Instruction::CallCurrentTime |
|
||||
@@ -1954,6 +1960,7 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::ExecuteHeadIsDynamic |
|
||||
&Instruction::ExecuteInstallSCCCleaner |
|
||||
&Instruction::ExecuteInstallInferenceCounter |
|
||||
&Instruction::ExecuteInferenceCount |
|
||||
&Instruction::ExecuteLiftedHeapLength |
|
||||
&Instruction::ExecuteLoadLibraryAsStream |
|
||||
&Instruction::ExecuteModuleExists |
|
||||
@@ -2008,6 +2015,7 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::ExecuteLoadForeignLib |
|
||||
&Instruction::ExecuteForeignCall |
|
||||
&Instruction::ExecuteDefineForeignStruct |
|
||||
&Instruction::ExecuteJsEval |
|
||||
&Instruction::ExecutePredicateDefined |
|
||||
&Instruction::ExecuteStripModule |
|
||||
&Instruction::ExecuteCurrentTime |
|
||||
|
||||
491
flamegraph.svg
491
flamegraph.svg
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 4.8 MiB |
@@ -29,7 +29,7 @@ pub(crate) trait Allocator {
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
cell: &Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
r: RegType,
|
||||
@@ -42,7 +42,7 @@ pub(crate) trait Allocator {
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
cell: &Cell<VarReg>,
|
||||
context: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
);
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::parser::ast::*;
|
||||
use crate::targets::*;
|
||||
use crate::temp_v;
|
||||
use crate::types::*;
|
||||
use crate::variable_records::*;
|
||||
|
||||
use crate::instr;
|
||||
use crate::machine::disjuncts::*;
|
||||
@@ -60,6 +61,7 @@ impl BranchCodeStack {
|
||||
marker: &mut DebrayAllocator,
|
||||
) -> SubsumedBranchHits {
|
||||
let mut subsumed_hits = SubsumedBranchHits::with_hasher(FxBuildHasher::default());
|
||||
let mut propagated_var_nums = IndexSet::with_hasher(FxBuildHasher::default());
|
||||
|
||||
for idx in (self.stack.len() - depth..self.stack.len()).rev() {
|
||||
let branch = &mut marker.branch_stack[idx];
|
||||
@@ -85,9 +87,17 @@ impl BranchCodeStack {
|
||||
}
|
||||
}
|
||||
|
||||
if idx > self.stack.len() - depth {
|
||||
propagated_var_nums.insert(var_num);
|
||||
}
|
||||
|
||||
subsumed_hits.insert(var_num);
|
||||
}
|
||||
}
|
||||
|
||||
for var_num in propagated_var_nums.drain(..) {
|
||||
marker.branch_stack[idx - 1].add_branch_occurrence(var_num);
|
||||
}
|
||||
}
|
||||
|
||||
subsumed_hits
|
||||
@@ -277,7 +287,6 @@ impl DebrayAllocator {
|
||||
code: &mut CodeDeque,
|
||||
) -> RegType {
|
||||
self.mark_var::<QueryInstruction>(var_num, Level::Shallow, vr, term_loc, code);
|
||||
|
||||
vr.get().norm()
|
||||
}
|
||||
|
||||
@@ -296,7 +305,14 @@ impl DebrayAllocator {
|
||||
self.mark_var_in_non_callable(var_num, term_loc, vr, code);
|
||||
temp_v!(arg)
|
||||
} else {
|
||||
self.increment_running_count(var_num);
|
||||
if let VarAlloc::Perm(_, PermVarAllocation::Pending) =
|
||||
&self.var_data.records[var_num].allocation
|
||||
{
|
||||
self.mark_var_in_non_callable(var_num, term_loc, vr, code);
|
||||
} else {
|
||||
self.increment_running_count(var_num);
|
||||
}
|
||||
|
||||
RegType::Perm(p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,19 @@ impl BranchOccurrences {
|
||||
subsumed_hits: SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
|
||||
debug_assert!(self.current_branch < self.num_branches);
|
||||
let num_branches = self.num_branches;
|
||||
|
||||
let entry = self
|
||||
.hits
|
||||
.entry(var_num)
|
||||
.or_insert_with(|| BitVec::repeat(false, num_branches));
|
||||
|
||||
entry.set(self.current_branch, true);
|
||||
self.subsumed_hits.insert(var_num);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -92,17 +105,7 @@ impl BranchStack {
|
||||
|
||||
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
|
||||
if let Some(occurrences) = self.last_mut() {
|
||||
debug_assert!(occurrences.current_branch < occurrences.num_branches);
|
||||
|
||||
let num_branches = occurrences.num_branches;
|
||||
|
||||
let entry = occurrences
|
||||
.hits
|
||||
.entry(var_num)
|
||||
.or_insert_with(|| BitVec::repeat(false, num_branches));
|
||||
|
||||
entry.set(occurrences.current_branch, true);
|
||||
occurrences.subsumed_hits.insert(var_num);
|
||||
occurrences.add_branch_occurrence(var_num);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,30 +169,26 @@ impl DebrayAllocator {
|
||||
for var_num in subsumed_hits {
|
||||
match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Perm(_, ref mut allocation) => {
|
||||
match allocation {
|
||||
PermVarAllocation::Done {
|
||||
shallow_safety,
|
||||
deep_safety,
|
||||
..
|
||||
} => {
|
||||
if !self
|
||||
.branch_stack
|
||||
.safety_unneeded_in_branch(shallow_safety, &branch_designator)
|
||||
{
|
||||
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||
branch_occurrences.shallow_safety.insert(var_num);
|
||||
}
|
||||
|
||||
if !self
|
||||
.branch_stack
|
||||
.safety_unneeded_in_branch(deep_safety, &branch_designator)
|
||||
{
|
||||
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||
branch_occurrences.deep_safety.insert(var_num);
|
||||
}
|
||||
if let PermVarAllocation::Done {
|
||||
shallow_safety,
|
||||
deep_safety,
|
||||
..
|
||||
} = allocation
|
||||
{
|
||||
if !self
|
||||
.branch_stack
|
||||
.safety_unneeded_in_branch(shallow_safety, &branch_designator)
|
||||
{
|
||||
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||
branch_occurrences.shallow_safety.insert(var_num);
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
|
||||
if !self
|
||||
.branch_stack
|
||||
.safety_unneeded_in_branch(deep_safety, &branch_designator)
|
||||
{
|
||||
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||
branch_occurrences.deep_safety.insert(var_num);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,7 +739,7 @@ impl Allocator for DebrayAllocator {
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
cell: &Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
) {
|
||||
@@ -748,11 +747,11 @@ impl Allocator for DebrayAllocator {
|
||||
RegType::Temp(0) => {
|
||||
let o = self.alloc_reg_to_var::<Target>(var_num, lvl, term_loc, code);
|
||||
cell.set(VarReg::Norm(RegType::Temp(o)));
|
||||
|
||||
(RegType::Temp(o), true)
|
||||
}
|
||||
RegType::Perm(0) => {
|
||||
let p = self.alloc_perm_var(var_num, term_loc.chunk_num());
|
||||
cell.set(VarReg::Norm(RegType::Perm(p)));
|
||||
(RegType::Perm(p), true)
|
||||
}
|
||||
r @ RegType::Perm(_) => {
|
||||
@@ -780,7 +779,7 @@ impl Allocator for DebrayAllocator {
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
cell: &Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
r: RegType,
|
||||
@@ -846,8 +845,21 @@ impl Allocator for DebrayAllocator {
|
||||
|
||||
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType {
|
||||
match self.get_binding(var_num) {
|
||||
RegType::Perm(0) | RegType::Temp(0) => {
|
||||
RegType::Perm(self.alloc_perm_var(var_num, chunk_num))
|
||||
RegType::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)),
|
||||
RegType::Temp(0) => {
|
||||
let t = self.alloc_reg_to_non_var();
|
||||
|
||||
match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Temp {
|
||||
temp_reg, safety, ..
|
||||
} => {
|
||||
*temp_reg = t;
|
||||
*safety = VarSafetyStatus::GloballyUnneeded;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
RegType::Temp(t)
|
||||
}
|
||||
r => r,
|
||||
}
|
||||
|
||||
21
src/forms.rs
21
src/forms.rs
@@ -744,7 +744,11 @@ impl Number {
|
||||
Number::Float(f) => Number::Float(OrderedFloat(f.signum())),
|
||||
_ => {
|
||||
if self.is_positive() {
|
||||
Number::Fixnum(Fixnum::build_with(1))
|
||||
if self.is_zero() {
|
||||
Number::Fixnum(Fixnum::build_with(0))
|
||||
} else {
|
||||
Number::Fixnum(Fixnum::build_with(1))
|
||||
}
|
||||
} else if self.is_negative() {
|
||||
Number::Fixnum(Fixnum::build_with(-1))
|
||||
} else {
|
||||
@@ -876,7 +880,7 @@ impl ClauseIndexInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub(crate) struct PredicateInfo {
|
||||
pub(crate) is_extensible: bool,
|
||||
pub(crate) is_discontiguous: bool,
|
||||
@@ -885,19 +889,6 @@ pub(crate) struct PredicateInfo {
|
||||
pub(crate) has_clauses: bool,
|
||||
}
|
||||
|
||||
impl Default for PredicateInfo {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
PredicateInfo {
|
||||
is_extensible: false,
|
||||
is_discontiguous: false,
|
||||
is_dynamic: false,
|
||||
is_multifile: false,
|
||||
has_clauses: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PredicateInfo {
|
||||
#[inline]
|
||||
pub(crate) fn compile_incrementally(&self) -> bool {
|
||||
|
||||
@@ -1762,7 +1762,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
while let Some(loc_data) = self.state_stack.pop() {
|
||||
match loc_data {
|
||||
TokenOrRedirect::Atom(atom) => self.print_impromptu_atom(atom),
|
||||
TokenOrRedirect::BarAsOp => append_str!(self, " | "),
|
||||
TokenOrRedirect::BarAsOp => append_str!(self, "|"),
|
||||
TokenOrRedirect::Char(c) => print_char!(self, self.quoted, c),
|
||||
TokenOrRedirect::Op(atom, op) => {
|
||||
self.print_op(&atom.as_str());
|
||||
|
||||
@@ -51,7 +51,8 @@ use wasm_bindgen::prelude::*;
|
||||
#[wasm_bindgen]
|
||||
pub fn eval_code(s: &str) -> String {
|
||||
use machine::mock_wam::*;
|
||||
use web_sys::console;
|
||||
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let mut wam = Machine::with_test_streams();
|
||||
let bytes = wam.test_load_string(s);
|
||||
|
||||
@@ -1173,8 +1173,13 @@ clause(H, B) :-
|
||||
% The clause will be inserted at the beginning of the module.
|
||||
asserta(Clause0) :-
|
||||
loader:strip_subst_module(Clause0, user, Module, Clause),
|
||||
iso_ext:asserta(Module, Clause).
|
||||
asserta_(Module, Clause).
|
||||
|
||||
asserta_(Module, (Head :- Body)) :-
|
||||
!,
|
||||
'$asserta'(Module, Head, Body).
|
||||
asserta_(Module, Fact) :-
|
||||
'$asserta'(Module, Fact, true).
|
||||
|
||||
:- meta_predicate assertz(:).
|
||||
|
||||
@@ -1184,7 +1189,13 @@ asserta(Clause0) :-
|
||||
% The clase will be inserted at the end of the module.
|
||||
assertz(Clause0) :-
|
||||
loader:strip_subst_module(Clause0, user, Module, Clause),
|
||||
iso_ext:assertz(Module, Clause).
|
||||
assertz_(Module, Clause).
|
||||
|
||||
assertz_(Module, (Head :- Body)) :-
|
||||
!,
|
||||
'$assertz'(Module, Head, Body).
|
||||
assertz_(Module, Fact) :-
|
||||
'$assertz'(Module, Fact, true).
|
||||
|
||||
|
||||
:- meta_predicate retract(:).
|
||||
@@ -1203,6 +1214,9 @@ retract(Clause0) :-
|
||||
Body = true,
|
||||
retract_module_clause(Head, Body, Module)
|
||||
; Clause = (Head :- Body) ->
|
||||
( var(Module) -> Module = user
|
||||
; true
|
||||
),
|
||||
retract_module_clause(Head, Body, Module)
|
||||
).
|
||||
|
||||
|
||||
@@ -7968,11 +7968,11 @@ coeff_var_term(C-V, T) :- ( C =:= 1 -> T = #V ; T = C * #V ).
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#=(X, Y, T) :-
|
||||
X #= Y #<==> B,
|
||||
X #= Y #<==> #B,
|
||||
zo_t(B, T).
|
||||
|
||||
#<(X, Y, T) :-
|
||||
X #< Y #<==> B,
|
||||
X #< Y #<==> #B,
|
||||
zo_t(B, T).
|
||||
|
||||
zo_t(0, false).
|
||||
|
||||
@@ -33,11 +33,13 @@ remove_goal([G0|G0s], Goal0, Goals) :-
|
||||
|
||||
vars_remove_goal([], _).
|
||||
vars_remove_goal([Var|Vars], Goal0) :-
|
||||
get_atts(Var, +dif(Goals0)),
|
||||
remove_goal(Goals0, Goal0, Goals),
|
||||
( Goals = [] ->
|
||||
put_atts(Var, -dif(_))
|
||||
; put_atts(Var, +dif(Goals))
|
||||
( get_atts(Var, +dif(Goals0)) ->
|
||||
remove_goal(Goals0, Goal0, Goals),
|
||||
( Goals = [] ->
|
||||
put_atts(Var, -dif(_))
|
||||
; put_atts(Var, +dif(Goals))
|
||||
)
|
||||
; true
|
||||
),
|
||||
vars_remove_goal(Vars, Goal0).
|
||||
|
||||
|
||||
@@ -17,9 +17,7 @@ but they're not part of the ISO Prolog standard at the moment.
|
||||
succ/2,
|
||||
call_nth/2,
|
||||
countall/2,
|
||||
copy_term_nat/2,
|
||||
asserta/2,
|
||||
assertz/2]).
|
||||
copy_term_nat/2]).
|
||||
|
||||
:- use_module(library(error), [can_be/2,
|
||||
domain_error/3,
|
||||
@@ -384,21 +382,3 @@ countall(Goal, N) :-
|
||||
copy_term_nat(Source, Dest) :-
|
||||
'$copy_term_without_attr_vars'(Source, Dest).
|
||||
|
||||
%% asserta(Module, Rule_Fact).
|
||||
%
|
||||
% Similar to `asserta/1` but allows specifying a Module
|
||||
asserta(Module, (Head :- Body)) :-
|
||||
!,
|
||||
'$asserta'(Module, Head, Body).
|
||||
asserta(Module, Fact) :-
|
||||
'$asserta'(Module, Fact, true).
|
||||
|
||||
%% assertz(Module, Rule_Fact).
|
||||
%
|
||||
% Similar to `assertz/1` but allows specifying a Module
|
||||
assertz(Module, (Head :- Body)) :-
|
||||
!,
|
||||
'$assertz'(Module, Head, Body).
|
||||
assertz(Module, Fact) :-
|
||||
'$assertz'(Module, Fact, true).
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
atomic_si/1,
|
||||
list_si/1,
|
||||
character_si/1,
|
||||
term_si/1,
|
||||
chars_si/1,
|
||||
dif_si/2]).
|
||||
|
||||
@@ -68,6 +69,11 @@ character_si(Ch) :-
|
||||
atom(Ch),
|
||||
atom_length(Ch,1).
|
||||
|
||||
term_si(Term) :-
|
||||
( ground(Term) -> acyclic_term(Term)
|
||||
; throw(error(instantiation_error, term_si/1))
|
||||
).
|
||||
|
||||
chars_si(Chs0) :-
|
||||
'$skip_max_list'(_,_, Chs0,Chs),
|
||||
( nonvar(Chs) -> Chs == [] ; true ), % fails for infinite lists too
|
||||
|
||||
@@ -96,7 +96,7 @@ sleep(T) :-
|
||||
:- meta_predicate time(0).
|
||||
|
||||
:- dynamic(time_id/1).
|
||||
:- dynamic(time_state/2).
|
||||
:- dynamic(time_state/3).
|
||||
|
||||
time_next_id(N) :-
|
||||
( retract(time_id(N0)) ->
|
||||
@@ -111,9 +111,9 @@ time_next_id(N) :-
|
||||
% Reports the execution time of Goal.
|
||||
|
||||
time(Goal) :-
|
||||
'$cpu_now'(T0),
|
||||
cputime_inferences(T0, I0),
|
||||
time_next_id(ID),
|
||||
setup_call_cleanup(asserta(time_state(ID, T0)),
|
||||
setup_call_cleanup(asserta(time_state(ID, T0, I0)),
|
||||
( call_cleanup(catch(Goal, E, (report_time(ID),throw(E))),
|
||||
Det = true),
|
||||
time_true(ID),
|
||||
@@ -123,49 +123,72 @@ time(Goal) :-
|
||||
; report_time(ID),
|
||||
false
|
||||
),
|
||||
retract(time_state(ID, _))).
|
||||
retract(time_state(ID, _, _))).
|
||||
|
||||
cputime_inferences(T, I) :-
|
||||
'$cpu_now'(T),
|
||||
'$inference_count'(I).
|
||||
|
||||
time_true(ID) :-
|
||||
report_time(ID).
|
||||
time_true(ID) :-
|
||||
% on backtracking, update the stored CPU time for this ID
|
||||
retract(time_state(ID, _)),
|
||||
'$cpu_now'(T0),
|
||||
asserta(time_state(ID, T0)),
|
||||
retract(time_state(ID, _, _)),
|
||||
cputime_inferences(T0, I0),
|
||||
asserta(time_state(ID, T0, I0)),
|
||||
false.
|
||||
|
||||
report_time(ID) :-
|
||||
time_state(ID, T0),
|
||||
'$cpu_now'(T),
|
||||
time_state(ID, T0, I0),
|
||||
cputime_inferences(T, I),
|
||||
Time is T - T0,
|
||||
Inferences0 is I - I0,
|
||||
% we must subtract the number of inferences that time/1 itself takes;
|
||||
% this may have to be adapted if the implementation changes,
|
||||
% so that (for example) true/1 takes exactly 1 inference.
|
||||
( bb_get('$answer_count', 0) ->
|
||||
Inferences is Inferences0 - 60,
|
||||
Pre = " ", Post = ""
|
||||
; Pre = "", Post = " "
|
||||
; Inferences is Inferences0 - 9,
|
||||
Pre = "", Post = " "
|
||||
),
|
||||
format("~s% CPU time: ~3fs~n~s", [Pre,Time,Post]).
|
||||
phrase((Pre,"% CPU time: ", format_("~3f", [Time]), "s, ",
|
||||
format_("~U", [Inferences])," inference",s_if_necessary(Inferences),"\n",
|
||||
Post), Cs),
|
||||
format("~s", [Cs]).
|
||||
|
||||
s_if_necessary(Inferences) -->
|
||||
{ compare(C, 1, Inferences) },
|
||||
s_(C).
|
||||
|
||||
s_(=) --> "".
|
||||
s_(<) --> "s".
|
||||
s_(>) --> " (exception?)".
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
?- time((true;false)).
|
||||
%@ % CPU time: 0.006s
|
||||
%@ true
|
||||
%@ ; % CPU time: 0.001s
|
||||
%@ false.
|
||||
% CPU time: 0.000s, 1 inference
|
||||
true
|
||||
; % CPU time: 0.000s, 0 inference (exception?)
|
||||
false.
|
||||
|
||||
:- time(use_module(library(clpz))).
|
||||
%@ % CPU time: 3.711s
|
||||
%@ true.
|
||||
% CPU time: 0.343s, 409_874 inferences
|
||||
true.
|
||||
|
||||
:- time(use_module(library(lists))).
|
||||
%@ % CPU time: 0.006s
|
||||
%@ true.
|
||||
% CPU time: 0.000s, 19 inferences
|
||||
true.
|
||||
|
||||
?- time(member(X, "abc")).
|
||||
%@ % CPU time: 0.005s
|
||||
%@ X = a
|
||||
%@ ; % CPU time: 0.000s
|
||||
%@ X = b
|
||||
%@ ; % CPU time: 0.000s
|
||||
%@ X = c
|
||||
%@ ; % CPU time: 0.000s
|
||||
%@ false.
|
||||
% CPU time: 0.000s, 1 inference
|
||||
X = a
|
||||
; % CPU time: 0.000s, 3 inferences
|
||||
X = b
|
||||
; % CPU time: 0.000s, 3 inferences
|
||||
X = c.
|
||||
|
||||
?- time((repeat,false)).
|
||||
% CPU time: 2.726s, 53_330_502 inferences
|
||||
error('$interrupt_thrown',repl/0).
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
29
src/lib/wasm.pl
Normal file
29
src/lib/wasm.pl
Normal file
@@ -0,0 +1,29 @@
|
||||
/** Predicates for the WebAssembly platform
|
||||
|
||||
This module contains predicates that are only available in
|
||||
the WASM (WebAssembly) version of Scryer Prolog.
|
||||
*/
|
||||
|
||||
:- module(wasm, [js_eval/2]).
|
||||
|
||||
:- use_module(library(error)).
|
||||
|
||||
%% js_eval(+JsCode, -Result).
|
||||
%
|
||||
% Executes a JavaScript snippet `JsCode` using the platform
|
||||
% `eval` function. `Result` takes the return value of that code.
|
||||
% Strings, booleans, numbers, null and undefined are directly mapped to Prolog.
|
||||
% Arrays, objects, bigints, symbols and functions are not mapped.
|
||||
% Instead, a `js_{type}` atom will be returned.
|
||||
%
|
||||
% Example (on a browser):
|
||||
%
|
||||
% ```
|
||||
% ?- js_eval("prompt('What is your name?')", Name).
|
||||
% % A prompt is showed, with a textbox.
|
||||
% Name = "Whatever was written on the textbox".
|
||||
% ```
|
||||
js_eval(JsCode, Result) :-
|
||||
must_be(chars, JsCode),
|
||||
can_be(chars, Result),
|
||||
'$js_eval'(JsCode, Result).
|
||||
@@ -348,7 +348,7 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
|
||||
(Number::Fixnum(n1), Number::Integer(n2)) => {
|
||||
let n1_i = n1.get_num();
|
||||
|
||||
if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && n2.is_zero() {
|
||||
if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && n2.is_negative() {
|
||||
let n = Number::Fixnum(n1);
|
||||
Err(numerical_type_error(ValidType::Float, n, stub_gen))
|
||||
} else {
|
||||
@@ -359,7 +359,7 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
|
||||
(Number::Integer(n1), Number::Fixnum(n2)) => {
|
||||
let n2_i = n2.get_num();
|
||||
|
||||
if !(*n1 == Integer::from(1) || n1.is_zero() || *n1 == Integer::from(-1)) && n2_i < 0 {
|
||||
if !(n1.is_one() || n1.is_zero() || n1.num_eq(&-1)) && n2_i < 0 {
|
||||
let n = Number::Integer(n1);
|
||||
Err(numerical_type_error(ValidType::Float, n, stub_gen))
|
||||
} else {
|
||||
@@ -368,9 +368,7 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
|
||||
}
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||
if !(*n1 == Integer::from(1) || n1.is_zero() || *n1 == Integer::from(-1))
|
||||
&& n2.is_zero()
|
||||
{
|
||||
if !(n1.is_one() || n1.is_zero() || n1.num_eq(&-1)) && n2.is_negative() {
|
||||
let n = Number::Integer(n1);
|
||||
Err(numerical_type_error(ValidType::Float, n, stub_gen))
|
||||
} else {
|
||||
@@ -711,11 +709,8 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
|
||||
(Number::Fixnum(n1), Number::Integer(n2)) => {
|
||||
let n1 = Integer::from(n1.get_num());
|
||||
|
||||
match (&*n2).try_into() as Result<u32, _> {
|
||||
Ok(n2) => {
|
||||
let n1: u64 = n1.try_into().unwrap();
|
||||
Ok(Number::arena_from(n1 << n2, arena))
|
||||
}
|
||||
match (&*n2).try_into() as Result<usize, _> {
|
||||
Ok(n2) => Ok(Number::arena_from(n1 << n2, arena)),
|
||||
_ => Ok(Number::arena_from(n1 << usize::max_value(), arena)),
|
||||
}
|
||||
}
|
||||
@@ -726,11 +721,8 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
|
||||
arena,
|
||||
)),
|
||||
},
|
||||
(Number::Integer(n1), Number::Integer(n2)) => match (&*n2).try_into() as Result<u32, _> {
|
||||
Ok(n2) => {
|
||||
let n1: u64 = (&*n1).try_into().unwrap();
|
||||
Ok(Number::arena_from(Integer::from(n1 << n2), arena))
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => match (&*n2).try_into() as Result<usize, _> {
|
||||
Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
|
||||
_ => Ok(Number::arena_from(
|
||||
Integer::from(&*n1 << usize::max_value()),
|
||||
arena,
|
||||
|
||||
@@ -18,6 +18,7 @@ pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
||||
fn store(&self, value: HeapCellValue) -> HeapCellValue;
|
||||
fn deref(&self, value: HeapCellValue) -> HeapCellValue;
|
||||
fn push(&mut self, value: HeapCellValue);
|
||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize);
|
||||
fn stack(&mut self) -> &mut Stack;
|
||||
fn threshold(&self) -> usize;
|
||||
}
|
||||
@@ -73,7 +74,6 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = list_loc_as_cell!(h);
|
||||
self.scan += 1;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -96,14 +96,19 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
|
||||
|
||||
if !cdr.is_var() {
|
||||
// mark addr + 1 as a list back edge in the cdr of the list
|
||||
self.trail_list_cell(addr + 1, threshold);
|
||||
self.target[addr + 1].set_mark_bit(true);
|
||||
self.target[addr + 1].set_forwarding_bit(true);
|
||||
} else {
|
||||
let car = self
|
||||
.target
|
||||
.store(self.target.deref(heap_loc_as_cell!(addr)));
|
||||
|
||||
if !car.is_var() {
|
||||
// mark addr as a list back edge in the car of the list
|
||||
self.trail_list_cell(addr, threshold);
|
||||
self.target[addr].set_mark_bit(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +183,7 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
|
||||
for (threshold, list_loc) in iter {
|
||||
self.target[threshold] = list_loc_as_cell!(self.target.threshold());
|
||||
self.target.push_attr_var_queue(threshold - 1);
|
||||
self.copy_attr_var_list(list_loc);
|
||||
}
|
||||
}
|
||||
@@ -263,6 +269,7 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
}
|
||||
|
||||
fn copy_var(&mut self, addr: HeapCellValue) {
|
||||
let index = addr.get_value() as usize;
|
||||
let rd = self.target.deref(addr);
|
||||
let ra = self.target.store(rd);
|
||||
|
||||
@@ -271,7 +278,20 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = ra;
|
||||
self.scan += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Lis, h) => {
|
||||
if h >= self.old_h && self.target[index].get_mark_bit() {
|
||||
*self.value_at_scan() = heap_loc_as_cell!(
|
||||
if ra.get_forwarding_bit() {
|
||||
h + 1
|
||||
} else {
|
||||
h
|
||||
}
|
||||
);
|
||||
|
||||
self.scan += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -356,12 +376,16 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn unwind_trail(&mut self) {
|
||||
for (r, value) in self.trail.drain(0..) {
|
||||
fn unwind_trail(mut self) {
|
||||
for (r, value) in self.trail {
|
||||
let index = r.get_value() as usize;
|
||||
|
||||
match r.get_tag() {
|
||||
RefTag::AttrVar | RefTag::HeapCell => self.target[index] = value,
|
||||
RefTag::AttrVar | RefTag::HeapCell => {
|
||||
self.target[index] = value;
|
||||
self.target[index].set_mark_bit(false);
|
||||
self.target[index].set_forwarding_bit(false);
|
||||
}
|
||||
RefTag::StackCell => self.target.stack()[index] = value,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,12 +663,16 @@ impl VariableClassifier {
|
||||
state_stack.last(),
|
||||
Some(TraversalState::RemoveBranchNum)
|
||||
) {
|
||||
// check if the second-to-last element is a regular BuildDisjunct, as we don't
|
||||
// want to add GetPrevLevel in case of a TrustMe.
|
||||
matches!(
|
||||
state_stack.iter().rev().nth(1),
|
||||
Some(TraversalState::BuildDisjunct(..))
|
||||
)
|
||||
// check if the second-to-last element
|
||||
// is a regular BuildDisjunct, as we
|
||||
// don't want to add GetPrevLevel in
|
||||
// case of a TrustMe.
|
||||
match state_stack.iter().rev().nth(1) {
|
||||
Some(&TraversalState::BuildDisjunct(preceding_len)) => {
|
||||
preceding_len + 1 == build_stack.len()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ macro_rules! try_or_throw {
|
||||
|
||||
macro_rules! increment_call_count {
|
||||
($s:expr) => {{
|
||||
if !($s.increment_call_count_fn)(&mut $s) {
|
||||
if !$s.increment_call_count() {
|
||||
$s.backtrack();
|
||||
continue;
|
||||
}
|
||||
@@ -208,6 +208,7 @@ impl MachineState {
|
||||
l
|
||||
}
|
||||
(HeapCellValueTag::Fixnum |
|
||||
HeapCellValueTag::CutPoint |
|
||||
HeapCellValueTag::Char |
|
||||
HeapCellValueTag::F64) => {
|
||||
c
|
||||
@@ -3675,6 +3676,16 @@ impl Machine {
|
||||
try_or_throw!(self.machine_st, self.install_inference_counter());
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallInferenceCount => {
|
||||
let global_count = self.machine_st.cwil.global_count.clone();
|
||||
self.inference_count(self.machine_st.registers[1], global_count);
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
}
|
||||
&Instruction::ExecuteInferenceCount => {
|
||||
let global_count = self.machine_st.cwil.global_count.clone();
|
||||
self.inference_count(self.machine_st.registers[1], global_count);
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallLiftedHeapLength => {
|
||||
self.lifted_heap_length();
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
@@ -4128,6 +4139,14 @@ impl Machine {
|
||||
try_or_throw!(self.machine_st, self.define_foreign_struct());
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallJsEval => {
|
||||
try_or_throw!(self.machine_st, self.js_eval());
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
}
|
||||
&Instruction::ExecuteJsEval => {
|
||||
try_or_throw!(self.machine_st, self.js_eval());
|
||||
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);
|
||||
|
||||
@@ -57,10 +57,11 @@ impl Machine {
|
||||
or_frame.prelude.attr_var_queue_len = 0;
|
||||
|
||||
self.machine_st.b = stub_b;
|
||||
self.machine_st.hb = self.machine_st.heap.len();
|
||||
}
|
||||
|
||||
pub fn run_query(&mut self, query: String) -> QueryResult {
|
||||
println!("Query: {}", query);
|
||||
// println!("Query: {}", query);
|
||||
// Parse the query so we can analyze and then call the term
|
||||
let mut parser = Parser::new(
|
||||
Stream::from_owned_string(query, &mut self.machine_st.arena),
|
||||
@@ -87,6 +88,7 @@ impl Machine {
|
||||
.expect("couldn't get code index")
|
||||
.local()
|
||||
.unwrap();
|
||||
self.machine_st.b0 = self.machine_st.b;
|
||||
|
||||
let var_names: IndexMap<_, _> = term_write_result
|
||||
.var_dict
|
||||
@@ -192,7 +194,7 @@ impl Machine {
|
||||
let outputter = printer.print();
|
||||
|
||||
let output: String = outputter.result();
|
||||
println!("Result: {} = {}", var_key.to_string(), output);
|
||||
// println!("Result: {} = {}", var_key.to_string(), output);
|
||||
|
||||
bindings.insert(var_key.to_string(), Value::try_from(output).expect("asdfs"));
|
||||
}
|
||||
@@ -444,10 +446,7 @@ mod tests {
|
||||
}
|
||||
|
||||
// Check if the block is a query
|
||||
if block.starts_with("query") {
|
||||
// Extract the query from the block
|
||||
let query = &block[5..];
|
||||
|
||||
if let Some(query) = block.strip_prefix("query") {
|
||||
i += 1;
|
||||
println!("query #{}: {}", i, query);
|
||||
// Parse and execute the query
|
||||
@@ -457,10 +456,7 @@ mod tests {
|
||||
|
||||
// Print the result
|
||||
println!("{:?}", result);
|
||||
} else if block.starts_with("consult") {
|
||||
// Extract the code from the block
|
||||
let code = &block[7..];
|
||||
|
||||
} else if let Some(code) = block.strip_prefix("consult") {
|
||||
println!("load code: {}", code);
|
||||
|
||||
// Load the code into the machine
|
||||
|
||||
@@ -148,9 +148,10 @@ impl<'a, LS: LoadState<'a>> Drop for Loader<'a, LS> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default)]
|
||||
pub enum CompilationTarget {
|
||||
Module(Atom),
|
||||
#[default]
|
||||
User,
|
||||
}
|
||||
|
||||
@@ -163,13 +164,6 @@ impl fmt::Display for CompilationTarget {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CompilationTarget {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
CompilationTarget::User
|
||||
}
|
||||
}
|
||||
|
||||
impl CompilationTarget {
|
||||
#[inline]
|
||||
pub(crate) fn module_name(&self) -> Atom {
|
||||
|
||||
@@ -492,13 +492,22 @@ impl MachineState {
|
||||
self.permission_error(Permission::Modify, atom!("static_module"), module)
|
||||
}
|
||||
SessionError::ExistenceError(err) => self.existence_error(err),
|
||||
SessionError::ModuleDoesNotContainExport(..) => {
|
||||
let error_atom = atom!("module_does_not_contain_claimed_export");
|
||||
SessionError::ModuleDoesNotContainExport(module_name, key) => {
|
||||
let functor_stub = functor_stub(key.0, key.1);
|
||||
|
||||
let stub = functor!(
|
||||
atom!("module_does_not_contain_claimed_export"),
|
||||
[
|
||||
atom(module_name),
|
||||
str(self.heap.len() + 4, 0)
|
||||
],
|
||||
[functor_stub]
|
||||
);
|
||||
|
||||
self.permission_error(
|
||||
Permission::Access,
|
||||
atom!("private_procedure"),
|
||||
functor!(error_atom),
|
||||
stub,
|
||||
)
|
||||
}
|
||||
SessionError::ModuleCannotImportSelf(module_name) => {
|
||||
|
||||
@@ -96,7 +96,6 @@ pub struct MachineState {
|
||||
pub(crate) unify_fn: fn(&mut MachineState),
|
||||
pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue),
|
||||
pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool,
|
||||
pub(crate) increment_call_count_fn: fn(&mut MachineState) -> bool,
|
||||
}
|
||||
|
||||
impl fmt::Debug for MachineState {
|
||||
@@ -290,6 +289,11 @@ impl<'a> CopierTarget for CopyTerm<'a> {
|
||||
self.state.heap.push(hcv);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
|
||||
self.state.attr_var_init.attr_var_queue.push(attr_var_loc);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn store(&self, value: HeapCellValue) -> HeapCellValue {
|
||||
self.state.store(value)
|
||||
@@ -308,6 +312,7 @@ impl<'a> CopierTarget for CopyTerm<'a> {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct CopyBallTerm<'a> {
|
||||
attr_var_queue: &'a mut Vec<usize>,
|
||||
stack: &'a mut Stack,
|
||||
heap: &'a mut Heap,
|
||||
heap_boundary: usize,
|
||||
@@ -315,10 +320,16 @@ pub(super) struct CopyBallTerm<'a> {
|
||||
}
|
||||
|
||||
impl<'a> CopyBallTerm<'a> {
|
||||
pub(super) fn new(stack: &'a mut Stack, heap: &'a mut Heap, stub: &'a mut Heap) -> Self {
|
||||
pub(super) fn new(
|
||||
attr_var_queue: &'a mut Vec<usize>,
|
||||
stack: &'a mut Stack,
|
||||
heap: &'a mut Heap,
|
||||
stub: &'a mut Heap,
|
||||
) -> Self {
|
||||
let hb = heap.len();
|
||||
|
||||
CopyBallTerm {
|
||||
attr_var_queue,
|
||||
stack,
|
||||
heap,
|
||||
heap_boundary: hb,
|
||||
@@ -360,6 +371,11 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
|
||||
self.stub.push(value);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
|
||||
self.attr_var_queue.push(attr_var_loc);
|
||||
}
|
||||
|
||||
fn store(&self, value: HeapCellValue) -> HeapCellValue {
|
||||
read_heap_cell!(value,
|
||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
|
||||
@@ -417,15 +433,17 @@ impl MachineState {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.cwil.global_count += 1;
|
||||
|
||||
if let Some(&(ref limit, block)) = self.cwil.limits.last() {
|
||||
if self.cwil.count == *limit {
|
||||
if self.cwil.local_count == *limit {
|
||||
self.cwil.inference_limit_exceeded = true;
|
||||
self.block = block;
|
||||
self.unwind_stack();
|
||||
|
||||
return false;
|
||||
} else {
|
||||
self.cwil.count += 1;
|
||||
self.cwil.local_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -967,7 +985,8 @@ impl MachineState {
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CWIL {
|
||||
count: Integer,
|
||||
local_count: Integer,
|
||||
pub(crate) global_count: Integer,
|
||||
limits: Vec<(Integer, usize)>,
|
||||
pub(crate) inference_limit_exceeded: bool,
|
||||
}
|
||||
@@ -975,22 +994,22 @@ pub(crate) struct CWIL {
|
||||
impl CWIL {
|
||||
pub(crate) fn new() -> Self {
|
||||
CWIL {
|
||||
count: Integer::from(0),
|
||||
local_count: Integer::from(0),
|
||||
global_count: Integer::from(0),
|
||||
limits: vec![],
|
||||
inference_limit_exceeded: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_limit(&mut self, limit: usize, block: usize) -> &Integer {
|
||||
let mut limit = Integer::from(limit);
|
||||
limit += &self.count;
|
||||
pub(crate) fn add_limit(&mut self, mut limit: Integer, block: usize) -> &Integer {
|
||||
limit += &self.local_count;
|
||||
|
||||
match self.limits.last() {
|
||||
Some((ref inner_limit, _)) if *inner_limit <= limit => {}
|
||||
_ => self.limits.push((limit, block)),
|
||||
};
|
||||
}
|
||||
|
||||
&self.count
|
||||
&self.local_count
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -1001,12 +1020,12 @@ impl CWIL {
|
||||
}
|
||||
}
|
||||
|
||||
&self.count
|
||||
&self.local_count
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn reset(&mut self) {
|
||||
self.count = Integer::from(0);
|
||||
self.local_count = Integer::from(0);
|
||||
self.limits.clear();
|
||||
self.inference_limit_exceeded = false;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ impl MachineState {
|
||||
unify_fn: MachineState::unify,
|
||||
bind_fn: MachineState::bind,
|
||||
run_cleaners_fn: |_| false,
|
||||
increment_call_count_fn: |_| true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +334,12 @@ impl MachineState {
|
||||
self.ball.boundary = self.heap.len();
|
||||
|
||||
copy_term(
|
||||
CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.ball.stub),
|
||||
CopyBallTerm::new(
|
||||
&mut self.attr_var_init.attr_var_queue,
|
||||
&mut self.stack,
|
||||
&mut self.heap,
|
||||
&mut self.ball.stub,
|
||||
),
|
||||
addr,
|
||||
AttrVarPolicy::DeepCopy,
|
||||
);
|
||||
|
||||
@@ -159,6 +159,14 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
|
||||
self.wam.machine_st.heap.push(val);
|
||||
}
|
||||
|
||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
|
||||
self.wam
|
||||
.machine_st
|
||||
.attr_var_init
|
||||
.attr_var_queue
|
||||
.push(attr_var_loc);
|
||||
}
|
||||
|
||||
fn stack(&mut self) -> &mut Stack {
|
||||
&mut self.wam.machine_st.stack
|
||||
}
|
||||
|
||||
@@ -211,6 +211,15 @@ impl Machine {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_inference_count(&mut self) -> u64 {
|
||||
self.machine_st
|
||||
.cwil
|
||||
.global_count
|
||||
.clone()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
|
||||
let err = self.machine_st.session_error(err);
|
||||
let stub = functor_stub(key.0, key.1);
|
||||
|
||||
@@ -27,6 +27,7 @@ use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
||||
use std::mem;
|
||||
use std::net::{Shutdown, TcpStream};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
@@ -1837,42 +1838,55 @@ impl MachineState {
|
||||
}
|
||||
};
|
||||
|
||||
let file = match open_options.open(&*file_spec.as_str()) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
match err.kind() {
|
||||
ErrorKind::NotFound => {
|
||||
// 8.11.5.3j)
|
||||
let stub = functor_stub(atom!("open"), 4);
|
||||
let mut path = PathBuf::from(&*file_spec.as_str());
|
||||
|
||||
let err =
|
||||
self.existence_error(ExistenceError::SourceSink(self[temp_v!(1)]));
|
||||
loop {
|
||||
let file = match open_options.open(&path) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
match err.kind() {
|
||||
ErrorKind::NotFound => {
|
||||
// 8.11.5.3j)
|
||||
let stub = functor_stub(atom!("open"), 4);
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
let err =
|
||||
self.existence_error(ExistenceError::SourceSink(self[temp_v!(1)]));
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
}
|
||||
ErrorKind::PermissionDenied => {
|
||||
// 8.11.5.3k)
|
||||
return Err(self.open_permission_error(
|
||||
self.registers[1],
|
||||
atom!("open"),
|
||||
4,
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
// assume the OS is out of file descriptors.
|
||||
let stub = functor_stub(atom!("open"), 4);
|
||||
let err = self.resource_error(ResourceError::OutOfFiles);
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
}
|
||||
}
|
||||
ErrorKind::PermissionDenied => {
|
||||
// 8.11.5.3k)
|
||||
return Err(self.open_permission_error(
|
||||
self.registers[1],
|
||||
atom!("open"),
|
||||
4,
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
// assume the OS is out of file descriptors.
|
||||
let stub = functor_stub(atom!("open"), 4);
|
||||
let err = self.resource_error(ResourceError::OutOfFiles);
|
||||
}
|
||||
};
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
if path.extension().is_none() {
|
||||
if let Some(metadata) = file.metadata().ok() {
|
||||
if metadata.is_dir() {
|
||||
path.set_extension("pl");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(if is_input_file {
|
||||
Stream::from_file_as_input(file_spec, file, &mut self.arena)
|
||||
} else {
|
||||
Stream::from_file_as_output(file_spec, file, in_append_mode, &mut self.arena)
|
||||
})
|
||||
return Ok(if is_input_file {
|
||||
Stream::from_file_as_input(file_spec, file, &mut self.arena)
|
||||
} else {
|
||||
Stream::from_file_as_output(file_spec, file, in_append_mode, &mut self.arena)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::parser::*;
|
||||
|
||||
use dashu::integer::Sign;
|
||||
use dashu::integer::UBig;
|
||||
use dashu::integer::{Sign, UBig};
|
||||
use lazy_static::lazy_static;
|
||||
use num_order::NumOrd;
|
||||
|
||||
@@ -828,8 +827,12 @@ impl MachineState {
|
||||
) -> usize {
|
||||
let threshold = self.lifted_heap.len() - lh_offset;
|
||||
|
||||
let mut copy_ball_term =
|
||||
CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.lifted_heap);
|
||||
let mut copy_ball_term = CopyBallTerm::new(
|
||||
&mut self.attr_var_init.attr_var_queue,
|
||||
&mut self.stack,
|
||||
&mut self.heap,
|
||||
&mut self.lifted_heap,
|
||||
);
|
||||
|
||||
copy_ball_term.push(list_loc_as_cell!(threshold + 1));
|
||||
copy_ball_term.push(heap_loc_as_cell!(threshold + 3));
|
||||
@@ -4188,7 +4191,14 @@ impl Machine {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[inline(always)]
|
||||
pub(crate) fn cpu_now(&mut self) {
|
||||
// TODO
|
||||
let millisecs = web_sys::window()
|
||||
.expect("window global object should be available")
|
||||
.performance()
|
||||
.expect("performance property in window should be available")
|
||||
.now();
|
||||
let secs = float_alloc!(millisecs / 1000.0, self.machine_st.arena);
|
||||
|
||||
self.machine_st.unify_f64(secs, self.deref_register(1));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -4879,6 +4889,70 @@ impl Machine {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[inline(always)]
|
||||
pub(crate) fn js_eval(&mut self) -> CallResult {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[inline(always)]
|
||||
pub(crate) fn js_eval(&mut self) -> CallResult {
|
||||
let code = self.deref_register(1);
|
||||
let result_reg = self.deref_register(2);
|
||||
if let Some(code) = self.machine_st.value_to_str_like(code) {
|
||||
match js_sys::eval(&code.as_str()) {
|
||||
Ok(result) => self.unify_js_value(result, result_reg),
|
||||
Err(result) => self.unify_js_value(result, result_reg),
|
||||
};
|
||||
return Ok(());
|
||||
}
|
||||
self.machine_st.fail = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn unify_js_value(&mut self, result: wasm_bindgen::JsValue, result_reg: HeapCellValue) {
|
||||
match result.as_bool() {
|
||||
Some(result) => match result {
|
||||
true => self.machine_st.unify_atom(atom!("true"), result_reg),
|
||||
false => self.machine_st.unify_atom(atom!("false"), result_reg),
|
||||
},
|
||||
None => match result.as_f64() {
|
||||
Some(result) => {
|
||||
let n = float_alloc!(result, self.machine_st.arena);
|
||||
self.machine_st.unify_f64(n, result_reg);
|
||||
}
|
||||
None => match result.as_string() {
|
||||
Some(result) => {
|
||||
let result = AtomTable::build_with(&self.machine_st.atom_tbl, &result);
|
||||
self.machine_st.unify_complete_string(result, result_reg);
|
||||
}
|
||||
None => {
|
||||
if result.is_null() {
|
||||
self.machine_st.unify_atom(atom!("null"), result_reg);
|
||||
} else if result.is_undefined() {
|
||||
self.machine_st.unify_atom(atom!("undefined"), result_reg);
|
||||
} else if result.is_symbol() {
|
||||
self.machine_st.unify_atom(atom!("js_symbol"), result_reg);
|
||||
} else if result.is_object() {
|
||||
self.machine_st.unify_atom(atom!("js_object"), result_reg);
|
||||
} else if result.is_array() {
|
||||
self.machine_st.unify_atom(atom!("js_array"), result_reg);
|
||||
} else if result.is_function() {
|
||||
self.machine_st.unify_atom(atom!("js_function"), result_reg);
|
||||
} else if result.is_bigint() {
|
||||
self.machine_st.unify_atom(atom!("js_bigint"), result_reg);
|
||||
} else {
|
||||
self.machine_st
|
||||
.unify_atom(atom!("js_unknown_type"), result_reg);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn current_time(&mut self) {
|
||||
let timestamp = self.systemtime_to_timestamp(SystemTime::now());
|
||||
@@ -5516,11 +5590,8 @@ impl Machine {
|
||||
let a2 = self.deref_register(2);
|
||||
|
||||
let n = match Number::try_from(a2) {
|
||||
Ok(Number::Fixnum(bp)) => bp.get_num() as usize,
|
||||
Ok(Number::Integer(n)) => {
|
||||
let value: usize = (&*n).try_into().unwrap();
|
||||
value
|
||||
}
|
||||
Ok(Number::Fixnum(bp)) => Integer::from(bp.get_num() as usize),
|
||||
Ok(Number::Integer(n)) => (*n).clone(),
|
||||
_ => {
|
||||
let stub = functor_stub(atom!("call_with_inference_limit"), 3);
|
||||
|
||||
@@ -5531,21 +5602,24 @@ impl Machine {
|
||||
|
||||
let bp = cell_as_fixnum!(a1).get_num() as usize;
|
||||
let a3 = self.deref_register(3);
|
||||
let count = self.machine_st.cwil.add_limit(n, bp);
|
||||
|
||||
let result = count.try_into();
|
||||
if let Ok(value) = result {
|
||||
self.machine_st.unify_fixnum(Fixnum::build_with(value), a3);
|
||||
} else {
|
||||
let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
|
||||
self.machine_st.unify_big_int(count, a3);
|
||||
}
|
||||
|
||||
self.machine_st.increment_call_count_fn = MachineState::increment_call_count;
|
||||
let count = self.machine_st.cwil.add_limit(n, bp).clone();
|
||||
self.inference_count(a3, count);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn inference_count(&mut self, count_var: HeapCellValue, count: Integer) {
|
||||
if let Some(value) = <&Integer as TryInto<i64>>::try_into(&count).ok() {
|
||||
self.machine_st
|
||||
.unify_fixnum(Fixnum::build_with(value), count_var);
|
||||
} else {
|
||||
let count = arena_alloc!(count, &mut self.machine_st.arena);
|
||||
self.machine_st.unify_big_int(count, count_var);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn module_exists(&mut self) {
|
||||
let module = self.deref_register(1);
|
||||
@@ -5671,7 +5745,6 @@ impl Machine {
|
||||
|
||||
if bp == self.machine_st.b && self.machine_st.cwil.is_empty() {
|
||||
self.machine_st.cwil.reset();
|
||||
self.machine_st.increment_call_count_fn = |_| true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6791,6 +6864,7 @@ impl Machine {
|
||||
|
||||
copy_term(
|
||||
CopyBallTerm::new(
|
||||
&mut self.machine_st.attr_var_init.attr_var_queue,
|
||||
&mut self.machine_st.stack,
|
||||
&mut self.machine_st.heap,
|
||||
&mut ball.stub,
|
||||
|
||||
@@ -327,8 +327,9 @@ impl DoubleQuotes {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub enum Unknown {
|
||||
#[default]
|
||||
Error,
|
||||
Fail,
|
||||
Warn,
|
||||
@@ -348,13 +349,6 @@ impl Unknown {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Unknown {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Unknown::Error
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_op_dir() -> OpDir {
|
||||
let mut op_dir = OpDir::with_hasher(FxBuildHasher::default());
|
||||
|
||||
|
||||
@@ -207,6 +207,13 @@ test("scryer-prolog#2056",(
|
||||
\+ E=[]
|
||||
)).
|
||||
|
||||
% https://github.com/mthom/scryer-prolog/issues/2175
|
||||
test("scryer-prolog#2175",(
|
||||
dif(A,B),
|
||||
A=_C*[],
|
||||
A=[]*D*B,D=[]
|
||||
)).
|
||||
|
||||
main :-
|
||||
findall(test(Name, Goal), test(Name, Goal), Tests),
|
||||
run_tests(Tests, Failed),
|
||||
|
||||
@@ -452,4 +452,4 @@ print_exception_with_check(E) :-
|
||||
% is expected to be printed instead.
|
||||
; print_exception(E)
|
||||
).
|
||||
|
||||
|
||||
|
||||
@@ -783,10 +783,10 @@ test_217_181_290_317 :-
|
||||
( op(1105,xfy,'|'),
|
||||
read_from_chars("(a-->b,c|d).", T0),
|
||||
writeq_term_to_chars(T0, C0),
|
||||
C0 == "a-->b,c | d",
|
||||
C0 == "a-->b,c|d",
|
||||
read_from_chars("[(a|b)].", T1),
|
||||
writeq_term_to_chars(T1, C1),
|
||||
C1 == "[(a | b)]",
|
||||
C1 == "[(a|b)]",
|
||||
read_from_chars("[a,(b,c)|[]].", T2),
|
||||
writeq_term_to_chars(T2, C2),
|
||||
C2 == "[a,(b,c)]"
|
||||
|
||||
Reference in New Issue
Block a user