mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 20:28:02 +00:00
Merge remote-tracking branch 'upstream' into annotate-type-signatures
This commit is contained in:
commit
406cc6c5e9
1204 changed files with 34365 additions and 39684 deletions
38
.devcontainer/devcontainer.json
Normal file
38
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/rust
|
||||
{
|
||||
"name": "Rust",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye",
|
||||
|
||||
// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
|
||||
// "mounts": [
|
||||
// {
|
||||
// "source": "devcontainer-cargo-cache-${devcontainerId}",
|
||||
// "target": "/usr/local/cargo",
|
||||
// "type": "volume"
|
||||
// }
|
||||
// ]
|
||||
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
"features": {
|
||||
"ghcr.io/devcontainers-contrib/features/zig:1": {
|
||||
"version": "0.13.0"
|
||||
},
|
||||
"ghcr.io/devcontainers-community/features/llvm:3": {
|
||||
"version": 18
|
||||
}
|
||||
},
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
// "postCreateCommand": "rustc --version",
|
||||
"onCreateCommand": "sudo apt-get update && sudo apt-get install -y pkg-config libz-dev libzstd-dev valgrind"
|
||||
|
||||
// Configure tool-specific properties.
|
||||
// "customizations": {},
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
43
.github/workflows/basic_cli_build_release.yml
vendored
43
.github/workflows/basic_cli_build_release.yml
vendored
|
@ -1,5 +1,5 @@
|
|||
on:
|
||||
# pull_request:
|
||||
# pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
# this cancels workflows currently in progress if you start a new one
|
||||
|
@ -11,7 +11,7 @@ env:
|
|||
# use .tar.gz for quick testing
|
||||
ARCHIVE_FORMAT: .tar.br
|
||||
# Make a new basic-cli git tag and set it here before starting this workflow
|
||||
RELEASE_TAG: 0.16.0
|
||||
RELEASE_TAG: 0.18.0
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
|
@ -96,7 +96,7 @@ jobs:
|
|||
basic-cli/platform/linux-arm64.a
|
||||
|
||||
build-macos-x86_64-files:
|
||||
runs-on: [macos-12] # I expect the generated files to work on macOS 12 and up
|
||||
runs-on: [macos-13] # I expect the generated files to work on macOS 13 and up
|
||||
needs: [prepare]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
@ -104,6 +104,8 @@ jobs:
|
|||
- name: Download the previously uploaded roc_nightly archives
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- run: brew install z3
|
||||
|
||||
- run: ./ci/build_basic_cli.sh macos_x86_64
|
||||
|
||||
- name: Save .a file
|
||||
|
@ -203,15 +205,29 @@ jobs:
|
|||
path: |
|
||||
docs.tar.gz
|
||||
|
||||
test-release-ubuntu:
|
||||
test-release:
|
||||
needs: [create-release-archive]
|
||||
runs-on: [ubuntu-20.04]
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-13, macos-14]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Download the previously uploaded files
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Set OS-specific variables
|
||||
id: vars
|
||||
run: |
|
||||
if [[ "${{ matrix.os }}" =~ ^ubuntu- ]]; then
|
||||
echo "os_pattern=linux_x86_64" >> $GITHUB_OUTPUT
|
||||
elif [ "${{ matrix.os }}" = "macos-13" ]; then
|
||||
echo "os_pattern=macos_x86_64" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "os_pattern=macos_apple_silicon" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: mv roc nightly and simplify name
|
||||
run: mv $(ls -d artifact/* | grep "roc_nightly.*tar\.gz" | grep "linux_x86_64") ./roc_nightly.tar.gz
|
||||
run: mv $(ls -d artifact/* | grep "roc_nightly.*tar\.gz" | grep "${{ steps.vars.outputs.os_pattern }}") ./roc_nightly.tar.gz
|
||||
|
||||
- name: decompress the tar
|
||||
run: tar -xzvf roc_nightly.tar.gz
|
||||
|
@ -231,11 +247,18 @@ jobs:
|
|||
cd basic-cli-platform && ls | grep "tar" | xargs brotli -d
|
||||
ls | grep "tar$" | xargs tar -xf
|
||||
|
||||
- name: Install expect for tests if we dont have it yet
|
||||
run: if ! dpkg -l | grep -qw expect; then sudo apt install -y expect; fi
|
||||
- name: Install dependencies (Ubuntu)
|
||||
if: startsWith(matrix.os, 'ubuntu-')
|
||||
run: |
|
||||
if ! dpkg -l | grep -qw expect; then sudo apt install -y expect; fi
|
||||
if ! dpkg -l | grep -qw ncat; then sudo apt install -y ncat; fi
|
||||
|
||||
- name: Install ncat for tests if we dont have it yet
|
||||
run: if ! dpkg -l | grep -qw ncat; then sudo apt install -y ncat; fi
|
||||
- name: Install dependencies (macOS)
|
||||
if: startsWith(matrix.os, 'macos-')
|
||||
run: |
|
||||
brew install expect
|
||||
brew install nmap # includes ncat
|
||||
brew install z3
|
||||
|
||||
- name: prepare testing
|
||||
run: |
|
||||
|
|
7
.github/workflows/ci_manager.yml
vendored
7
.github/workflows/ci_manager.yml
vendored
|
@ -124,10 +124,10 @@ jobs:
|
|||
if: needs.check-changes.outputs.run_tests == 'full'
|
||||
uses: ./.github/workflows/benchmarks.yml
|
||||
|
||||
start-panic-check:
|
||||
start-fuzzer-tests:
|
||||
needs: check-changes
|
||||
if: needs.check-changes.outputs.run_tests == 'full'
|
||||
uses: ./.github/workflows/improve_panics.yml
|
||||
uses: ./.github/workflows/fuzzer.yml
|
||||
|
||||
ran-full:
|
||||
runs-on: ubuntu-22.04
|
||||
|
@ -141,8 +141,7 @@ jobs:
|
|||
start-ubuntu-x86-64-nix-tests-debug,
|
||||
start-windows-release-build-test,
|
||||
start-windows-tests,
|
||||
start-roc-benchmarks,
|
||||
start-panic-check
|
||||
start-roc-benchmarks
|
||||
]
|
||||
steps:
|
||||
- run: echo "all workflows succeeded!"
|
||||
|
|
20
.github/workflows/fuzzer.yml
vendored
Normal file
20
.github/workflows/fuzzer.yml
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
on:
|
||||
workflow_call:
|
||||
|
||||
name: CI
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
fuzz-test-parser:
|
||||
name: Fuzz test parser (allowed to fail). Do check this if you've made changes to the parser.
|
||||
runs-on: [self-hosted, i7-6700K]
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: run fuzz tests - ok to merge if this one fails # for now!
|
||||
run: |
|
||||
cargo +nightly-2024-02-03 install --locked cargo-fuzz
|
||||
cd crates/compiler/test_syntax/fuzz && cargo +nightly-2024-02-03 fuzz run -j4 fuzz_expr --sanitizer=none -- -dict=dict.txt -max_total_time=60
|
56
.github/workflows/improve_panics.yml
vendored
56
.github/workflows/improve_panics.yml
vendored
|
@ -1,56 +0,0 @@
|
|||
on:
|
||||
workflow_call:
|
||||
|
||||
# Check that the number of panicking function/macro calls has not increased
|
||||
# https://github.com/roc-lang/roc/issues/2046
|
||||
name: Improve panics/unwrap/expect
|
||||
|
||||
jobs:
|
||||
improve-panics:
|
||||
name: improve panics
|
||||
runs-on: [ubuntu-22.04]
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
RUST_BACKTRACE: 1
|
||||
steps:
|
||||
# install nix
|
||||
- uses: cachix/install-nix-action@v23
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: checkout source branch in separate directory
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
clean: true
|
||||
path: source_branch_dir
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- name: checkout target branch in separate directory
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
clean: false
|
||||
path: target_branch_dir
|
||||
ref: ${{ github.base_ref }}
|
||||
|
||||
- name: Compare panics, expects, and unwraps between source and target brach
|
||||
run: |
|
||||
for branch_dir in source_branch_dir target_branch_dir; do
|
||||
cd $branch_dir
|
||||
echo "Calculating violations in &branch_dir..."
|
||||
VIOLATIONS=$(nix develop -c cargo clippy --no-deps -- -W clippy::unwrap_used -W clippy::expect_used -W clippy::panic 2> >(grep -e "warning: \`panic\`" -e "warning: used" -e "warning: usage of" | wc -l ))
|
||||
echo $VIOLATIONS > violations
|
||||
cd ..
|
||||
done
|
||||
|
||||
SOURCE_VIOLATIONS=$(cat source_branch_dir/violations)
|
||||
TARGET_VIOLATIONS=$(cat target_branch_dir/violations)
|
||||
if [ "$SOURCE_VIOLATIONS" -gt "$TARGET_VIOLATIONS" ]; then
|
||||
echo "You added panic/unwrap/expect, in this PR their count increased from $TARGET_VIOLATIONS to $SOURCE_VIOLATIONS."
|
||||
echo "These calls can kill the REPL, try alternative error handling."
|
||||
echo ""
|
||||
echo "TIP: Ask AI \"In rust, how can I rewrite code that contains panic or unwrap so it doesn't crash?\""
|
||||
echo ""
|
||||
echo "If you believe your panic/unwrap/expect is justified, ask Anton-4, rtfeldman or lukewilliamboswell to bypass this workflow failure."
|
||||
exit 1
|
||||
fi
|
4
.github/workflows/macos_x86_64.yml
vendored
4
.github/workflows/macos_x86_64.yml
vendored
|
@ -31,6 +31,4 @@ jobs:
|
|||
run: cargo nextest-gen-llvm --release --no-fail-fast --locked -E "package(test_gen) - test(gen_str::str_append_scalar)"
|
||||
|
||||
- name: regular rust tests
|
||||
run: cargo test --locked --release -- --skip opaque_wrap_function --skip gen_list::bool_list_literal --skip platform_switching_swift --skip swift_ui --skip gen_tags::phantom_polymorphic_record && sccache --show-stats
|
||||
# swift tests are skipped because of "Could not find or use auto-linked library 'swiftCompatibilityConcurrency'" on macos x86_64 CI machine
|
||||
# this issue may be caused by using older versions of XCode
|
||||
run: cargo test --locked --release -- --skip opaque_wrap_function --skip gen_list::bool_list_literal --skip gen_tags::phantom_polymorphic_record && sccache --show-stats
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
on:
|
||||
#pull_request:
|
||||
# pull_request:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 9 * * *"
|
||||
|
|
4
.github/workflows/nightly_macos_x86_64.yml
vendored
4
.github/workflows/nightly_macos_x86_64.yml
vendored
|
@ -27,9 +27,7 @@ jobs:
|
|||
run: ./ci/write_version.sh
|
||||
|
||||
- name: execute rust tests
|
||||
run: cargo test --release --locked -- --skip opaque_wrap_function --skip gen_list::bool_list_literal --skip platform_switching_swift --skip swift_ui --skip gen_tags::phantom_polymorphic_record
|
||||
# swift tests are skipped because of "Could not find or use auto-linked library 'swiftCompatibilityConcurrency'" on macos x86_64 CI machine
|
||||
# this issue may be caused by using older versions of XCode
|
||||
run: cargo test --release --locked -- --skip opaque_wrap_function --skip gen_list::bool_list_literal --skip gen_tags::phantom_polymorphic_record
|
||||
|
||||
- name: build release
|
||||
run: RUSTFLAGS="-C target-cpu=x86-64" cargo build --profile=release-with-lto --locked --bin roc --bin roc_language_server
|
||||
|
|
8
.github/workflows/nix_linux_x86_64.yml
vendored
8
.github/workflows/nix_linux_x86_64.yml
vendored
|
@ -18,22 +18,22 @@ jobs:
|
|||
run: nix-build
|
||||
|
||||
- name: execute tests with --release
|
||||
# skipping glue tests due to difficult multithreading bug, we run them single threaded in the next step
|
||||
# skipping glue tests due to difficult multithreading bug, we run them single threaded in the next step, see #7476
|
||||
run: nix develop -c cargo test --locked --release -- --skip glue_cli_tests
|
||||
|
||||
- name: glue_cli_tests
|
||||
# single threaded due to difficult bug when multithreading
|
||||
# single threaded due to difficult bug when multithreading, see #7476
|
||||
run: nix develop -c cargo test --locked --release glue_cli_tests -- --test-threads=1
|
||||
|
||||
- name: roc test all builtins
|
||||
run: nix develop -c ./ci/roc_test_builtins.sh
|
||||
|
||||
- name: test wasm32 cli_tests
|
||||
# skipping glue tests due to difficult multithreading bug, we run them single threaded in the next step
|
||||
# skipping glue tests due to difficult multithreading bug, we run them single threaded in the next step, see #7476
|
||||
run: nix develop -c cargo test --locked --release --features="wasm32-cli-run" -- --skip glue_cli_tests
|
||||
|
||||
- name: wasm32 glue_cli_tests
|
||||
# single threaded due to difficult bug when multithreading
|
||||
# single threaded due to difficult bug when multithreading, see #7476
|
||||
run: nix develop -c cargo test --locked --release --features="wasm32-cli-run" glue_cli_tests -- --test-threads=1
|
||||
|
||||
- name: test the dev backend # these tests require an explicit feature flag
|
||||
|
|
|
@ -11,6 +11,11 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Update PATH to use zig 13
|
||||
run: echo "PATH=/Users/m1ci/Downloads/zig-macos-aarch64-0.13.0:$PATH" >> $GITHUB_ENV
|
||||
|
||||
- run: zig version
|
||||
|
||||
- name: get the latest release archive
|
||||
run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-macos_apple_silicon-latest.tar.gz
|
||||
|
||||
|
|
5
.github/workflows/test_nightly_many_os.yml
vendored
5
.github/workflows/test_nightly_many_os.yml
vendored
|
@ -1,4 +1,5 @@
|
|||
on:
|
||||
# pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Test latest nightly releases for macOS and Linux x86_64
|
||||
|
@ -18,9 +19,9 @@ jobs:
|
|||
with:
|
||||
version: 0.13.0
|
||||
|
||||
- name: Install zlib on macOS-13
|
||||
- name: Install z3 on macOS-13
|
||||
if: matrix.os == 'macos-13'
|
||||
run: brew install zlib
|
||||
run: brew install z3
|
||||
|
||||
- name: get the latest release archive for linux (x86_64)
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
|
|
8
.github/workflows/ubuntu_x86_64.yml
vendored
8
.github/workflows/ubuntu_x86_64.yml
vendored
|
@ -63,7 +63,7 @@ jobs:
|
|||
- name: test website build script
|
||||
run: bash www/build.sh
|
||||
|
||||
- name: run fuzz tests - ok to merge if this one fails # for now!
|
||||
run: |
|
||||
cargo +nightly-2024-02-03 install --locked cargo-fuzz
|
||||
cd crates/compiler/test_syntax/fuzz && cargo +nightly-2024-02-03 fuzz run -j4 fuzz_expr --sanitizer=none -- -dict=dict.txt -max_total_time=60
|
||||
#- name: run fuzz tests - ok to merge if this one fails # for now!
|
||||
# run: |
|
||||
# cargo +nightly-2024-02-03 install --locked cargo-fuzz
|
||||
# cd crates/compiler/test_syntax/fuzz && cargo +nightly-2024-02-03 fuzz run -j4 fuzz_expr --sanitizer=none -- -dict=dict.txt -max_total_time=60
|
||||
|
|
|
@ -22,6 +22,10 @@ jobs:
|
|||
- name: Check if debug flag files are in sync
|
||||
run: ./ci/check_debug_vars.sh
|
||||
|
||||
# for skipped tests; see #6946, #6947
|
||||
- name: cargo test without --release
|
||||
run: nix develop -c sh -c 'export ROC_CHECK_MONO_IR=1 && cargo test'
|
||||
# skipping glue tests due to difficult multithreading bug, we run them single threaded in the next step, see #7476
|
||||
run: nix develop -c sh -c 'export ROC_CHECK_MONO_IR=1 && cargo test --locked -- --skip glue_cli_tests'
|
||||
|
||||
- name: glue_cli_tests
|
||||
# single threaded due to difficult bug when multithreading, see #7476
|
||||
run: nix develop -c sh -c 'export ROC_CHECK_MONO_IR=1 && cargo test --locked glue_cli_tests -- --test-threads=1'
|
||||
|
|
13
.github/workflows/www.yml
vendored
13
.github/workflows/www.yml
vendored
|
@ -1,21 +1,24 @@
|
|||
name: deploy www.roc-lang.org
|
||||
|
||||
# Whenever a commit lands on `main`, deploy the site
|
||||
on:
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# Whenever a commit lands on `main`, deploy the site
|
||||
push:
|
||||
branches:
|
||||
- deploy-www
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: 'Deploy to Netlify'
|
||||
name: "Deploy to Netlify"
|
||||
runs-on: [self-hosted, linux]
|
||||
steps:
|
||||
- uses: jsmrcaga/action-netlify-deploy@v1.6.0
|
||||
with:
|
||||
install_command: 'pwd; cd ../../www'
|
||||
build_command: 'bash build.sh'
|
||||
build_directory: 'build'
|
||||
install_command: "pwd; cd ../../www"
|
||||
build_command: "bash build.sh"
|
||||
build_directory: "build"
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
NETLIFY_DEPLOY_MESSAGE: "Deploy git ref ${{ github.ref }}"
|
||||
|
|
1
AUTHORS
1
AUTHORS
|
@ -170,3 +170,4 @@ Isak Jones <isak.jones.980@gmail.com>
|
|||
Ch1n3du <danielonyesoh@gmail.com>
|
||||
Elias Mulhall <eli.mulhall@gmail.com>
|
||||
ABuffSeagull <reecevanatta@hey.com>
|
||||
Timon Krebs <timonkrebs@hotmail.com>
|
|
@ -2,6 +2,17 @@
|
|||
|
||||
If you run into any problems getting Roc built from source, please ask for help in the `#beginners` channel on [Roc Zulip](https://roc.zulipchat.com) (the fastest way), or create an issue in this repo!
|
||||
|
||||
## Using Devcontainer
|
||||
|
||||
### Codespaces
|
||||
To access the browser-based editor, you can change the URL of your repository to https://github.dev/roc-lang/roc, replacing github.com with github.dev or go to the roc repo on https://github.com/roc-lang/roc and press . (period key).
|
||||
|
||||
Or use it locally in [VSCode](https://code.visualstudio.com/docs/remote/codespaces)
|
||||
|
||||
### Docker
|
||||
|
||||
Or even run it in your local Docker environment [Developing inside a Container](https://code.visualstudio.com/docs/devcontainers/containers)
|
||||
|
||||
## Using Nix
|
||||
|
||||
On MacOS and Linux, we highly recommend Using [nix](https://nixos.org/download.html) to quickly install all dependencies necessary to build roc.
|
||||
|
@ -111,24 +122,24 @@ sudo apt-get install libz-dev libzstd-dev
|
|||
|
||||
### Zig
|
||||
|
||||
**version: 0.11.0**
|
||||
**version: 0.13.0**
|
||||
|
||||
For any OS, you can use [`zigup`](https://github.com/marler8997/zigup) to manage zig installations.
|
||||
|
||||
If you prefer a package manager, you can try the following:
|
||||
|
||||
- MacOS: `brew install zig@0.11.0`
|
||||
- MacOS: `brew install zig`
|
||||
- Systems with snap (such as Ubuntu): `snap install zig --classic --beta`
|
||||
- Other systems: refer to the [zig documentation](https://github.com/ziglang/zig/wiki/Install-Zig-from-a-Package-Manager)
|
||||
|
||||
If you want to install it manually, you can [download the binary](https://ziglang.org/download/#release-0.11.0) and place it on your PATH.
|
||||
If you want to install it manually, you can [download the binary](https://ziglang.org/download/#release-0.13.0) and place it on your PATH.
|
||||
Apart from the binary, the archive contains a `lib` folder, which needs to be copied next to the binary.
|
||||
|
||||
> WINDOWS NOTE: when you unpack the Zig archive on windows, the result is nested in an extra directory. The instructions on the zig website will seem to not work. So, double-check that the path to zig executable does not include the same directory name twice.
|
||||
|
||||
### LLVM
|
||||
|
||||
**version: 16.0.x**
|
||||
**version: 18.0.x**
|
||||
|
||||
See below for operating system specific installation instructions.
|
||||
|
||||
|
@ -140,7 +151,7 @@ To use the `repl` subcommand, execute `cargo run repl`.
|
|||
|
||||
The default is a developer build. For an optimized build, use:
|
||||
|
||||
```
|
||||
```sh
|
||||
cargo build --release --bin roc
|
||||
```
|
||||
|
||||
|
@ -156,10 +167,10 @@ chmod +x llvm.sh
|
|||
```
|
||||
|
||||
If you use this script, you'll need to add `clang` to your `PATH`.
|
||||
By default, the script installs it as `clang-16`. You can address this with symlinks like so:
|
||||
By default, the script installs it as `clang-18`. You can address this with symlinks like so:
|
||||
|
||||
```sh
|
||||
sudo ln -s /usr/bin/clang-16 /usr/bin/clang
|
||||
sudo ln -s /usr/bin/clang-18 /usr/bin/clang
|
||||
```
|
||||
|
||||
There are also alternative installation options at <http://releases.llvm.org/download.html>
|
||||
|
@ -192,7 +203,7 @@ Add `export LLVM_SYS_180_PREFIX=/usr/lib/llvm-18` to your `~/.bashrc` or equival
|
|||
|
||||
For macOS, you can install LLVM 18 using `brew install llvm@18` and then adding
|
||||
`$(brew --prefix llvm@18)/bin` to your `PATH`. You can confirm this worked by
|
||||
running `llc --version` - it should mention "LLVM version 16.0.x" at the top.
|
||||
running `llc --version` - it should mention "LLVM version 18.x.x" at the top.
|
||||
You may also need to manually specify a prefix env var like so:
|
||||
|
||||
```sh
|
||||
|
@ -250,8 +261,8 @@ Create `~/.cargo/config.toml` if it does not exist and add this to it:
|
|||
rustflags = ["-C", "link-arg=-fuse-ld=lld", "-C", "target-cpu=native"]
|
||||
```
|
||||
|
||||
Then install `lld` version 16 (e.g. with `$ sudo apt-get install lld-16`)
|
||||
Then install `lld` version 18 (e.g. with `$ sudo apt-get install lld-18`)
|
||||
and add make sure there's a `ld.lld` executable on your `PATH` which
|
||||
is symlinked to `lld-16`.
|
||||
is symlinked to `lld-18`.
|
||||
|
||||
That's it! Enjoy the faster builds.
|
||||
|
|
|
@ -68,6 +68,8 @@ programs.gnupg.agent = {
|
|||
<details>
|
||||
<summary>Forgot to sign commits?</summary>
|
||||
|
||||
:exclamation: Make sure [to set up signing on your device](devtools/signing.md) first, then continue below.
|
||||
|
||||
You can view your commits on github, those without the "Verified" badge still need to be signed.
|
||||
If any of those is a merge commit, follow [these steps](https://stackoverflow.com/a/9958215/4200103) instead of the ones below.
|
||||
|
||||
|
|
43
Cargo.lock
generated
43
Cargo.lock
generated
|
@ -216,7 +216,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"object 0.32.2",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
|
@ -724,7 +724,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.3",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
|
@ -932,6 +932,12 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.0"
|
||||
|
@ -1117,6 +1123,15 @@ dependencies = [
|
|||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
|
@ -1302,7 +1317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1719,9 +1734,18 @@ name = "object"
|
|||
version = "0.32.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"hashbrown",
|
||||
"hashbrown 0.15.2",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
]
|
||||
|
@ -2368,7 +2392,6 @@ dependencies = [
|
|||
"bitvec",
|
||||
"bumpalo",
|
||||
"indoc",
|
||||
"insta",
|
||||
"pretty_assertions",
|
||||
"roc_collections",
|
||||
"roc_error_macros",
|
||||
|
@ -2468,7 +2491,7 @@ dependencies = [
|
|||
"bitvec",
|
||||
"bumpalo",
|
||||
"fnv",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.3",
|
||||
"im",
|
||||
"im-rc",
|
||||
"smallvec",
|
||||
|
@ -2598,7 +2621,7 @@ version = "0.0.1"
|
|||
dependencies = [
|
||||
"bumpalo",
|
||||
"capstone",
|
||||
"object",
|
||||
"object 0.36.7",
|
||||
"packed_struct",
|
||||
"roc_builtins",
|
||||
"roc_can",
|
||||
|
@ -2759,7 +2782,7 @@ dependencies = [
|
|||
"libc",
|
||||
"mach_object",
|
||||
"memmap2 0.5.10",
|
||||
"object",
|
||||
"object 0.36.7",
|
||||
"roc_collections",
|
||||
"roc_error_macros",
|
||||
"roc_load",
|
||||
|
@ -2877,7 +2900,7 @@ dependencies = [
|
|||
"arrayvec 0.7.4",
|
||||
"bitvec",
|
||||
"bumpalo",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.3",
|
||||
"indoc",
|
||||
"parking_lot",
|
||||
"roc_builtins",
|
||||
|
@ -3179,7 +3202,7 @@ dependencies = [
|
|||
"arrayvec 0.7.4",
|
||||
"bitvec",
|
||||
"bumpalo",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.3",
|
||||
"indoc",
|
||||
"parking_lot",
|
||||
"pretty_assertions",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"crates/build/specialize_types",
|
||||
"crates/compiler/*",
|
||||
"crates/vendor/*",
|
||||
"crates/fs",
|
||||
|
@ -56,7 +57,7 @@ repository = "https://github.com/roc-lang/roc"
|
|||
version = "0.0.1"
|
||||
|
||||
[workspace.dependencies]
|
||||
object = { version = "0.32.2", default-features = false, features = [
|
||||
object = { version = "0.36.7", default-features = false, features = [
|
||||
"read",
|
||||
"write",
|
||||
] }
|
||||
|
@ -212,7 +213,7 @@ roc_serialize = { path = "crates/compiler/serialize" }
|
|||
roc_solve = { path = "crates/compiler/solve" }
|
||||
roc_solve_schema = { path = "crates/compiler/solve_schema" }
|
||||
roc_solve_problem = { path = "crates/compiler/solve_problem" }
|
||||
roc_specialize_types = { path = "crates/compiler/specialize_types" }
|
||||
roc_specialize_types = { path = "crates/build/specialize_types" }
|
||||
roc_std = { path = "crates/roc_std" }
|
||||
roc_target = { path = "crates/compiler/roc_target" }
|
||||
roc_test_utils = { path = "crates/test_utils" }
|
||||
|
|
14
Earthfile
14
Earthfile
|
@ -16,20 +16,20 @@ install-zig-llvm:
|
|||
ARG ZIG_ARCH
|
||||
FROM +install-other-libs
|
||||
# zig
|
||||
RUN wget -c https://ziglang.org/download/0.11.0/zig-linux-$ZIG_ARCH-0.11.0.tar.xz --no-check-certificate
|
||||
RUN tar -xf zig-linux-$ZIG_ARCH-0.11.0.tar.xz
|
||||
RUN ln -s /earthbuild/zig-linux-$ZIG_ARCH-0.11.0/zig /bin/zig
|
||||
RUN wget -c https://ziglang.org/download/0.13.0/zig-linux-$ZIG_ARCH-0.13.0.tar.xz --no-check-certificate
|
||||
RUN tar -xf zig-linux-$ZIG_ARCH-0.13.0.tar.xz
|
||||
RUN ln -s /earthbuild/zig-linux-$ZIG_ARCH-0.13.0/zig /bin/zig
|
||||
# zig builtins wasm tests
|
||||
RUN apt -y install build-essential
|
||||
# llvm
|
||||
RUN apt -y install lsb-release software-properties-common gnupg
|
||||
RUN wget https://apt.llvm.org/llvm.sh
|
||||
RUN chmod +x llvm.sh
|
||||
RUN ./llvm.sh 16
|
||||
RUN ln -s /usr/bin/clang-16 /usr/bin/clang
|
||||
RUN ./llvm.sh 18
|
||||
RUN ln -s /usr/bin/clang-18 /usr/bin/clang
|
||||
# use lld as linker
|
||||
RUN ln -s /usr/bin/lld-16 /usr/bin/ld.lld
|
||||
RUN apt -y install libpolly-16-dev # required by llvm-sys crate
|
||||
RUN ln -s /usr/bin/lld-18 /usr/bin/ld.lld
|
||||
RUN apt -y install libpolly-18-dev # required by llvm-sys crate
|
||||
ENV RUSTFLAGS="-C link-arg=-fuse-ld=lld -C target-cpu=native"
|
||||
RUN apt -y install libssl-dev
|
||||
RUN wget https://rustwasm.github.io/wasm-pack/installer/init.sh -O init.sh && sh init.sh
|
||||
|
|
|
@ -54,6 +54,6 @@ fi
|
|||
./jump-start.sh
|
||||
|
||||
# build the basic cli platform
|
||||
roc build.roc
|
||||
roc build.roc --linker=legacy
|
||||
|
||||
cd ..
|
||||
|
|
|
@ -7,14 +7,22 @@ set -euxo pipefail
|
|||
strip ./target/release-with-lto/roc
|
||||
strip ./target/release-with-lto/roc_language_server
|
||||
|
||||
mkdir -p $1 $1/examples $1/crates/compiler/builtins/bitcode
|
||||
mkdir -p $1 $1/examples
|
||||
|
||||
mv target/release-with-lto/{roc,roc_language_server,lib} $1
|
||||
mv LICENSE LEGAL_DETAILS $1
|
||||
|
||||
mv examples/{platform-switching,cli} $1/examples
|
||||
mv crates/cli/tests/platform-switching $1/examples
|
||||
mv examples/README.md $1/examples
|
||||
|
||||
mv crates/roc_std $1/crates
|
||||
mv crates/compiler/builtins/bitcode/src $1/crates/compiler/builtins/bitcode
|
||||
# temporary github.com/roc-lang/roc/pull/7231
|
||||
rm $1/examples/platform-switching/rocLovesRust.roc
|
||||
rm -rf $1/examples/platform-switching/rust-platform
|
||||
|
||||
# copy zig builtins
|
||||
if [ ! -d "$1/examples/platform-switching/zig-platform/glue" ]; then
|
||||
mkdir $1/examples/platform-switching/zig-platform/glue
|
||||
mv crates/compiler/builtins/bitcode/src/* $1/examples/platform-switching/zig-platform/glue
|
||||
fi
|
||||
|
||||
tar -czvf "$1.tar.gz" $1
|
||||
|
|
|
@ -8,6 +8,7 @@ mod mono_expr;
|
|||
mod mono_ir;
|
||||
mod mono_module;
|
||||
mod mono_num;
|
||||
mod mono_pattern;
|
||||
mod mono_struct;
|
||||
mod mono_type;
|
||||
// mod specialize_expr;
|
||||
|
@ -16,9 +17,10 @@ mod specialize_type;
|
|||
pub use debug_info::DebugInfo;
|
||||
pub use foreign_symbol::{ForeignSymbolId, ForeignSymbols};
|
||||
pub use mono_expr::Env;
|
||||
pub use mono_ir::{MonoExpr, MonoExprId, MonoExprs};
|
||||
pub use mono_ir::{MonoExpr, MonoExprId, MonoExprs, WhenBranches};
|
||||
pub use mono_module::{InternedStrId, Interns};
|
||||
pub use mono_num::Number;
|
||||
pub use mono_pattern::{MonoPattern, MonoPatternId, MonoPatterns};
|
||||
pub use mono_struct::MonoFieldId;
|
||||
pub use mono_type::{MonoType, MonoTypeId, MonoTypes, Primitive};
|
||||
pub use specialize_type::{MonoTypeCache, Problem, RecordFieldIds, TupleElemIds};
|
|
@ -1,13 +1,16 @@
|
|||
use crate::{
|
||||
mono_ir::{MonoExpr, MonoExprId, MonoExprs},
|
||||
mono_ir::{MonoExpr, MonoExprId, MonoExprs, WhenBranch, WhenBranches},
|
||||
mono_module::Interns,
|
||||
mono_num::Number,
|
||||
mono_type::{MonoType, MonoTypes, Primitive},
|
||||
specialize_type::{MonoTypeCache, Problem, RecordFieldIds, TupleElemIds},
|
||||
DebugInfo, MonoTypeId,
|
||||
DebugInfo, MonoPattern, MonoPatterns, MonoTypeId,
|
||||
};
|
||||
use bumpalo::{collections::Vec, Bump};
|
||||
use roc_can::expr::{Expr, IntValue};
|
||||
use roc_can::{
|
||||
expr::{Expr, IntValue},
|
||||
pattern::Pattern,
|
||||
};
|
||||
use roc_collections::{Push, VecMap};
|
||||
use roc_module::symbol::ModuleId;
|
||||
use roc_region::all::Region;
|
||||
|
@ -44,12 +47,14 @@ impl MonoFnCache {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
||||
pub struct Env<'a, 'c, 'd, 'i, 's, 't, 'p, 'w, P> {
|
||||
arena: &'a Bump,
|
||||
subs: &'s mut Subs,
|
||||
types_cache: &'c mut MonoTypeCache,
|
||||
mono_types: &'t mut MonoTypes,
|
||||
mono_exprs: &'t mut MonoExprs,
|
||||
mono_patterns: &'p mut MonoPatterns,
|
||||
when_branches: &'w mut WhenBranches,
|
||||
record_field_ids: RecordFieldIds,
|
||||
tuple_elem_ids: TupleElemIds,
|
||||
debug_info: &'d mut Option<DebugInfo>,
|
||||
|
@ -57,13 +62,15 @@ pub struct Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
problems: P,
|
||||
}
|
||||
|
||||
impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
||||
impl<'a, 'c, 'd, 'i, 's, 't, 'p, 'w, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, 'p, 'w, P> {
|
||||
pub fn new(
|
||||
arena: &'a Bump,
|
||||
subs: &'s mut Solved<Subs>,
|
||||
types_cache: &'c mut MonoTypeCache,
|
||||
mono_types: &'t mut MonoTypes,
|
||||
mono_exprs: &'t mut MonoExprs,
|
||||
mono_patterns: &'p mut MonoPatterns,
|
||||
when_branches: &'w mut WhenBranches,
|
||||
record_field_ids: RecordFieldIds,
|
||||
tuple_elem_ids: TupleElemIds,
|
||||
string_interns: &'i mut Interns<'a>,
|
||||
|
@ -76,6 +83,8 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
types_cache,
|
||||
mono_types,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
record_field_ids,
|
||||
tuple_elem_ids,
|
||||
string_interns,
|
||||
|
@ -84,25 +93,23 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_mono_expr(&mut self, can_expr: &Expr) -> MonoExpr {
|
||||
let problems = &mut self.problems;
|
||||
let mono_types = &mut self.mono_types;
|
||||
let mut mono_from_var = |var| {
|
||||
self.types_cache.monomorphize_var(
|
||||
self.arena,
|
||||
self.subs,
|
||||
mono_types,
|
||||
&mut self.record_field_ids,
|
||||
&mut self.tuple_elem_ids,
|
||||
problems,
|
||||
self.debug_info,
|
||||
var,
|
||||
)
|
||||
};
|
||||
fn mono_from_var(&mut self, var: Variable) -> MonoTypeId {
|
||||
self.types_cache.monomorphize_var(
|
||||
self.arena,
|
||||
self.subs,
|
||||
self.mono_types,
|
||||
&mut self.record_field_ids,
|
||||
&mut self.tuple_elem_ids,
|
||||
&mut self.problems,
|
||||
self.debug_info,
|
||||
var,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_mono_expr(&mut self, can_expr: &Expr) -> MonoExpr {
|
||||
macro_rules! compiler_bug {
|
||||
($problem:expr) => {{
|
||||
problems.push($problem);
|
||||
self.problems.push($problem);
|
||||
MonoExpr::CompilerBug($problem)
|
||||
}};
|
||||
}
|
||||
|
@ -115,9 +122,11 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
MonoExpr::Number(Number::Dec(*val))
|
||||
}
|
||||
_ => {
|
||||
let mono_type = mono_from_var(*var);
|
||||
match mono_types.get(mono_type) {
|
||||
MonoType::Primitive(primitive) => to_frac(*primitive, *val, problems),
|
||||
let mono_type = self.mono_from_var(*var);
|
||||
match self.mono_types.get(mono_type) {
|
||||
MonoType::Primitive(primitive) => {
|
||||
to_frac(*primitive, *val, &mut self.problems)
|
||||
}
|
||||
other => {
|
||||
compiler_bug!(Problem::NumSpecializedToWrongType(Some(*other)))
|
||||
}
|
||||
|
@ -126,23 +135,28 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
}
|
||||
}
|
||||
Expr::Num(var, _, int_value, _) | Expr::Int(var, _, _, int_value, _) => {
|
||||
let mono_type = mono_from_var(*var);
|
||||
let mono_type = self.mono_from_var(*var);
|
||||
|
||||
// Number literals and int literals both specify integer numbers, so to_num() can work on both.
|
||||
match mono_types.get(mono_type) {
|
||||
MonoType::Primitive(primitive) => to_num(*primitive, *int_value, problems),
|
||||
match self.mono_types.get(mono_type) {
|
||||
MonoType::Primitive(primitive) => match to_num(*primitive, *int_value) {
|
||||
Ok(num) => MonoExpr::Number(num),
|
||||
Err(problem) => compiler_bug!(problem),
|
||||
},
|
||||
other => compiler_bug!(Problem::NumSpecializedToWrongType(Some(*other))),
|
||||
}
|
||||
}
|
||||
Expr::SingleQuote(var, _, char, _) => {
|
||||
let mono_type = mono_from_var(*var);
|
||||
let mono_type = self.mono_from_var(*var);
|
||||
|
||||
// Single-quote characters monomorphize to an integer.
|
||||
// TODO [mono2] if we store these using the same representation as other ints (e.g. Expr::Int,
|
||||
// or keeping a separate value but storing an IntValue instead of a char), then
|
||||
// even though we verify them differently, we can combine this branch with Num and Int.
|
||||
match mono_types.get(mono_type) {
|
||||
MonoType::Primitive(primitive) => char_to_int(*primitive, *char, problems),
|
||||
match self.mono_types.get(mono_type) {
|
||||
MonoType::Primitive(primitive) => {
|
||||
char_to_int(*primitive, *char, &mut self.problems)
|
||||
}
|
||||
other => compiler_bug!(Problem::CharSpecializedToWrongType(Some(*other))),
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +214,7 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
branches,
|
||||
final_else,
|
||||
} => {
|
||||
let branch_type = mono_from_var(*branch_var);
|
||||
let branch_type = self.mono_from_var(*branch_var);
|
||||
|
||||
let mono_final_else = self.to_mono_expr(&final_else.value);
|
||||
let final_else = self.mono_exprs.add(mono_final_else, final_else.region);
|
||||
|
@ -224,10 +238,68 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
}
|
||||
}
|
||||
Expr::Var(symbol, var) | Expr::ParamsVar { symbol, var, .. } => {
|
||||
MonoExpr::Lookup(*symbol, mono_from_var(*var))
|
||||
MonoExpr::Lookup(*symbol, self.mono_from_var(*var))
|
||||
}
|
||||
Expr::When {
|
||||
loc_cond,
|
||||
cond_var,
|
||||
expr_var,
|
||||
region: _,
|
||||
branches,
|
||||
branches_cond_var: _,
|
||||
exhaustive: _,
|
||||
} => {
|
||||
let value_type = self.mono_from_var(*cond_var);
|
||||
let branch_type = self.mono_from_var(*expr_var);
|
||||
let value = self.to_mono_expr(&loc_cond.value);
|
||||
let value_id = self.mono_exprs.add(value, loc_cond.region);
|
||||
|
||||
let branches_slice = self.when_branches.reserve(branches.len());
|
||||
|
||||
for (branch_index, branch) in branches_slice.into_iter().zip(branches.iter()) {
|
||||
let patterns_slice = self.mono_patterns.reserve(branch.patterns.len());
|
||||
|
||||
for (pattern_id, pattern) in
|
||||
patterns_slice.into_iter().zip(branch.patterns.iter())
|
||||
{
|
||||
let mono_pattern = self.to_mono_pattern(&pattern.pattern.value);
|
||||
self.mono_patterns
|
||||
.insert(pattern_id, mono_pattern, pattern.pattern.region);
|
||||
}
|
||||
|
||||
let value = self.to_mono_expr(&branch.value.value);
|
||||
|
||||
let Some(patterns_slice) = NonEmptySlice::from_slice(patterns_slice) else {
|
||||
return compiler_bug!(Problem::WhenBranchHasNoPatterns);
|
||||
};
|
||||
|
||||
let guard = branch.guard.as_ref().map(|guard| {
|
||||
let mono_guard = self.to_mono_expr(&guard.value);
|
||||
self.mono_exprs.add(mono_guard, guard.region)
|
||||
});
|
||||
|
||||
let mono_branch = WhenBranch {
|
||||
patterns: patterns_slice,
|
||||
guard,
|
||||
value: self.mono_exprs.add(value, branch.value.region),
|
||||
};
|
||||
|
||||
self.when_branches.insert(branch_index, mono_branch);
|
||||
}
|
||||
|
||||
let Some(branches_slice) = NonEmptySlice::from_slice(branches_slice) else {
|
||||
return compiler_bug!(Problem::WhenHasNoBranches);
|
||||
};
|
||||
|
||||
MonoExpr::When {
|
||||
value: value_id,
|
||||
value_type,
|
||||
branch_type,
|
||||
branches: branches_slice,
|
||||
}
|
||||
}
|
||||
// Expr::Call((fn_var, fn_expr, capture_var, ret_var), args, called_via) => {
|
||||
// let opt_ret_type = mono_from_var(*var);
|
||||
// let opt_ret_type = self.mono_from_var(*var);
|
||||
|
||||
// if opt_ret_type.is_none() {
|
||||
// let fn_type = match self.subs.get_content_without_compacting(fn_var) {
|
||||
|
@ -262,7 +334,7 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
// let todo = (); // TODO this is where we need to specialize, which means...duplicating the fn expr body maybe? and caching it under the mono type?
|
||||
// let fn_expr = self.to_mono_expr(can_expr, stmts)?;
|
||||
// let args = todo!(); // TODO compute the args. This is tricky because of preallocated slices!
|
||||
// let capture_type = mono_from_var(*capture_var);
|
||||
// let capture_type = self.mono_from_var(*capture_var);
|
||||
|
||||
// let todo = (); // How do we pre-reserve the statements? Is that possible? It does seem necessary...might not be possible though. Maybe we just need to make Vec rather than Slice on these.
|
||||
|
||||
|
@ -276,11 +348,11 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
|
||||
// None
|
||||
// } else {
|
||||
// let fn_type = mono_from_var(*fn_var)?;
|
||||
// let fn_type = self.mono_from_var(*fn_var)?;
|
||||
// let todo = (); // TODO this is where we need to specialize, which means...duplicating the fn expr body maybe? and caching it under the mono type?
|
||||
// let fn_expr = self.to_mono_expr(can_expr, stmts)?;
|
||||
// let args = todo!(); // TODO compute the args. This is tricky because of preallocated slices!
|
||||
// let capture_type = mono_from_var(*capture_var);
|
||||
// let capture_type = self.mono_from_var(*capture_var);
|
||||
|
||||
// Some(MonoExpr::Call {
|
||||
// fn_type,
|
||||
|
@ -320,15 +392,6 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
// params_var,
|
||||
// } => todo!(),
|
||||
// Expr::AbilityMember(symbol, specialization_id, variable) => todo!(),
|
||||
// Expr::When {
|
||||
// loc_cond,
|
||||
// cond_var,
|
||||
// expr_var,
|
||||
// region,
|
||||
// branches,
|
||||
// branches_cond_var,
|
||||
// exhaustive,
|
||||
// } => todo!(),
|
||||
// Expr::Call(_, vec, called_via) => todo!(),
|
||||
// Expr::RunLowLevel { op, args, ret_var } => todo!(),
|
||||
// Expr::ForeignCall {
|
||||
|
@ -405,36 +468,69 @@ impl<'a, 'c, 'd, 'i, 's, 't, P: Push<Problem>> Env<'a, 'c, 'd, 'i, 's, 't, P> {
|
|||
// }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_mono_pattern(&mut self, can_pattern: &Pattern) -> MonoPattern {
|
||||
match can_pattern {
|
||||
Pattern::Identifier(ident) => MonoPattern::Identifier(*ident),
|
||||
Pattern::As(_, _) => todo!(),
|
||||
Pattern::AppliedTag { .. } => todo!(),
|
||||
Pattern::UnwrappedOpaque { .. } => todo!(),
|
||||
Pattern::RecordDestructure { .. } => todo!(),
|
||||
Pattern::TupleDestructure { .. } => todo!(),
|
||||
Pattern::List { .. } => todo!(),
|
||||
Pattern::NumLiteral(var, _, int_value, _)
|
||||
| Pattern::IntLiteral(var, _, _, int_value, _) => {
|
||||
let mono_type = self.mono_from_var(*var);
|
||||
|
||||
match self.mono_types.get(mono_type) {
|
||||
MonoType::Primitive(primitive) => match to_num(*primitive, *int_value) {
|
||||
Ok(num) => MonoPattern::NumberLiteral(num),
|
||||
Err(problem) => MonoPattern::CompilerBug(problem),
|
||||
},
|
||||
other => {
|
||||
MonoPattern::CompilerBug(Problem::NumSpecializedToWrongType(Some(*other)))
|
||||
}
|
||||
}
|
||||
}
|
||||
Pattern::FloatLiteral(_, _, _, _, _) => todo!(),
|
||||
Pattern::StrLiteral(_) => todo!(),
|
||||
Pattern::SingleQuote(_, _, _, _) => todo!(),
|
||||
Pattern::Underscore => MonoPattern::Underscore,
|
||||
Pattern::AbilityMemberSpecialization { .. } => todo!(),
|
||||
Pattern::Shadowed(_, _, _) => todo!(),
|
||||
Pattern::OpaqueNotInScope(_) => todo!(),
|
||||
Pattern::UnsupportedPattern(_) => todo!(),
|
||||
Pattern::MalformedPattern(_, _) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a number literal (e.g. `42`) or integer literal (e.g. `0x42`) to a monomorphized type.
|
||||
/// Nums are allowed to convert to either an integer or a fraction. Integer literals should have
|
||||
/// given a compile-time error if they ended up unifying to a fractional type, but we can
|
||||
/// gracefully allow them to compile to that type anyway.
|
||||
fn to_num(primitive: Primitive, val: IntValue, problems: &mut impl Push<Problem>) -> MonoExpr {
|
||||
fn to_num(primitive: Primitive, val: IntValue) -> Result<Number, Problem> {
|
||||
match primitive {
|
||||
// These are ordered roughly by most to least common integer types
|
||||
Primitive::U8 => MonoExpr::Number(Number::U8(val.as_i128() as u8)),
|
||||
Primitive::I8 => MonoExpr::Number(Number::I8(val.as_i128() as i8)),
|
||||
Primitive::U16 => MonoExpr::Number(Number::U16(val.as_i128() as u16)),
|
||||
Primitive::I16 => MonoExpr::Number(Number::I16(val.as_i128() as i16)),
|
||||
Primitive::U32 => MonoExpr::Number(Number::U32(val.as_i128() as u32)),
|
||||
Primitive::I32 => MonoExpr::Number(Number::I32(val.as_i128() as i32)),
|
||||
Primitive::U64 => MonoExpr::Number(Number::U64(val.as_i128() as u64)),
|
||||
Primitive::I64 => MonoExpr::Number(Number::I64(val.as_i128() as i64)),
|
||||
Primitive::F32 => MonoExpr::Number(Number::F32(val.as_i128() as f32)),
|
||||
Primitive::F64 => MonoExpr::Number(Number::F64(val.as_i128() as f64)),
|
||||
Primitive::Dec => MonoExpr::Number(Number::Dec(match val {
|
||||
Primitive::U8 => Ok(Number::U8(val.as_i128() as u8)),
|
||||
Primitive::I8 => Ok(Number::I8(val.as_i128() as i8)),
|
||||
Primitive::U16 => Ok(Number::U16(val.as_i128() as u16)),
|
||||
Primitive::I16 => Ok(Number::I16(val.as_i128() as i16)),
|
||||
Primitive::U32 => Ok(Number::U32(val.as_i128() as u32)),
|
||||
Primitive::I32 => Ok(Number::I32(val.as_i128() as i32)),
|
||||
Primitive::U64 => Ok(Number::U64(val.as_i128() as u64)),
|
||||
Primitive::I64 => Ok(Number::I64(val.as_i128() as i64)),
|
||||
Primitive::F32 => Ok(Number::F32(val.as_i128() as f32)),
|
||||
Primitive::F64 => Ok(Number::F64(val.as_i128() as f64)),
|
||||
Primitive::Dec => Ok(Number::Dec(match val {
|
||||
IntValue::I128(bytes) => i128::from_ne_bytes(bytes) as f64,
|
||||
IntValue::U128(bytes) => u128::from_ne_bytes(bytes) as f64,
|
||||
})),
|
||||
Primitive::U128 => MonoExpr::Number(Number::U128(val.as_u128())),
|
||||
Primitive::I128 => MonoExpr::Number(Number::I128(val.as_i128())),
|
||||
Primitive::Str | Primitive::Crash | Primitive::Bool => {
|
||||
let problem = Problem::NumSpecializedToWrongType(Some(MonoType::Primitive(primitive)));
|
||||
problems.push(problem);
|
||||
MonoExpr::CompilerBug(problem)
|
||||
}
|
||||
Primitive::U128 => Ok(Number::U128(val.as_u128())),
|
||||
Primitive::I128 => Ok(Number::I128(val.as_i128())),
|
||||
Primitive::Str | Primitive::Crash | Primitive::Bool => Err(
|
||||
Problem::NumSpecializedToWrongType(Some(MonoType::Primitive(primitive))),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,14 @@
|
|||
use crate::{
|
||||
foreign_symbol::ForeignSymbolId, mono_module::InternedStrId, mono_num::Number,
|
||||
mono_struct::MonoFieldId, mono_type::MonoTypeId, specialize_type::Problem,
|
||||
mono_struct::MonoFieldId, mono_type::MonoTypeId, specialize_type::Problem, MonoPattern,
|
||||
MonoPatternId,
|
||||
};
|
||||
use roc_can::expr::Recursive;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::Region;
|
||||
use soa::{Index, NonEmptySlice, PairSlice, Slice, Slice2, Slice3};
|
||||
use std::iter;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct MonoPatternId {
|
||||
inner: u32,
|
||||
}
|
||||
use soa::{Index, NonEmptySlice, PairSlice, Slice, Slice2};
|
||||
use std::{iter, mem::MaybeUninit};
|
||||
|
||||
pub type IdentId = Symbol; // TODO make this an Index into an array local to this module
|
||||
|
||||
|
@ -298,43 +294,75 @@ pub enum MonoExpr {
|
|||
final_else: MonoExprId,
|
||||
},
|
||||
|
||||
When {
|
||||
/// The value being matched on
|
||||
value: MonoExprId,
|
||||
/// The type of the value being matched on
|
||||
value_type: MonoTypeId,
|
||||
/// The return type of all branches and thus the whole when expression
|
||||
branch_type: MonoTypeId,
|
||||
/// The branches of the when expression
|
||||
branches: NonEmptySlice<WhenBranch>,
|
||||
},
|
||||
|
||||
CompilerBug(Problem),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum MonoPattern {
|
||||
Identifier(IdentId),
|
||||
As(MonoPatternId, IdentId),
|
||||
StrLiteral(InternedStrId),
|
||||
NumberLiteral(Number),
|
||||
AppliedTag {
|
||||
tag_union_type: MonoTypeId,
|
||||
tag_name: IdentId,
|
||||
args: Slice<MonoPatternId>,
|
||||
},
|
||||
StructDestructure {
|
||||
struct_type: MonoTypeId,
|
||||
destructs: Slice3<IdentId, MonoFieldId, DestructType>,
|
||||
},
|
||||
List {
|
||||
elem_type: MonoTypeId,
|
||||
patterns: Slice<MonoPatternId>,
|
||||
|
||||
/// Where a rest pattern splits patterns before and after it, if it does at all.
|
||||
/// If present, patterns at index >= the rest index appear after the rest pattern.
|
||||
/// For example:
|
||||
/// [ .., A, B ] -> patterns = [A, B], rest = 0
|
||||
/// [ A, .., B ] -> patterns = [A, B], rest = 1
|
||||
/// [ A, B, .. ] -> patterns = [A, B], rest = 2
|
||||
/// Optionally, the rest pattern can be named - e.g. `[ A, B, ..others ]`
|
||||
opt_rest: Option<(u16, Option<IdentId>)>,
|
||||
},
|
||||
Underscore,
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct WhenBranch {
|
||||
/// The pattern(s) to match the value against
|
||||
pub patterns: NonEmptySlice<MonoPattern>,
|
||||
/// A boolean expression that must be true for this branch to be taken
|
||||
pub guard: Option<MonoExprId>,
|
||||
/// The expression to produce if the pattern matches
|
||||
pub value: MonoExprId,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum DestructType {
|
||||
Required,
|
||||
Optional(MonoTypeId, MonoExprId),
|
||||
Guard(MonoTypeId, MonoPatternId),
|
||||
#[derive(Debug, Default)]
|
||||
pub struct WhenBranches {
|
||||
branches: Vec<MaybeUninit<WhenBranch>>,
|
||||
}
|
||||
|
||||
impl WhenBranches {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
branches: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reserve(&mut self, count: usize) -> Slice<WhenBranch> {
|
||||
let start = self.branches.len();
|
||||
|
||||
let new_size = start + count;
|
||||
self.branches.reserve(count);
|
||||
|
||||
unsafe {
|
||||
self.branches.set_len(new_size);
|
||||
}
|
||||
|
||||
Slice::new(start as u32, count as u16)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, id: Index<WhenBranch>, branch: WhenBranch) {
|
||||
debug_assert!(
|
||||
self.branches.get(id.index()).is_some(),
|
||||
"A WhenBranch index was not found in WhenBranches. This should never happen!"
|
||||
);
|
||||
|
||||
// Safety: we should only ever hand out WhenBranch indices that are valid indices into here.
|
||||
unsafe {
|
||||
self.branches.get_unchecked_mut(id.index()).write(branch);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_slice(
|
||||
&self,
|
||||
branches: Slice<WhenBranch>,
|
||||
) -> impl Iterator<Item = &MaybeUninit<WhenBranch>> {
|
||||
branches.indices().map(|index| {
|
||||
debug_assert!(self.branches.len() > index, "Slice index out of bounds");
|
||||
|
||||
unsafe { self.branches.get_unchecked(index) }
|
||||
})
|
||||
}
|
||||
}
|
110
crates/build/specialize_types/src/mono_pattern.rs
Normal file
110
crates/build/specialize_types/src/mono_pattern.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
use roc_region::all::Region;
|
||||
use soa::{Index, Slice, Slice3};
|
||||
|
||||
use crate::{
|
||||
mono_ir::IdentId, InternedStrId, MonoExprId, MonoFieldId, MonoTypeId, Number, Problem,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct MonoPatternId {
|
||||
inner: Index<MonoPattern>,
|
||||
}
|
||||
|
||||
impl MonoPatternId {
|
||||
fn new(inner: Index<MonoPattern>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct MonoPatterns {
|
||||
patterns: Vec<MonoPattern>,
|
||||
regions: Vec<Region>,
|
||||
}
|
||||
|
||||
impl MonoPatterns {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
patterns: Vec::new(),
|
||||
regions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reserve(&mut self, count: usize) -> Slice<MonoPattern> {
|
||||
let start = self.patterns.len();
|
||||
|
||||
self.patterns.extend(
|
||||
std::iter::repeat(MonoPattern::CompilerBug(
|
||||
Problem::UninitializedReservedPattern,
|
||||
))
|
||||
.take(count),
|
||||
);
|
||||
self.regions
|
||||
.extend(std::iter::repeat(Region::zero()).take(count));
|
||||
|
||||
Slice::new(start as u32, count as u16)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, id: Index<MonoPattern>, pattern: MonoPattern, region: Region) {
|
||||
debug_assert!(
|
||||
self.patterns.len() > id.index(),
|
||||
"Pattern index out of bounds"
|
||||
);
|
||||
|
||||
// Safety: we should only ever hand out WhenBranch indices that are valid indices into here.
|
||||
unsafe {
|
||||
*self.patterns.get_unchecked_mut(id.index()) = pattern;
|
||||
*self.regions.get_unchecked_mut(id.index()) = region;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_slice(&self, patterns: Slice<MonoPattern>) -> impl Iterator<Item = &MonoPattern> {
|
||||
patterns.indices().map(|index| {
|
||||
debug_assert!(
|
||||
self.patterns.len() > index,
|
||||
"MonoPattern Slice out of bounds"
|
||||
);
|
||||
|
||||
unsafe { self.patterns.get_unchecked(index) }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum MonoPattern {
|
||||
Identifier(IdentId),
|
||||
As(MonoPatternId, IdentId),
|
||||
StrLiteral(InternedStrId),
|
||||
NumberLiteral(Number),
|
||||
AppliedTag {
|
||||
tag_union_type: MonoTypeId,
|
||||
tag_name: IdentId,
|
||||
args: Slice<MonoPatternId>,
|
||||
},
|
||||
StructDestructure {
|
||||
struct_type: MonoTypeId,
|
||||
destructs: Slice3<IdentId, MonoFieldId, DestructType>,
|
||||
},
|
||||
List {
|
||||
elem_type: MonoTypeId,
|
||||
patterns: Slice<MonoPatternId>,
|
||||
|
||||
/// Where a rest pattern splits patterns before and after it, if it does at all.
|
||||
/// If present, patterns at index >= the rest index appear after the rest pattern.
|
||||
/// For example:
|
||||
/// [ .., A, B ] -> patterns = [A, B], rest = 0
|
||||
/// [ A, .., B ] -> patterns = [A, B], rest = 1
|
||||
/// [ A, B, .. ] -> patterns = [A, B], rest = 2
|
||||
/// Optionally, the rest pattern can be named - e.g. `[ A, B, ..others ]`
|
||||
opt_rest: Option<(u16, Option<IdentId>)>,
|
||||
},
|
||||
Underscore,
|
||||
CompilerBug(Problem),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum DestructType {
|
||||
Required,
|
||||
Optional(MonoTypeId, MonoExprId),
|
||||
Guard(MonoTypeId, MonoPatternId),
|
||||
}
|
|
@ -35,6 +35,9 @@ pub enum Problem {
|
|||
BadNumTypeParam,
|
||||
UninitializedReservedExpr,
|
||||
FnDidNotHaveFnType,
|
||||
WhenHasNoBranches,
|
||||
WhenBranchHasNoPatterns,
|
||||
UninitializedReservedPattern,
|
||||
}
|
||||
|
||||
/// For MonoTypes that are records, store their field indices.
|
|
@ -7,8 +7,8 @@ use roc_load::LoadedModule;
|
|||
use roc_region::all::Region;
|
||||
use roc_solve::FunctionKind;
|
||||
use roc_specialize_types::{
|
||||
DebugInfo, Env, Interns, MonoExpr, MonoExprs, MonoTypeCache, MonoTypes, RecordFieldIds,
|
||||
TupleElemIds,
|
||||
DebugInfo, Env, Interns, MonoExpr, MonoExprs, MonoPattern, MonoPatterns, MonoTypeCache,
|
||||
MonoTypes, RecordFieldIds, TupleElemIds, WhenBranches,
|
||||
};
|
||||
use test_compile::{trim_and_deindent, SpecializedExprOut};
|
||||
use test_solve_helpers::{format_problems, run_load_and_infer};
|
||||
|
@ -65,6 +65,8 @@ fn specialize_expr<'a>(
|
|||
let mut types_cache = MonoTypeCache::from_solved_subs(&solved);
|
||||
let mut mono_types = MonoTypes::new();
|
||||
let mut mono_exprs = MonoExprs::new();
|
||||
let mut mono_patterns = MonoPatterns::new();
|
||||
let mut when_branches = WhenBranches::new();
|
||||
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
|
@ -72,6 +74,8 @@ fn specialize_expr<'a>(
|
|||
&mut types_cache,
|
||||
&mut mono_types,
|
||||
&mut mono_exprs,
|
||||
&mut mono_patterns,
|
||||
&mut when_branches,
|
||||
RecordFieldIds::default(),
|
||||
TupleElemIds::default(),
|
||||
string_interns,
|
||||
|
@ -94,6 +98,8 @@ fn specialize_expr<'a>(
|
|||
problems,
|
||||
mono_types,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
region,
|
||||
}
|
||||
}
|
||||
|
@ -117,9 +123,17 @@ pub fn expect_mono_expr(input: impl AsRef<str>, mono_expr: MonoExpr) {
|
|||
pub fn expect_mono_expr_str(input: impl AsRef<str>, expr_str: impl AsRef<str>) {
|
||||
expect_mono_expr_custom(
|
||||
input,
|
||||
|_, _, _| expr_str.as_ref().to_string(),
|
||||
|arena, mono_exprs, interns, expr| {
|
||||
dbg_mono_expr(arena, mono_exprs, interns, expr).to_string()
|
||||
|_, _, _, _, _| expr_str.as_ref().to_string(),
|
||||
|arena, mono_exprs, mono_patterns, when_branches, interns, expr| {
|
||||
dbg_mono_expr(
|
||||
arena,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
interns,
|
||||
expr,
|
||||
)
|
||||
.to_string()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -127,12 +141,23 @@ pub fn expect_mono_expr_str(input: impl AsRef<str>, expr_str: impl AsRef<str>) {
|
|||
fn dbg_mono_expr<'a>(
|
||||
arena: &'a Bump,
|
||||
mono_exprs: &MonoExprs,
|
||||
mono_patterns: &MonoPatterns,
|
||||
when_branches: &WhenBranches,
|
||||
interns: &Interns<'a>,
|
||||
expr: &MonoExpr,
|
||||
) -> &'a str {
|
||||
let mut buf = bumpalo::collections::String::new_in(arena);
|
||||
|
||||
dbg_mono_expr_help(arena, mono_exprs, interns, expr, &mut buf).unwrap();
|
||||
dbg_mono_expr_help(
|
||||
arena,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
interns,
|
||||
expr,
|
||||
&mut buf,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
buf.into_bump_str()
|
||||
}
|
||||
|
@ -140,6 +165,8 @@ fn dbg_mono_expr<'a>(
|
|||
fn dbg_mono_expr_help<'a>(
|
||||
arena: &'a Bump,
|
||||
mono_exprs: &MonoExprs,
|
||||
mono_patterns: &MonoPatterns,
|
||||
when_branches: &WhenBranches,
|
||||
interns: &Interns<'a>,
|
||||
expr: &MonoExpr,
|
||||
buf: &mut impl Write,
|
||||
|
@ -159,7 +186,15 @@ fn dbg_mono_expr_help<'a>(
|
|||
write!(buf, ", ")?;
|
||||
}
|
||||
|
||||
dbg_mono_expr_help(arena, mono_exprs, interns, expr, buf)?;
|
||||
dbg_mono_expr_help(
|
||||
arena,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
interns,
|
||||
expr,
|
||||
buf,
|
||||
)?;
|
||||
}
|
||||
|
||||
write!(buf, "])")
|
||||
|
@ -179,9 +214,25 @@ fn dbg_mono_expr_help<'a>(
|
|||
write!(buf, ", ")?;
|
||||
}
|
||||
|
||||
dbg_mono_expr_help(arena, mono_exprs, interns, cond, buf)?;
|
||||
dbg_mono_expr_help(
|
||||
arena,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
interns,
|
||||
cond,
|
||||
buf,
|
||||
)?;
|
||||
write!(buf, " -> ")?;
|
||||
dbg_mono_expr_help(arena, mono_exprs, interns, branch, buf)?;
|
||||
dbg_mono_expr_help(
|
||||
arena,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
interns,
|
||||
branch,
|
||||
buf,
|
||||
)?;
|
||||
write!(buf, ")")?;
|
||||
}
|
||||
|
||||
|
@ -189,6 +240,8 @@ fn dbg_mono_expr_help<'a>(
|
|||
dbg_mono_expr_help(
|
||||
arena,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
interns,
|
||||
mono_exprs.get_expr(*final_else),
|
||||
buf,
|
||||
|
@ -198,6 +251,73 @@ fn dbg_mono_expr_help<'a>(
|
|||
MonoExpr::Lookup(ident, _mono_type_id) => {
|
||||
write!(buf, "{:?}", ident)
|
||||
}
|
||||
MonoExpr::When {
|
||||
value,
|
||||
value_type: _,
|
||||
branch_type: _,
|
||||
branches,
|
||||
} => {
|
||||
write!(buf, "When(")?;
|
||||
|
||||
dbg_mono_expr_help(
|
||||
arena,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
interns,
|
||||
mono_exprs.get_expr(*value),
|
||||
buf,
|
||||
)?;
|
||||
|
||||
write!(buf, ", ")?;
|
||||
|
||||
for (index, branch) in when_branches.iter_slice(branches.as_slice()).enumerate() {
|
||||
if index > 0 {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
|
||||
let branch = unsafe { branch.assume_init() };
|
||||
|
||||
for (index, pattern) in mono_patterns
|
||||
.iter_slice(branch.patterns.as_slice())
|
||||
.enumerate()
|
||||
{
|
||||
if index > 0 {
|
||||
write!(buf, " | ")?;
|
||||
}
|
||||
|
||||
dbg_mono_pattern_help(arena, mono_patterns, interns, pattern, buf)?;
|
||||
}
|
||||
|
||||
if let Some(guard) = branch.guard {
|
||||
write!(buf, " if ")?;
|
||||
|
||||
dbg_mono_expr_help(
|
||||
arena,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
interns,
|
||||
mono_exprs.get_expr(guard),
|
||||
buf,
|
||||
)?;
|
||||
}
|
||||
|
||||
write!(buf, " -> ")?;
|
||||
|
||||
dbg_mono_expr_help(
|
||||
arena,
|
||||
mono_exprs,
|
||||
mono_patterns,
|
||||
when_branches,
|
||||
interns,
|
||||
mono_exprs.get_expr(branch.value),
|
||||
buf,
|
||||
)?;
|
||||
}
|
||||
|
||||
write!(buf, ")")
|
||||
}
|
||||
// MonoExpr::List { elem_type, elems } => todo!(),
|
||||
// MonoExpr::ParameterizedLookup {
|
||||
// name,
|
||||
|
@ -281,6 +401,44 @@ fn dbg_mono_expr_help<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn dbg_mono_pattern_help<'a>(
|
||||
_arena: &'a Bump,
|
||||
_mono_patterns: &MonoPatterns,
|
||||
_interns: &Interns<'a>,
|
||||
pattern: &MonoPattern,
|
||||
buf: &mut impl Write,
|
||||
) -> Result<(), core::fmt::Error> {
|
||||
match pattern {
|
||||
MonoPattern::Identifier(ident) => {
|
||||
write!(buf, "Identifier({:?})", ident)
|
||||
}
|
||||
MonoPattern::As(_, _) => {
|
||||
todo!()
|
||||
}
|
||||
MonoPattern::StrLiteral(_) => {
|
||||
todo!()
|
||||
}
|
||||
MonoPattern::NumberLiteral(number) => {
|
||||
write!(buf, "Number({:?})", number)
|
||||
}
|
||||
MonoPattern::AppliedTag { .. } => {
|
||||
todo!()
|
||||
}
|
||||
MonoPattern::StructDestructure { .. } => {
|
||||
todo!()
|
||||
}
|
||||
MonoPattern::List { .. } => {
|
||||
todo!()
|
||||
}
|
||||
MonoPattern::Underscore => {
|
||||
write!(buf, "Underscore")
|
||||
}
|
||||
MonoPattern::CompilerBug(problem) => {
|
||||
write!(buf, "CompilerBug({:?}", problem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn expect_mono_expr_with_interns(
|
||||
input: impl AsRef<str>,
|
||||
|
@ -288,24 +446,44 @@ pub fn expect_mono_expr_with_interns(
|
|||
) {
|
||||
expect_mono_expr_custom(
|
||||
input,
|
||||
|arena, _exprs, interns| from_interns(arena, interns),
|
||||
|_, _, _, expr| *expr,
|
||||
|arena, _exprs, _, _, interns| from_interns(arena, interns),
|
||||
|_, _, _, _, _, expr| *expr,
|
||||
);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn expect_mono_expr_custom<T: PartialEq + core::fmt::Debug>(
|
||||
input: impl AsRef<str>,
|
||||
to_expected: impl for<'a> Fn(&'a Bump, &MonoExprs, &Interns<'a>) -> T,
|
||||
to_actual: impl for<'a> Fn(&'a Bump, &MonoExprs, &Interns<'a>, &MonoExpr) -> T,
|
||||
to_expected: impl for<'a> Fn(&'a Bump, &MonoExprs, &MonoPatterns, &WhenBranches, &Interns<'a>) -> T,
|
||||
to_actual: impl for<'a> Fn(
|
||||
&'a Bump,
|
||||
&MonoExprs,
|
||||
&MonoPatterns,
|
||||
&WhenBranches,
|
||||
&Interns<'a>,
|
||||
&MonoExpr,
|
||||
) -> T,
|
||||
) {
|
||||
let arena = Bump::new();
|
||||
let mut string_interns = Interns::new();
|
||||
let out = specialize_expr(&arena, input.as_ref(), &mut string_interns);
|
||||
|
||||
let actual_expr = out.mono_exprs.get_expr(out.mono_expr_id); // Must run first, to populate string interns!
|
||||
let actual = to_actual(&arena, &out.mono_exprs, &string_interns, actual_expr);
|
||||
let expected = to_expected(&arena, &out.mono_exprs, &string_interns);
|
||||
let actual = to_actual(
|
||||
&arena,
|
||||
&out.mono_exprs,
|
||||
&out.mono_patterns,
|
||||
&out.when_branches,
|
||||
&string_interns,
|
||||
actual_expr,
|
||||
);
|
||||
let expected = to_expected(
|
||||
&arena,
|
||||
&out.mono_exprs,
|
||||
&out.mono_patterns,
|
||||
&out.when_branches,
|
||||
&string_interns,
|
||||
);
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
|
@ -5,7 +5,7 @@ extern crate pretty_assertions;
|
|||
mod helpers;
|
||||
|
||||
#[cfg(test)]
|
||||
mod specialize_structs {
|
||||
mod specialize_if {
|
||||
use crate::helpers::expect_mono_expr_str;
|
||||
|
||||
#[test]
|
69
crates/build/specialize_types/tests/specialize_when.rs
Normal file
69
crates/build/specialize_types/tests/specialize_when.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
#[macro_use]
|
||||
extern crate pretty_assertions;
|
||||
|
||||
#[cfg(test)]
|
||||
mod helpers;
|
||||
|
||||
#[cfg(test)]
|
||||
mod specialize_when {
|
||||
use crate::helpers::expect_mono_expr_str;
|
||||
|
||||
#[test]
|
||||
fn single_branch() {
|
||||
expect_mono_expr_str(
|
||||
r"
|
||||
when 123 is
|
||||
num -> num
|
||||
",
|
||||
"When(Number(I8(123)), Identifier(`#UserApp.IdentId(1)`) -> `#UserApp.IdentId(1)`)",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn number_pattern() {
|
||||
expect_mono_expr_str(
|
||||
r"
|
||||
when 123 is
|
||||
123 -> 321
|
||||
num -> num
|
||||
",
|
||||
"When(Number(I16(123)), Number(I16(123)) -> Number(I16(321)), Identifier(`#UserApp.IdentId(1)`) -> `#UserApp.IdentId(1)`)",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn underscore_pattern() {
|
||||
expect_mono_expr_str(
|
||||
r"
|
||||
when 123 is
|
||||
123 -> 321
|
||||
_ -> 0
|
||||
",
|
||||
"When(Number(I8(123)), Number(I8(123)) -> Number(I16(321)), Underscore -> Number(I16(0)))"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_patterns_per_branch() {
|
||||
expect_mono_expr_str(
|
||||
r"
|
||||
when 123 is
|
||||
123 | 321 -> 321
|
||||
_ -> 0
|
||||
",
|
||||
"When(Number(I16(123)), Number(I16(123)) | Number(I16(321)) -> Number(I16(321)), Underscore -> Number(I16(0)))"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn guard() {
|
||||
expect_mono_expr_str(
|
||||
r"
|
||||
when 123 is
|
||||
123 if Bool.true -> 321
|
||||
_ -> 0
|
||||
",
|
||||
"When(Number(I8(123)), Number(I8(123)) if `Bool.true` -> Number(I16(321)), Underscore -> Number(I16(0)))"
|
||||
);
|
||||
}
|
||||
}
|
|
@ -199,7 +199,7 @@ pub enum FormatProblem {
|
|||
|
||||
pub fn format_src(arena: &Bump, src: &str, flags: MigrationFlags) -> Result<String, FormatProblem> {
|
||||
let ast = arena.alloc(parse_all(arena, src).unwrap_or_else(|e| {
|
||||
user_error!("Unexpected parse failure when parsing this formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", src, e)
|
||||
user_error!("Unexpected parse failure when parsing this formatting:\n\n{src}\n\nParse error was:\n\n{:#?}\n\n", e)
|
||||
}));
|
||||
let mut buf = Buf::new_in(arena, flags);
|
||||
fmt_all(&mut buf, ast);
|
||||
|
@ -438,14 +438,14 @@ import pf.Stdin
|
|||
main =
|
||||
Stdout.line! "What's your name?"
|
||||
name = Stdin.line!
|
||||
Stdout.line! "Hi $(name)!""#;
|
||||
Stdout.line! "Hi ${name}!""#;
|
||||
|
||||
const UNFORMATTED_ROC: &str = r#"app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
main =
|
||||
Stdout.line! "What's your name?"
|
||||
name = Stdin.line!
|
||||
Stdout.line! "Hi $(name)!"
|
||||
Stdout.line! "Hi ${name}!"
|
||||
"#;
|
||||
|
||||
fn setup_test_file(dir: &Path, file_name: &str, contents: &str) -> PathBuf {
|
||||
|
@ -465,7 +465,10 @@ main =
|
|||
fn test_single_file_needs_reformatting() {
|
||||
let dir = tempdir().unwrap();
|
||||
let file_path = setup_test_file(dir.path(), "test1.roc", UNFORMATTED_ROC);
|
||||
let flags = MigrationFlags::new(false);
|
||||
let flags = MigrationFlags {
|
||||
snakify: false,
|
||||
parens_and_commas: false,
|
||||
};
|
||||
|
||||
let result = format_files(vec![file_path.clone()], FormatMode::CheckOnly, flags);
|
||||
assert!(result.is_err());
|
||||
|
@ -485,7 +488,10 @@ main =
|
|||
let dir = tempdir().unwrap();
|
||||
let file1 = setup_test_file(dir.path(), "test1.roc", UNFORMATTED_ROC);
|
||||
let file2 = setup_test_file(dir.path(), "test2.roc", UNFORMATTED_ROC);
|
||||
let flags = MigrationFlags::new(false);
|
||||
let flags = MigrationFlags {
|
||||
snakify: false,
|
||||
parens_and_commas: false,
|
||||
};
|
||||
|
||||
let result = format_files(vec![file1, file2], FormatMode::CheckOnly, flags);
|
||||
assert!(result.is_err());
|
||||
|
@ -499,7 +505,10 @@ main =
|
|||
fn test_no_files_need_reformatting() {
|
||||
let dir = tempdir().unwrap();
|
||||
let file_path = setup_test_file(dir.path(), "formatted.roc", FORMATTED_ROC);
|
||||
let flags = MigrationFlags::new(false);
|
||||
let flags = MigrationFlags {
|
||||
snakify: false,
|
||||
parens_and_commas: false,
|
||||
};
|
||||
|
||||
let result = format_files(vec![file_path], FormatMode::CheckOnly, flags);
|
||||
assert!(result.is_ok());
|
||||
|
@ -513,7 +522,10 @@ main =
|
|||
let file_formatted = setup_test_file(dir.path(), "formatted.roc", FORMATTED_ROC);
|
||||
let file1_unformated = setup_test_file(dir.path(), "test1.roc", UNFORMATTED_ROC);
|
||||
let file2_unformated = setup_test_file(dir.path(), "test2.roc", UNFORMATTED_ROC);
|
||||
let flags = MigrationFlags::new(false);
|
||||
let flags = MigrationFlags {
|
||||
snakify: false,
|
||||
parens_and_commas: false,
|
||||
};
|
||||
|
||||
let result = format_files(
|
||||
vec![file_formatted, file1_unformated, file2_unformated],
|
||||
|
|
|
@ -92,6 +92,7 @@ pub const FLAG_PP_HOST: &str = "host";
|
|||
pub const FLAG_PP_PLATFORM: &str = "platform";
|
||||
pub const FLAG_PP_DYLIB: &str = "lib";
|
||||
pub const FLAG_MIGRATE: &str = "migrate";
|
||||
pub const FLAG_DOCS_ROOT: &str = "root-dir";
|
||||
|
||||
pub const VERSION: &str = env!("ROC_VERSION");
|
||||
const DEFAULT_GENERATED_DOCS_DIR: &str = "generated-docs";
|
||||
|
@ -187,6 +188,12 @@ pub fn build_app() -> Command {
|
|||
.num_args(0..)
|
||||
.allow_hyphen_values(true);
|
||||
|
||||
let flag_docs_root_dir = Arg::new(FLAG_DOCS_ROOT)
|
||||
.long(FLAG_DOCS_ROOT)
|
||||
.help("Set a root directory path to be used as a prefix for URL links in the generated documentation files.")
|
||||
.value_parser(value_parser!(Option<String>))
|
||||
.required(false);
|
||||
|
||||
let build_target_values_parser =
|
||||
PossibleValuesParser::new(Target::iter().map(Into::<&'static str>::into));
|
||||
|
||||
|
@ -244,6 +251,13 @@ pub fn build_app() -> Command {
|
|||
.action(ArgAction::SetTrue)
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(FLAG_VERBOSE)
|
||||
.long(FLAG_VERBOSE)
|
||||
.help("Print detailed information while building")
|
||||
.action(ArgAction::SetTrue)
|
||||
.required(false)
|
||||
)
|
||||
.arg(
|
||||
Arg::new(ROC_FILE)
|
||||
.help("The .roc file to build")
|
||||
|
@ -411,6 +425,7 @@ pub fn build_app() -> Command {
|
|||
.required(false)
|
||||
.default_value(DEFAULT_ROC_FILENAME),
|
||||
)
|
||||
.arg(flag_docs_root_dir)
|
||||
)
|
||||
.subcommand(Command::new(CMD_GLUE)
|
||||
.about("Generate glue code between a platform's Roc API and its host language")
|
||||
|
@ -434,6 +449,7 @@ pub fn build_app() -> Command {
|
|||
.required(false)
|
||||
.default_value(DEFAULT_ROC_FILENAME)
|
||||
)
|
||||
.arg(flag_linker.clone())
|
||||
)
|
||||
.subcommand(Command::new(CMD_PREPROCESS_HOST)
|
||||
.about("Runs the surgical linker preprocessor to generate `.rh` and `.rm` files.")
|
||||
|
@ -779,6 +795,30 @@ fn nearest_match<'a>(reference: &str, options: &'a [String]) -> Option<(&'a Stri
|
|||
.min_by(|(_, a), (_, b)| a.cmp(b))
|
||||
}
|
||||
|
||||
pub fn default_linking_strategy(
|
||||
matches: &ArgMatches,
|
||||
link_type: LinkType,
|
||||
target: Target,
|
||||
) -> LinkingStrategy {
|
||||
let linker_support_level = roc_linker::support_level(link_type, target);
|
||||
match matches.get_one::<String>(FLAG_LINKER).map(AsRef::as_ref) {
|
||||
Some("legacy") => LinkingStrategy::Legacy,
|
||||
Some("surgical") => match linker_support_level {
|
||||
roc_linker::SupportLevel::Full => LinkingStrategy::Surgical,
|
||||
roc_linker::SupportLevel::Wip => {
|
||||
println!("Warning! Using an unfinished surgical linker for target {target}");
|
||||
LinkingStrategy::Surgical
|
||||
}
|
||||
roc_linker::SupportLevel::None => LinkingStrategy::Legacy,
|
||||
},
|
||||
_ => match linker_support_level {
|
||||
roc_linker::SupportLevel::Full => LinkingStrategy::Surgical,
|
||||
_ => LinkingStrategy::Legacy,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn build(
|
||||
matches: &ArgMatches,
|
||||
subcommands: &[String],
|
||||
|
@ -787,6 +827,7 @@ pub fn build(
|
|||
out_path: Option<&Path>,
|
||||
roc_cache_dir: RocCacheDir<'_>,
|
||||
link_type: LinkType,
|
||||
verbose: bool,
|
||||
) -> io::Result<i32> {
|
||||
use BuildConfig::*;
|
||||
|
||||
|
@ -929,12 +970,8 @@ pub fn build(
|
|||
|
||||
let linking_strategy = if wasm_dev_backend {
|
||||
LinkingStrategy::Additive
|
||||
} else if !roc_linker::supported(link_type, target)
|
||||
|| matches.get_one::<String>(FLAG_LINKER).map(|s| s.as_str()) == Some("legacy")
|
||||
{
|
||||
LinkingStrategy::Legacy
|
||||
} else {
|
||||
LinkingStrategy::Surgical
|
||||
default_linking_strategy(matches, link_type, target)
|
||||
};
|
||||
|
||||
// All hosts should be prebuilt, this flag keeps the rebuilding behvaiour
|
||||
|
@ -982,6 +1019,7 @@ pub fn build(
|
|||
roc_cache_dir,
|
||||
load_config,
|
||||
out_path,
|
||||
verbose,
|
||||
);
|
||||
|
||||
match res_binary_path {
|
||||
|
|
|
@ -3,12 +3,13 @@ use bumpalo::Bump;
|
|||
use roc_build::link::LinkType;
|
||||
use roc_build::program::{check_file, CodeGenBackend};
|
||||
use roc_cli::{
|
||||
annotate_file, build_app, format_files, format_src, test, BuildConfig, FormatMode, CMD_BUILD,
|
||||
CMD_CHECK, CMD_DEV, CMD_DOCS, CMD_FORMAT, CMD_FORMAT_ANNOTATE, CMD_GLUE, CMD_PREPROCESS_HOST,
|
||||
CMD_REPL, CMD_RUN, CMD_TEST, CMD_VERSION, DIRECTORY_OR_FILES, FLAG_CHECK, FLAG_DEV, FLAG_LIB,
|
||||
FLAG_MAIN, FLAG_MIGRATE, FLAG_NO_COLOR, FLAG_NO_HEADER, FLAG_NO_LINK, FLAG_OUTPUT,
|
||||
FLAG_PP_DYLIB, FLAG_PP_HOST, FLAG_PP_PLATFORM, FLAG_STDIN, FLAG_STDOUT, FLAG_TARGET, FLAG_TIME,
|
||||
GLUE_DIR, GLUE_SPEC, ROC_FILE, VERSION,
|
||||
annotate_file, build_app, default_linking_strategy, format_files, format_src, test,
|
||||
BuildConfig, FormatMode, CMD_BUILD, CMD_CHECK, CMD_DEV, CMD_DOCS, CMD_FORMAT,
|
||||
CMD_FORMAT_ANNOTATE, CMD_GLUE, CMD_PREPROCESS_HOST, CMD_REPL, CMD_RUN, CMD_TEST, CMD_VERSION,
|
||||
DIRECTORY_OR_FILES, FLAG_CHECK, FLAG_DEV, FLAG_DOCS_ROOT, FLAG_LIB, FLAG_MAIN, FLAG_MIGRATE,
|
||||
FLAG_NO_COLOR, FLAG_NO_HEADER, FLAG_NO_LINK, FLAG_OUTPUT, FLAG_PP_DYLIB, FLAG_PP_HOST,
|
||||
FLAG_PP_PLATFORM, FLAG_STDIN, FLAG_STDOUT, FLAG_TARGET, FLAG_TIME, FLAG_VERBOSE, GLUE_DIR,
|
||||
GLUE_SPEC, ROC_FILE, VERSION,
|
||||
};
|
||||
use roc_docs::generate_docs_html;
|
||||
use roc_error_macros::{internal_error, user_error};
|
||||
|
@ -54,6 +55,7 @@ fn main() -> io::Result<()> {
|
|||
None,
|
||||
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||
LinkType::Executable,
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
Ok(1)
|
||||
|
@ -69,6 +71,7 @@ fn main() -> io::Result<()> {
|
|||
None,
|
||||
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||
LinkType::Executable,
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
eprintln!("What .roc file do you want to run? Specify it at the end of the `roc run` command.");
|
||||
|
@ -95,6 +98,7 @@ fn main() -> io::Result<()> {
|
|||
None,
|
||||
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||
LinkType::Executable,
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
eprintln!("What .roc file do you want to build? Specify it at the end of the `roc run` command.");
|
||||
|
@ -113,8 +117,19 @@ fn main() -> io::Result<()> {
|
|||
false => CodeGenBackend::Llvm(LlvmBackendMode::BinaryGlue),
|
||||
};
|
||||
|
||||
let link_type = LinkType::Dylib;
|
||||
let target = Triple::host().into();
|
||||
let linking_strategy = default_linking_strategy(matches, link_type, target);
|
||||
|
||||
if !output_path.exists() || output_path.is_dir() {
|
||||
roc_glue::generate(input_path, output_path, spec_path, backend)
|
||||
roc_glue::generate(
|
||||
input_path,
|
||||
output_path,
|
||||
spec_path,
|
||||
backend,
|
||||
link_type,
|
||||
linking_strategy,
|
||||
)
|
||||
} else {
|
||||
eprintln!("`roc glue` must be given a directory to output into, because the glue might generate multiple files.");
|
||||
|
||||
|
@ -153,7 +168,7 @@ fn main() -> io::Result<()> {
|
|||
.and_then(|s| Target::from_str(s).ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
let verbose_and_time = matches.get_one::<bool>(roc_cli::FLAG_VERBOSE).unwrap();
|
||||
let verbose_and_time = matches.get_one::<bool>(FLAG_VERBOSE).unwrap();
|
||||
|
||||
let preprocessed_path = platform_path.with_file_name(target.prebuilt_surgical_host());
|
||||
let metadata_path = platform_path.with_file_name(target.metadata_file_name());
|
||||
|
@ -184,6 +199,7 @@ fn main() -> io::Result<()> {
|
|||
let out_path = matches
|
||||
.get_one::<OsString>(FLAG_OUTPUT)
|
||||
.map(OsString::as_ref);
|
||||
let verbose = matches.get_flag(FLAG_VERBOSE);
|
||||
|
||||
Ok(build(
|
||||
matches,
|
||||
|
@ -193,6 +209,7 @@ fn main() -> io::Result<()> {
|
|||
out_path,
|
||||
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||
link_type,
|
||||
verbose,
|
||||
)?)
|
||||
}
|
||||
Some((CMD_CHECK, matches)) => {
|
||||
|
@ -282,6 +299,7 @@ fn main() -> io::Result<()> {
|
|||
) {
|
||||
Ok((problems, total_time)) => {
|
||||
problems.print_error_warning_count(total_time);
|
||||
println!(".\n");
|
||||
Ok(problems.exit_code())
|
||||
}
|
||||
|
||||
|
@ -307,7 +325,25 @@ fn main() -> io::Result<()> {
|
|||
let root_path = matches.get_one::<PathBuf>(ROC_FILE).unwrap();
|
||||
let out_dir = matches.get_one::<OsString>(FLAG_OUTPUT).unwrap();
|
||||
|
||||
generate_docs_html(root_path.to_owned(), out_dir.as_ref());
|
||||
let maybe_root_dir: Option<String> = {
|
||||
if let Ok(root_dir) = std::env::var("ROC_DOCS_URL_ROOT") {
|
||||
// if the env var is set, it should override the flag for now
|
||||
// TODO -- confirm we no longer need this and remove
|
||||
// once docs are migrated to individual repositories and not roc website
|
||||
Some(root_dir)
|
||||
} else {
|
||||
matches
|
||||
.get_one::<Option<String>>(FLAG_DOCS_ROOT)
|
||||
.unwrap_or(&None)
|
||||
.clone()
|
||||
}
|
||||
};
|
||||
|
||||
generate_docs_html(
|
||||
root_path.to_owned(),
|
||||
out_dir.as_ref(),
|
||||
maybe_root_dir.clone(),
|
||||
);
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
@ -346,7 +382,10 @@ fn main() -> io::Result<()> {
|
|||
false => FormatMode::WriteToFile,
|
||||
}
|
||||
};
|
||||
let flags = MigrationFlags::new(migrate);
|
||||
let flags = MigrationFlags {
|
||||
snakify: migrate,
|
||||
parens_and_commas: migrate,
|
||||
};
|
||||
|
||||
if from_stdin && matches!(format_mode, FormatMode::WriteToFile) {
|
||||
eprintln!("When using the --stdin flag, either the --check or the --stdout flag must also be specified. (Otherwise, it's unclear what filename to write to!)");
|
||||
|
|
|
@ -1,107 +1,107 @@
|
|||
module [findPath, Model, initialModel, cheapestOpen, reconstructPath]
|
||||
module [find_path, Model, initial_model, cheapest_open, reconstruct_path]
|
||||
|
||||
import Quicksort
|
||||
|
||||
findPath = \costFn, moveFn, start, end ->
|
||||
astar costFn moveFn end (initialModel start)
|
||||
find_path = \cost_fn, move_fn, start, end ->
|
||||
astar(cost_fn, move_fn, end, initial_model(start))
|
||||
|
||||
Model position : {
|
||||
evaluated : Set position,
|
||||
openSet : Set position,
|
||||
open_set : Set position,
|
||||
costs : Dict position F64,
|
||||
cameFrom : Dict position position,
|
||||
came_from : Dict position position,
|
||||
} where position implements Hash & Eq
|
||||
|
||||
initialModel : position -> Model position where position implements Hash & Eq
|
||||
initialModel = \start -> {
|
||||
evaluated: Set.empty {},
|
||||
openSet: Set.single start,
|
||||
costs: Dict.single start 0,
|
||||
cameFrom: Dict.empty {},
|
||||
initial_model : position -> Model position where position implements Hash & Eq
|
||||
initial_model = \start -> {
|
||||
evaluated: Set.empty({}),
|
||||
open_set: Set.single(start),
|
||||
costs: Dict.single(start, 0),
|
||||
came_from: Dict.empty({}),
|
||||
}
|
||||
|
||||
cheapestOpen : (position -> F64), Model position -> Result position {} where position implements Hash & Eq
|
||||
cheapestOpen = \costFn, model ->
|
||||
model.openSet
|
||||
|> Set.toList
|
||||
|> List.keepOks
|
||||
(\position ->
|
||||
when Dict.get model.costs position is
|
||||
Err _ -> Err {}
|
||||
Ok cost -> Ok { cost: cost + costFn position, position }
|
||||
)
|
||||
|> Quicksort.sortBy .cost
|
||||
cheapest_open : (position -> F64), Model position -> Result position {} where position implements Hash & Eq
|
||||
cheapest_open = \cost_fn, model ->
|
||||
model.open_set
|
||||
|> Set.to_list
|
||||
|> List.keep_oks(
|
||||
\position ->
|
||||
when Dict.get(model.costs, position) is
|
||||
Err(_) -> Err({})
|
||||
Ok(cost) -> Ok({ cost: cost + cost_fn(position), position }),
|
||||
)
|
||||
|> Quicksort.sort_by(.cost)
|
||||
|> List.first
|
||||
|> Result.map .position
|
||||
|> Result.mapErr (\_ -> {})
|
||||
|> Result.map_ok(.position)
|
||||
|> Result.map_err(\_ -> {})
|
||||
|
||||
reconstructPath : Dict position position, position -> List position where position implements Hash & Eq
|
||||
reconstructPath = \cameFrom, goal ->
|
||||
when Dict.get cameFrom goal is
|
||||
Err _ -> []
|
||||
Ok next -> List.append (reconstructPath cameFrom next) goal
|
||||
reconstruct_path : Dict position position, position -> List position where position implements Hash & Eq
|
||||
reconstruct_path = \came_from, goal ->
|
||||
when Dict.get(came_from, goal) is
|
||||
Err(_) -> []
|
||||
Ok(next) -> List.append(reconstruct_path(came_from, next), goal)
|
||||
|
||||
updateCost : position, position, Model position -> Model position where position implements Hash & Eq
|
||||
updateCost = \current, neighbor, model ->
|
||||
newCameFrom =
|
||||
Dict.insert model.cameFrom neighbor current
|
||||
update_cost : position, position, Model position -> Model position where position implements Hash & Eq
|
||||
update_cost = \current, neighbor, model ->
|
||||
new_came_from =
|
||||
Dict.insert(model.came_from, neighbor, current)
|
||||
|
||||
newCosts =
|
||||
Dict.insert model.costs neighbor distanceTo
|
||||
new_costs =
|
||||
Dict.insert(model.costs, neighbor, distance_to)
|
||||
|
||||
distanceTo =
|
||||
reconstructPath newCameFrom neighbor
|
||||
distance_to =
|
||||
reconstruct_path(new_came_from, neighbor)
|
||||
|> List.len
|
||||
|> Num.toFrac
|
||||
|> Num.to_frac
|
||||
|
||||
newModel =
|
||||
new_model =
|
||||
{ model &
|
||||
costs: newCosts,
|
||||
cameFrom: newCameFrom,
|
||||
costs: new_costs,
|
||||
came_from: new_came_from,
|
||||
}
|
||||
|
||||
when Dict.get model.costs neighbor is
|
||||
Err _ ->
|
||||
newModel
|
||||
when Dict.get(model.costs, neighbor) is
|
||||
Err(_) ->
|
||||
new_model
|
||||
|
||||
Ok previousDistance ->
|
||||
if distanceTo < previousDistance then
|
||||
newModel
|
||||
Ok(previous_distance) ->
|
||||
if distance_to < previous_distance then
|
||||
new_model
|
||||
else
|
||||
model
|
||||
|
||||
astar : (position, position -> F64), (position -> Set position), position, Model position -> Result (List position) {} where position implements Hash & Eq
|
||||
astar = \costFn, moveFn, goal, model ->
|
||||
when cheapestOpen (\source -> costFn source goal) model is
|
||||
Err {} -> Err {}
|
||||
Ok current ->
|
||||
astar = \cost_fn, move_fn, goal, model ->
|
||||
when cheapest_open(\source -> cost_fn(source, goal), model) is
|
||||
Err({}) -> Err({})
|
||||
Ok(current) ->
|
||||
if current == goal then
|
||||
Ok (reconstructPath model.cameFrom goal)
|
||||
Ok(reconstruct_path(model.came_from, goal))
|
||||
else
|
||||
modelPopped =
|
||||
model_popped =
|
||||
{ model &
|
||||
openSet: Set.remove model.openSet current,
|
||||
evaluated: Set.insert model.evaluated current,
|
||||
open_set: Set.remove(model.open_set, current),
|
||||
evaluated: Set.insert(model.evaluated, current),
|
||||
}
|
||||
|
||||
neighbors =
|
||||
moveFn current
|
||||
move_fn(current)
|
||||
|
||||
newNeighbors =
|
||||
Set.difference neighbors modelPopped.evaluated
|
||||
new_neighbors =
|
||||
Set.difference(neighbors, model_popped.evaluated)
|
||||
|
||||
modelWithNeighbors : Model position
|
||||
modelWithNeighbors =
|
||||
modelPopped
|
||||
|> &openSet (Set.union modelPopped.openSet newNeighbors)
|
||||
model_with_neighbors : Model position
|
||||
model_with_neighbors =
|
||||
model_popped
|
||||
|> &open_set(Set.union(model_popped.open_set, new_neighbors))
|
||||
|
||||
walker : Model position, position -> Model position
|
||||
walker = \amodel, n -> updateCost current n amodel
|
||||
walker = \amodel, n -> update_cost(current, n, amodel)
|
||||
|
||||
modelWithCosts =
|
||||
Set.walk newNeighbors modelWithNeighbors walker
|
||||
model_with_costs =
|
||||
Set.walk(new_neighbors, model_with_neighbors, walker)
|
||||
|
||||
astar costFn moveFn goal modelWithCosts
|
||||
astar(cost_fn, move_fn, goal, model_with_costs)
|
||||
|
||||
# takeStep = \moveFn, _goal, model, current ->
|
||||
# modelPopped =
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
module [fromBytes, fromStr, toBytes, toStr]
|
||||
module [from_bytes, from_str, to_bytes, to_str]
|
||||
|
||||
import Base64.Decode
|
||||
import Base64.Encode
|
||||
|
||||
# base 64 encoding from a sequence of bytes
|
||||
fromBytes : List U8 -> Result Str [InvalidInput]
|
||||
fromBytes = \bytes ->
|
||||
when Base64.Decode.fromBytes bytes is
|
||||
Ok v ->
|
||||
Ok v
|
||||
from_bytes : List U8 -> Result Str [InvalidInput]
|
||||
from_bytes = \bytes ->
|
||||
when Base64.Decode.from_bytes(bytes) is
|
||||
Ok(v) ->
|
||||
Ok(v)
|
||||
|
||||
Err _ ->
|
||||
Err InvalidInput
|
||||
Err(_) ->
|
||||
Err(InvalidInput)
|
||||
|
||||
# base 64 encoding from a string
|
||||
fromStr : Str -> Result Str [InvalidInput]
|
||||
fromStr = \str ->
|
||||
fromBytes (Str.toUtf8 str)
|
||||
from_str : Str -> Result Str [InvalidInput]
|
||||
from_str = \str ->
|
||||
from_bytes(Str.to_utf8(str))
|
||||
|
||||
# base64-encode bytes to the original
|
||||
toBytes : Str -> Result (List U8) [InvalidInput]
|
||||
toBytes = \str ->
|
||||
Ok (Base64.Encode.toBytes str)
|
||||
to_bytes : Str -> Result (List U8) [InvalidInput]
|
||||
to_bytes = \str ->
|
||||
Ok(Base64.Encode.to_bytes(str))
|
||||
|
||||
toStr : Str -> Result Str [InvalidInput]
|
||||
toStr = \str ->
|
||||
when toBytes str is
|
||||
Ok bytes ->
|
||||
when Str.fromUtf8 bytes is
|
||||
Ok v ->
|
||||
Ok v
|
||||
to_str : Str -> Result Str [InvalidInput]
|
||||
to_str = \str ->
|
||||
when to_bytes(str) is
|
||||
Ok(bytes) ->
|
||||
when Str.from_utf8(bytes) is
|
||||
Ok(v) ->
|
||||
Ok(v)
|
||||
|
||||
Err _ ->
|
||||
Err InvalidInput
|
||||
Err(_) ->
|
||||
Err(InvalidInput)
|
||||
|
||||
Err _ ->
|
||||
Err InvalidInput
|
||||
Err(_) ->
|
||||
Err(InvalidInput)
|
||||
|
|
|
@ -1,86 +1,86 @@
|
|||
module [fromBytes]
|
||||
module [from_bytes]
|
||||
|
||||
import Bytes.Decode exposing [ByteDecoder, DecodeProblem]
|
||||
|
||||
fromBytes : List U8 -> Result Str DecodeProblem
|
||||
fromBytes = \bytes ->
|
||||
Bytes.Decode.decode bytes (decodeBase64 (List.len bytes))
|
||||
from_bytes : List U8 -> Result Str DecodeProblem
|
||||
from_bytes = \bytes ->
|
||||
Bytes.Decode.decode(bytes, decode_base64(List.len(bytes)))
|
||||
|
||||
decodeBase64 : U64 -> ByteDecoder Str
|
||||
decodeBase64 = \width -> Bytes.Decode.loop loopHelp { remaining: width, string: "" }
|
||||
decode_base64 : U64 -> ByteDecoder Str
|
||||
decode_base64 = \width -> Bytes.Decode.loop(loop_help, { remaining: width, string: "" })
|
||||
|
||||
loopHelp : { remaining : U64, string : Str } -> ByteDecoder (Bytes.Decode.Step { remaining : U64, string : Str } Str)
|
||||
loopHelp = \{ remaining, string } ->
|
||||
loop_help : { remaining : U64, string : Str } -> ByteDecoder (Bytes.Decode.Step { remaining : U64, string : Str } Str)
|
||||
loop_help = \{ remaining, string } ->
|
||||
if remaining >= 3 then
|
||||
Bytes.Decode.map3 Bytes.Decode.u8 Bytes.Decode.u8 Bytes.Decode.u8 \x, y, z ->
|
||||
Bytes.Decode.map3(Bytes.Decode.u8, Bytes.Decode.u8, Bytes.Decode.u8, \x, y, z ->
|
||||
a : U32
|
||||
a = Num.intCast x
|
||||
a = Num.int_cast(x)
|
||||
b : U32
|
||||
b = Num.intCast y
|
||||
b = Num.int_cast(y)
|
||||
c : U32
|
||||
c = Num.intCast z
|
||||
combined = Num.bitwiseOr (Num.bitwiseOr (Num.shiftLeftBy a 16) (Num.shiftLeftBy b 8)) c
|
||||
c = Num.int_cast(z)
|
||||
combined = Num.bitwise_or(Num.bitwise_or(Num.shift_left_by(a, 16), Num.shift_left_by(b, 8)), c)
|
||||
|
||||
Loop {
|
||||
Loop({
|
||||
remaining: remaining - 3,
|
||||
string: Str.concat string (bitsToChars combined 0),
|
||||
}
|
||||
string: Str.concat(string, bits_to_chars(combined, 0)),
|
||||
}))
|
||||
else if remaining == 0 then
|
||||
Bytes.Decode.succeed (Done string)
|
||||
Bytes.Decode.succeed(Done(string))
|
||||
else if remaining == 2 then
|
||||
Bytes.Decode.map2 Bytes.Decode.u8 Bytes.Decode.u8 \x, y ->
|
||||
Bytes.Decode.map2(Bytes.Decode.u8, Bytes.Decode.u8, \x, y ->
|
||||
|
||||
a : U32
|
||||
a = Num.intCast x
|
||||
a = Num.int_cast(x)
|
||||
b : U32
|
||||
b = Num.intCast y
|
||||
combined = Num.bitwiseOr (Num.shiftLeftBy a 16) (Num.shiftLeftBy b 8)
|
||||
b = Num.int_cast(y)
|
||||
combined = Num.bitwise_or(Num.shift_left_by(a, 16), Num.shift_left_by(b, 8))
|
||||
|
||||
Done (Str.concat string (bitsToChars combined 1))
|
||||
Done(Str.concat(string, bits_to_chars(combined, 1))))
|
||||
else
|
||||
# remaining = 1
|
||||
Bytes.Decode.map Bytes.Decode.u8 \x ->
|
||||
Bytes.Decode.map(Bytes.Decode.u8, \x ->
|
||||
|
||||
a : U32
|
||||
a = Num.intCast x
|
||||
a = Num.int_cast(x)
|
||||
|
||||
Done (Str.concat string (bitsToChars (Num.shiftLeftBy a 16) 2))
|
||||
Done(Str.concat(string, bits_to_chars(Num.shift_left_by(a, 16), 2))))
|
||||
|
||||
bitsToChars : U32, Int * -> Str
|
||||
bitsToChars = \bits, missing ->
|
||||
when Str.fromUtf8 (bitsToCharsHelp bits missing) is
|
||||
Ok str -> str
|
||||
Err _ -> ""
|
||||
bits_to_chars : U32, Int * -> Str
|
||||
bits_to_chars = \bits, missing ->
|
||||
when Str.from_utf8(bits_to_chars_help(bits, missing)) is
|
||||
Ok(str) -> str
|
||||
Err(_) -> ""
|
||||
|
||||
# Mask that can be used to get the lowest 6 bits of a binary number
|
||||
lowest6BitsMask : Int *
|
||||
lowest6BitsMask = 63
|
||||
lowest6_bits_mask : Int *
|
||||
lowest6_bits_mask = 63
|
||||
|
||||
bitsToCharsHelp : U32, Int * -> List U8
|
||||
bitsToCharsHelp = \bits, missing ->
|
||||
bits_to_chars_help : U32, Int * -> List U8
|
||||
bits_to_chars_help = \bits, missing ->
|
||||
# The input is 24 bits, which we have to partition into 4 6-bit segments. We achieve this by
|
||||
# shifting to the right by (a multiple of) 6 to remove unwanted bits on the right, then `Num.bitwiseAnd`
|
||||
# with `0b111111` (which is 2^6 - 1 or 63) (so, 6 1s) to remove unwanted bits on the left.
|
||||
# any 6-bit number is a valid base64 digit, so this is actually safe
|
||||
p =
|
||||
Num.shiftRightZfBy bits 18
|
||||
|> Num.intCast
|
||||
|> unsafeToChar
|
||||
Num.shift_right_zf_by(bits, 18)
|
||||
|> Num.int_cast
|
||||
|> unsafe_to_char
|
||||
|
||||
q =
|
||||
Num.bitwiseAnd (Num.shiftRightZfBy bits 12) lowest6BitsMask
|
||||
|> Num.intCast
|
||||
|> unsafeToChar
|
||||
Num.bitwise_and(Num.shift_right_zf_by(bits, 12), lowest6_bits_mask)
|
||||
|> Num.int_cast
|
||||
|> unsafe_to_char
|
||||
|
||||
r =
|
||||
Num.bitwiseAnd (Num.shiftRightZfBy bits 6) lowest6BitsMask
|
||||
|> Num.intCast
|
||||
|> unsafeToChar
|
||||
Num.bitwise_and(Num.shift_right_zf_by(bits, 6), lowest6_bits_mask)
|
||||
|> Num.int_cast
|
||||
|> unsafe_to_char
|
||||
|
||||
s =
|
||||
Num.bitwiseAnd bits lowest6BitsMask
|
||||
|> Num.intCast
|
||||
|> unsafeToChar
|
||||
Num.bitwise_and(bits, lowest6_bits_mask)
|
||||
|> Num.int_cast
|
||||
|> unsafe_to_char
|
||||
|
||||
equals : U8
|
||||
equals = 61
|
||||
|
@ -94,8 +94,8 @@ bitsToCharsHelp = \bits, missing ->
|
|||
[]
|
||||
|
||||
# Base64 index to character/digit
|
||||
unsafeToChar : U8 -> U8
|
||||
unsafeToChar = \n ->
|
||||
unsafe_to_char : U8 -> U8
|
||||
unsafe_to_char = \n ->
|
||||
if n <= 25 then
|
||||
# uppercase characters
|
||||
65 + n
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
module [toBytes]
|
||||
module [to_bytes]
|
||||
|
||||
import Bytes.Encode exposing [ByteEncoder]
|
||||
|
||||
InvalidChar : U8
|
||||
|
||||
# State : [None, One U8, Two U8, Three U8]
|
||||
toBytes : Str -> List U8
|
||||
toBytes = \str ->
|
||||
to_bytes : Str -> List U8
|
||||
to_bytes = \str ->
|
||||
str
|
||||
|> Str.toUtf8
|
||||
|> encodeChunks
|
||||
|> Str.to_utf8
|
||||
|> encode_chunks
|
||||
|> Bytes.Encode.sequence
|
||||
|> Bytes.Encode.encode
|
||||
|
||||
encodeChunks : List U8 -> List ByteEncoder
|
||||
encodeChunks = \bytes ->
|
||||
List.walk bytes { output: [], accum: None } folder
|
||||
|> encodeResidual
|
||||
encode_chunks : List U8 -> List ByteEncoder
|
||||
encode_chunks = \bytes ->
|
||||
List.walk(bytes, { output: [], accum: None }, folder)
|
||||
|> encode_residual
|
||||
|
||||
coerce : U64, a -> a
|
||||
coerce = \_, x -> x
|
||||
|
@ -24,113 +24,114 @@ coerce = \_, x -> x
|
|||
# folder : { output : List ByteEncoder, accum : State }, U8 -> { output : List ByteEncoder, accum : State }
|
||||
folder = \{ output, accum }, char ->
|
||||
when accum is
|
||||
Unreachable n -> coerce n { output, accum: Unreachable n }
|
||||
None -> { output, accum: One char }
|
||||
One a -> { output, accum: Two a char }
|
||||
Two a b -> { output, accum: Three a b char }
|
||||
Three a b c ->
|
||||
when encodeCharacters a b c char is
|
||||
Ok encoder ->
|
||||
Unreachable(n) -> coerce(n, { output, accum: Unreachable(n) })
|
||||
None -> { output, accum: One(char) }
|
||||
One(a) -> { output, accum: Two(a, char) }
|
||||
Two(a, b) -> { output, accum: Three(a, b, char) }
|
||||
Three(a, b, c) ->
|
||||
when encode_characters(a, b, c, char) is
|
||||
Ok(encoder) ->
|
||||
{
|
||||
output: List.append output encoder,
|
||||
output: List.append(output, encoder),
|
||||
accum: None,
|
||||
}
|
||||
|
||||
Err _ ->
|
||||
Err(_) ->
|
||||
{ output, accum: None }
|
||||
|
||||
# SGVs bG8g V29y bGQ=
|
||||
# encodeResidual : { output : List ByteEncoder, accum : State } -> List ByteEncoder
|
||||
encodeResidual = \{ output, accum } ->
|
||||
encode_residual = \{ output, accum } ->
|
||||
when accum is
|
||||
Unreachable _ -> output
|
||||
Unreachable(_) -> output
|
||||
None -> output
|
||||
One _ -> output
|
||||
Two a b ->
|
||||
when encodeCharacters a b equals equals is
|
||||
Ok encoder -> List.append output encoder
|
||||
Err _ -> output
|
||||
One(_) -> output
|
||||
Two(a, b) ->
|
||||
when encode_characters(a, b, equals, equals) is
|
||||
Ok(encoder) -> List.append(output, encoder)
|
||||
Err(_) -> output
|
||||
|
||||
Three a b c ->
|
||||
when encodeCharacters a b c equals is
|
||||
Ok encoder -> List.append output encoder
|
||||
Err _ -> output
|
||||
Three(a, b, c) ->
|
||||
when encode_characters(a, b, c, equals) is
|
||||
Ok(encoder) -> List.append(output, encoder)
|
||||
Err(_) -> output
|
||||
|
||||
equals : U8
|
||||
equals = 61
|
||||
|
||||
# Convert 4 characters to 24 bits (as an ByteEncoder)
|
||||
encodeCharacters : U8, U8, U8, U8 -> Result ByteEncoder InvalidChar
|
||||
encodeCharacters = \a, b, c, d ->
|
||||
if !(isValidChar a) then
|
||||
Err a
|
||||
else if !(isValidChar b) then
|
||||
Err b
|
||||
encode_characters : U8, U8, U8, U8 -> Result ByteEncoder InvalidChar
|
||||
encode_characters = \a, b, c, d ->
|
||||
if !(is_valid_char(a)) then
|
||||
Err(a)
|
||||
else if !(is_valid_char(b)) then
|
||||
Err(b)
|
||||
else
|
||||
# `=` is the padding character, and must be special-cased
|
||||
# only the `c` and `d` char are allowed to be padding
|
||||
n1 = unsafeConvertChar a
|
||||
n2 = unsafeConvertChar b
|
||||
n1 = unsafe_convert_char(a)
|
||||
n2 = unsafe_convert_char(b)
|
||||
|
||||
x : U32
|
||||
x = Num.intCast n1
|
||||
x = Num.int_cast(n1)
|
||||
|
||||
y : U32
|
||||
y = Num.intCast n2
|
||||
y = Num.int_cast(n2)
|
||||
|
||||
if d == equals then
|
||||
if c == equals then
|
||||
n = Num.bitwiseOr (Num.shiftLeftBy x 18) (Num.shiftLeftBy y 12)
|
||||
n = Num.bitwise_or(Num.shift_left_by(x, 18), Num.shift_left_by(y, 12))
|
||||
|
||||
# masking higher bits is not needed, Encode.unsignedInt8 ignores higher bits
|
||||
b1 : U8
|
||||
b1 = Num.intCast (Num.shiftRightBy n 16)
|
||||
b1 = Num.int_cast(Num.shift_right_by(n, 16))
|
||||
|
||||
Ok (Bytes.Encode.u8 b1)
|
||||
else if !(isValidChar c) then
|
||||
Err c
|
||||
Ok(Bytes.Encode.u8(b1))
|
||||
else if !(is_valid_char(c)) then
|
||||
Err(c)
|
||||
else
|
||||
n3 = unsafeConvertChar c
|
||||
n3 = unsafe_convert_char(c)
|
||||
|
||||
z : U32
|
||||
z = Num.intCast n3
|
||||
z = Num.int_cast(n3)
|
||||
|
||||
n = Num.bitwiseOr (Num.bitwiseOr (Num.shiftLeftBy x 18) (Num.shiftLeftBy y 12)) (Num.shiftLeftBy z 6)
|
||||
n = Num.bitwise_or(Num.bitwise_or(Num.shift_left_by(x, 18), Num.shift_left_by(y, 12)), Num.shift_left_by(z, 6))
|
||||
|
||||
combined : U16
|
||||
combined = Num.intCast (Num.shiftRightBy n 8)
|
||||
combined = Num.int_cast(Num.shift_right_by(n, 8))
|
||||
|
||||
Ok (Bytes.Encode.u16 BE combined)
|
||||
else if !(isValidChar d) then
|
||||
Err d
|
||||
Ok(Bytes.Encode.u16(BE, combined))
|
||||
else if !(is_valid_char(d)) then
|
||||
Err(d)
|
||||
else
|
||||
n3 = unsafeConvertChar c
|
||||
n4 = unsafeConvertChar d
|
||||
n3 = unsafe_convert_char(c)
|
||||
n4 = unsafe_convert_char(d)
|
||||
|
||||
z : U32
|
||||
z = Num.intCast n3
|
||||
z = Num.int_cast(n3)
|
||||
|
||||
w : U32
|
||||
w = Num.intCast n4
|
||||
w = Num.int_cast(n4)
|
||||
|
||||
n =
|
||||
Num.bitwiseOr
|
||||
(Num.bitwiseOr (Num.shiftLeftBy x 18) (Num.shiftLeftBy y 12))
|
||||
(Num.bitwiseOr (Num.shiftLeftBy z 6) w)
|
||||
Num.bitwise_or(
|
||||
Num.bitwise_or(Num.shift_left_by(x, 18), Num.shift_left_by(y, 12)),
|
||||
Num.bitwise_or(Num.shift_left_by(z, 6), w),
|
||||
)
|
||||
|
||||
b3 : U8
|
||||
b3 = Num.intCast n
|
||||
b3 = Num.int_cast(n)
|
||||
|
||||
combined : U16
|
||||
combined = Num.intCast (Num.shiftRightBy n 8)
|
||||
combined = Num.int_cast(Num.shift_right_by(n, 8))
|
||||
|
||||
Ok (Bytes.Encode.sequence [Bytes.Encode.u16 BE combined, Bytes.Encode.u8 b3])
|
||||
Ok(Bytes.Encode.sequence([Bytes.Encode.u16(BE, combined), Bytes.Encode.u8(b3)]))
|
||||
|
||||
# is the character a base64 digit?
|
||||
# The base16 digits are: A-Z, a-z, 0-1, '+' and '/'
|
||||
isValidChar : U8 -> Bool
|
||||
isValidChar = \c ->
|
||||
if isAlphaNum c then
|
||||
is_valid_char : U8 -> Bool
|
||||
is_valid_char = \c ->
|
||||
if is_alpha_num(c) then
|
||||
Bool.true
|
||||
else
|
||||
when c is
|
||||
|
@ -145,14 +146,14 @@ isValidChar = \c ->
|
|||
_ ->
|
||||
Bool.false
|
||||
|
||||
isAlphaNum : U8 -> Bool
|
||||
isAlphaNum = \key ->
|
||||
is_alpha_num : U8 -> Bool
|
||||
is_alpha_num = \key ->
|
||||
(key >= 48 && key <= 57) || (key >= 64 && key <= 90) || (key >= 97 && key <= 122)
|
||||
|
||||
# Convert a base64 character/digit to its index
|
||||
# See also [Wikipedia](https://en.wikipedia.org/wiki/Base64#Base64_table)
|
||||
unsafeConvertChar : U8 -> U8
|
||||
unsafeConvertChar = \key ->
|
||||
unsafe_convert_char : U8 -> U8
|
||||
unsafe_convert_char = \key ->
|
||||
if key >= 65 && key <= 90 then
|
||||
# A-Z
|
||||
key - 65
|
||||
|
|
|
@ -7,105 +7,111 @@ DecodeProblem : [OutOfBytes]
|
|||
ByteDecoder a := State -> [Good State a, Bad DecodeProblem]
|
||||
|
||||
decode : List U8, ByteDecoder a -> Result a DecodeProblem
|
||||
decode = \bytes, @ByteDecoder decoder ->
|
||||
when decoder { bytes, cursor: 0 } is
|
||||
Good _ value ->
|
||||
Ok value
|
||||
decode = \bytes, @ByteDecoder(decoder) ->
|
||||
when decoder({ bytes, cursor: 0 }) is
|
||||
Good(_, value) ->
|
||||
Ok(value)
|
||||
|
||||
Bad e ->
|
||||
Err e
|
||||
Bad(e) ->
|
||||
Err(e)
|
||||
|
||||
succeed : a -> ByteDecoder a
|
||||
succeed = \value -> @ByteDecoder \state -> Good state value
|
||||
succeed = \value -> @ByteDecoder(\state -> Good(state, value))
|
||||
|
||||
map : ByteDecoder a, (a -> b) -> ByteDecoder b
|
||||
map = \@ByteDecoder decoder, transform ->
|
||||
@ByteDecoder
|
||||
map = \@ByteDecoder(decoder), transform ->
|
||||
@ByteDecoder(
|
||||
\state ->
|
||||
when decoder state is
|
||||
Good state1 value ->
|
||||
Good state1 (transform value)
|
||||
when decoder(state) is
|
||||
Good(state1, value) ->
|
||||
Good(state1, transform(value))
|
||||
|
||||
Bad e ->
|
||||
Bad e
|
||||
Bad(e) ->
|
||||
Bad(e),
|
||||
)
|
||||
|
||||
map2 : ByteDecoder a, ByteDecoder b, (a, b -> c) -> ByteDecoder c
|
||||
map2 = \@ByteDecoder decoder1, @ByteDecoder decoder2, transform ->
|
||||
@ByteDecoder
|
||||
map2 = \@ByteDecoder(decoder1), @ByteDecoder(decoder2), transform ->
|
||||
@ByteDecoder(
|
||||
\state1 ->
|
||||
when decoder1 state1 is
|
||||
Good state2 a ->
|
||||
when decoder2 state2 is
|
||||
Good state3 b ->
|
||||
Good state3 (transform a b)
|
||||
when decoder1(state1) is
|
||||
Good(state2, a) ->
|
||||
when decoder2(state2) is
|
||||
Good(state3, b) ->
|
||||
Good(state3, transform(a, b))
|
||||
|
||||
Bad e ->
|
||||
Bad e
|
||||
Bad(e) ->
|
||||
Bad(e)
|
||||
|
||||
Bad e ->
|
||||
Bad e
|
||||
Bad(e) ->
|
||||
Bad(e),
|
||||
)
|
||||
|
||||
map3 : ByteDecoder a, ByteDecoder b, ByteDecoder c, (a, b, c -> d) -> ByteDecoder d
|
||||
map3 = \@ByteDecoder decoder1, @ByteDecoder decoder2, @ByteDecoder decoder3, transform ->
|
||||
@ByteDecoder
|
||||
map3 = \@ByteDecoder(decoder1), @ByteDecoder(decoder2), @ByteDecoder(decoder3), transform ->
|
||||
@ByteDecoder(
|
||||
\state1 ->
|
||||
when decoder1 state1 is
|
||||
Good state2 a ->
|
||||
when decoder2 state2 is
|
||||
Good state3 b ->
|
||||
when decoder3 state3 is
|
||||
Good state4 c ->
|
||||
Good state4 (transform a b c)
|
||||
when decoder1(state1) is
|
||||
Good(state2, a) ->
|
||||
when decoder2(state2) is
|
||||
Good(state3, b) ->
|
||||
when decoder3(state3) is
|
||||
Good(state4, c) ->
|
||||
Good(state4, transform(a, b, c))
|
||||
|
||||
Bad e ->
|
||||
Bad e
|
||||
Bad(e) ->
|
||||
Bad(e)
|
||||
|
||||
Bad e ->
|
||||
Bad e
|
||||
Bad(e) ->
|
||||
Bad(e)
|
||||
|
||||
Bad e ->
|
||||
Bad e
|
||||
Bad(e) ->
|
||||
Bad(e),
|
||||
)
|
||||
|
||||
after : ByteDecoder a, (a -> ByteDecoder b) -> ByteDecoder b
|
||||
after = \@ByteDecoder decoder, transform ->
|
||||
@ByteDecoder
|
||||
after = \@ByteDecoder(decoder), transform ->
|
||||
@ByteDecoder(
|
||||
\state ->
|
||||
when decoder state is
|
||||
Good state1 value ->
|
||||
(@ByteDecoder decoder1) = transform value
|
||||
when decoder(state) is
|
||||
Good(state1, value) ->
|
||||
@ByteDecoder(decoder1) = transform(value)
|
||||
|
||||
decoder1 state1
|
||||
decoder1(state1)
|
||||
|
||||
Bad e ->
|
||||
Bad e
|
||||
Bad(e) ->
|
||||
Bad(e),
|
||||
)
|
||||
|
||||
u8 : ByteDecoder U8
|
||||
u8 = @ByteDecoder
|
||||
u8 = @ByteDecoder(
|
||||
\state ->
|
||||
when List.get state.bytes state.cursor is
|
||||
Ok b ->
|
||||
Good { state & cursor: state.cursor + 1 } b
|
||||
when List.get(state.bytes, state.cursor) is
|
||||
Ok(b) ->
|
||||
Good({ state & cursor: state.cursor + 1 }, b)
|
||||
|
||||
Err _ ->
|
||||
Bad OutOfBytes
|
||||
Err(_) ->
|
||||
Bad(OutOfBytes),
|
||||
)
|
||||
|
||||
Step state b : [Loop state, Done b]
|
||||
|
||||
loop : (state -> ByteDecoder (Step state a)), state -> ByteDecoder a
|
||||
loop = \stepper, initial ->
|
||||
@ByteDecoder
|
||||
@ByteDecoder(
|
||||
\state ->
|
||||
loopHelp stepper initial state
|
||||
loop_help(stepper, initial, state),
|
||||
)
|
||||
|
||||
loopHelp = \stepper, accum, state ->
|
||||
(@ByteDecoder stepper1) = stepper accum
|
||||
loop_help = \stepper, accum, state ->
|
||||
@ByteDecoder(stepper1) = stepper(accum)
|
||||
|
||||
when stepper1 state is
|
||||
Good newState (Done value) ->
|
||||
Good newState value
|
||||
when stepper1(state) is
|
||||
Good(new_state, Done(value)) ->
|
||||
Good(new_state, value)
|
||||
|
||||
Good newState (Loop newAccum) ->
|
||||
loopHelp stepper newAccum newState
|
||||
Good(new_state, Loop(new_accum)) ->
|
||||
loop_help(stepper, new_accum, new_state)
|
||||
|
||||
Bad e ->
|
||||
Bad e
|
||||
Bad(e) ->
|
||||
Bad(e)
|
||||
|
|
|
@ -5,130 +5,132 @@ Endianness : [BE, LE]
|
|||
ByteEncoder : [Signed8 I8, Unsigned8 U8, Signed16 Endianness I16, Unsigned16 Endianness U16, Sequence U64 (List ByteEncoder), Bytes (List U8)]
|
||||
|
||||
u8 : U8 -> ByteEncoder
|
||||
u8 = \value -> Unsigned8 value
|
||||
u8 = \value -> Unsigned8(value)
|
||||
|
||||
empty : ByteEncoder
|
||||
empty =
|
||||
foo : List ByteEncoder
|
||||
foo = []
|
||||
|
||||
Sequence 0 foo
|
||||
Sequence(0, foo)
|
||||
|
||||
u16 : Endianness, U16 -> ByteEncoder
|
||||
u16 = \endianness, value -> Unsigned16 endianness value
|
||||
u16 = \endianness, value -> Unsigned16(endianness, value)
|
||||
|
||||
bytes : List U8 -> ByteEncoder
|
||||
bytes = \bs -> Bytes bs
|
||||
bytes = \bs -> Bytes(bs)
|
||||
|
||||
sequence : List ByteEncoder -> ByteEncoder
|
||||
sequence = \encoders ->
|
||||
Sequence (getWidths encoders 0) encoders
|
||||
Sequence(get_widths(encoders, 0), encoders)
|
||||
|
||||
getWidth : ByteEncoder -> U64
|
||||
getWidth = \encoder ->
|
||||
get_width : ByteEncoder -> U64
|
||||
get_width = \encoder ->
|
||||
when encoder is
|
||||
Signed8 _ -> 1
|
||||
Unsigned8 _ -> 1
|
||||
Signed16 _ _ -> 2
|
||||
Unsigned16 _ _ -> 2
|
||||
Signed8(_) -> 1
|
||||
Unsigned8(_) -> 1
|
||||
Signed16(_, _) -> 2
|
||||
Unsigned16(_, _) -> 2
|
||||
# Signed32 _ -> 4
|
||||
# Unsigned32 _ -> 4
|
||||
# Signed64 _ -> 8
|
||||
# Unsigned64 _ -> 8
|
||||
# Signed128 _ -> 16
|
||||
# Unsigned128 _ -> 16
|
||||
Sequence w _ -> w
|
||||
Bytes bs -> List.len bs
|
||||
Sequence(w, _) -> w
|
||||
Bytes(bs) -> List.len(bs)
|
||||
|
||||
getWidths : List ByteEncoder, U64 -> U64
|
||||
getWidths = \encoders, initial ->
|
||||
List.walk encoders initial \accum, encoder -> accum + getWidth encoder
|
||||
get_widths : List ByteEncoder, U64 -> U64
|
||||
get_widths = \encoders, initial ->
|
||||
List.walk(encoders, initial, \accum, encoder -> accum + get_width(encoder))
|
||||
|
||||
encode : ByteEncoder -> List U8
|
||||
encode = \encoder ->
|
||||
output = List.repeat 0 (getWidth encoder)
|
||||
output = List.repeat(0, get_width(encoder))
|
||||
|
||||
encodeHelp encoder 0 output
|
||||
encode_help(encoder, 0, output)
|
||||
|> .output
|
||||
|
||||
encodeHelp : ByteEncoder, U64, List U8 -> { output : List U8, offset : U64 }
|
||||
encodeHelp = \encoder, offset, output ->
|
||||
encode_help : ByteEncoder, U64, List U8 -> { output : List U8, offset : U64 }
|
||||
encode_help = \encoder, offset, output ->
|
||||
when encoder is
|
||||
Unsigned8 value ->
|
||||
Unsigned8(value) ->
|
||||
{
|
||||
output: List.set output offset value,
|
||||
output: List.set(output, offset, value),
|
||||
offset: offset + 1,
|
||||
}
|
||||
|
||||
Signed8 value ->
|
||||
Signed8(value) ->
|
||||
cast : U8
|
||||
cast = Num.intCast value
|
||||
cast = Num.int_cast(value)
|
||||
|
||||
{
|
||||
output: List.set output offset cast,
|
||||
output: List.set(output, offset, cast),
|
||||
offset: offset + 1,
|
||||
}
|
||||
|
||||
Unsigned16 endianness value ->
|
||||
Unsigned16(endianness, value) ->
|
||||
a : U8
|
||||
a = Num.intCast (Num.shiftRightBy value 8)
|
||||
a = Num.int_cast(Num.shift_right_by(value, 8))
|
||||
|
||||
b : U8
|
||||
b = Num.intCast value
|
||||
b = Num.int_cast(value)
|
||||
|
||||
newOutput =
|
||||
new_output =
|
||||
when endianness is
|
||||
BE ->
|
||||
output
|
||||
|> List.set (offset + 0) a
|
||||
|> List.set (offset + 1) b
|
||||
|> List.set((offset + 0), a)
|
||||
|> List.set((offset + 1), b)
|
||||
|
||||
LE ->
|
||||
output
|
||||
|> List.set (offset + 0) b
|
||||
|> List.set (offset + 1) a
|
||||
|> List.set((offset + 0), b)
|
||||
|> List.set((offset + 1), a)
|
||||
|
||||
{
|
||||
output: newOutput,
|
||||
output: new_output,
|
||||
offset: offset + 2,
|
||||
}
|
||||
|
||||
Signed16 endianness value ->
|
||||
Signed16(endianness, value) ->
|
||||
a : U8
|
||||
a = Num.intCast (Num.shiftRightBy value 8)
|
||||
a = Num.int_cast(Num.shift_right_by(value, 8))
|
||||
|
||||
b : U8
|
||||
b = Num.intCast value
|
||||
b = Num.int_cast(value)
|
||||
|
||||
newOutput =
|
||||
new_output =
|
||||
when endianness is
|
||||
BE ->
|
||||
output
|
||||
|> List.set (offset + 0) a
|
||||
|> List.set (offset + 1) b
|
||||
|> List.set((offset + 0), a)
|
||||
|> List.set((offset + 1), b)
|
||||
|
||||
LE ->
|
||||
output
|
||||
|> List.set (offset + 0) b
|
||||
|> List.set (offset + 1) a
|
||||
|> List.set((offset + 0), b)
|
||||
|> List.set((offset + 1), a)
|
||||
|
||||
{
|
||||
output: newOutput,
|
||||
output: new_output,
|
||||
offset: offset + 1,
|
||||
}
|
||||
|
||||
Bytes bs ->
|
||||
List.walk
|
||||
bs
|
||||
{ output, offset }
|
||||
Bytes(bs) ->
|
||||
List.walk(
|
||||
bs,
|
||||
{ output, offset },
|
||||
\accum, byte -> {
|
||||
offset: accum.offset + 1,
|
||||
output: List.set accum.output offset byte,
|
||||
}
|
||||
output: List.set(accum.output, offset, byte),
|
||||
},
|
||||
)
|
||||
|
||||
Sequence _ encoders ->
|
||||
List.walk
|
||||
encoders
|
||||
{ output, offset }
|
||||
Sequence(_, encoders) ->
|
||||
List.walk(
|
||||
encoders,
|
||||
{ output, offset },
|
||||
\accum, single ->
|
||||
encodeHelp single accum.offset accum.output
|
||||
encode_help(single, accum.offset, accum.output),
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module [text, asText]
|
||||
module [text, as_text]
|
||||
|
||||
text = "Hello, world!"
|
||||
|
||||
asText = Num.toStr
|
||||
as_text = Num.to_str
|
||||
|
|
|
@ -1,75 +1,75 @@
|
|||
module [sortBy, sortWith, show]
|
||||
module [sort_by, sort_with, show]
|
||||
|
||||
show : List I64 -> Str
|
||||
show = \list ->
|
||||
if List.isEmpty list then
|
||||
if List.is_empty(list) then
|
||||
"[]"
|
||||
else
|
||||
content =
|
||||
list
|
||||
|> List.map Num.toStr
|
||||
|> Str.joinWith ", "
|
||||
|> List.map(Num.to_str)
|
||||
|> Str.join_with(", ")
|
||||
|
||||
"[$(content)]"
|
||||
"[${content}]"
|
||||
|
||||
sortBy : List a, (a -> Num *) -> List a
|
||||
sortBy = \list, toComparable ->
|
||||
sortWith list (\x, y -> Num.compare (toComparable x) (toComparable y))
|
||||
sort_by : List a, (a -> Num *) -> List a
|
||||
sort_by = \list, to_comparable ->
|
||||
sort_with(list, \x, y -> Num.compare(to_comparable(x), to_comparable(y)))
|
||||
|
||||
Order a : a, a -> [LT, GT, EQ]
|
||||
|
||||
sortWith : List a, (a, a -> [LT, GT, EQ]) -> List a
|
||||
sortWith = \list, order ->
|
||||
n = List.len list
|
||||
sort_with : List a, (a, a -> [LT, GT, EQ]) -> List a
|
||||
sort_with = \list, order ->
|
||||
n = List.len(list)
|
||||
|
||||
quicksortHelp list order 0 (n - 1)
|
||||
quicksort_help(list, order, 0, (n - 1))
|
||||
|
||||
quicksortHelp : List a, Order a, U64, U64 -> List a
|
||||
quicksortHelp = \list, order, low, high ->
|
||||
quicksort_help : List a, Order a, U64, U64 -> List a
|
||||
quicksort_help = \list, order, low, high ->
|
||||
if low < high then
|
||||
when partition low high list order is
|
||||
Pair partitionIndex partitioned ->
|
||||
when partition(low, high, list, order) is
|
||||
Pair(partition_index, partitioned) ->
|
||||
partitioned
|
||||
|> quicksortHelp order low (Num.subSaturated partitionIndex 1)
|
||||
|> quicksortHelp order (partitionIndex + 1) high
|
||||
|> quicksort_help(order, low, Num.sub_saturated(partition_index, 1))
|
||||
|> quicksort_help(order, (partition_index + 1), high)
|
||||
else
|
||||
list
|
||||
|
||||
partition : U64, U64, List a, Order a -> [Pair U64 (List a)]
|
||||
partition = \low, high, initialList, order ->
|
||||
when List.get initialList high is
|
||||
Ok pivot ->
|
||||
when partitionHelp low low initialList order high pivot is
|
||||
Pair newI newList ->
|
||||
Pair newI (swap newI high newList)
|
||||
partition = \low, high, initial_list, order ->
|
||||
when List.get(initial_list, high) is
|
||||
Ok(pivot) ->
|
||||
when partition_help(low, low, initial_list, order, high, pivot) is
|
||||
Pair(new_i, new_list) ->
|
||||
Pair(new_i, swap(new_i, high, new_list))
|
||||
|
||||
Err _ ->
|
||||
Pair low initialList
|
||||
Err(_) ->
|
||||
Pair(low, initial_list)
|
||||
|
||||
partitionHelp : U64, U64, List c, Order c, U64, c -> [Pair U64 (List c)]
|
||||
partitionHelp = \i, j, list, order, high, pivot ->
|
||||
partition_help : U64, U64, List c, Order c, U64, c -> [Pair U64 (List c)]
|
||||
partition_help = \i, j, list, order, high, pivot ->
|
||||
if j < high then
|
||||
when List.get list j is
|
||||
Ok value ->
|
||||
when order value pivot is
|
||||
when List.get(list, j) is
|
||||
Ok(value) ->
|
||||
when order(value, pivot) is
|
||||
LT | EQ ->
|
||||
partitionHelp (i + 1) (j + 1) (swap i j list) order high pivot
|
||||
partition_help((i + 1), (j + 1), swap(i, j, list), order, high, pivot)
|
||||
|
||||
GT ->
|
||||
partitionHelp i (j + 1) list order high pivot
|
||||
partition_help(i, (j + 1), list, order, high, pivot)
|
||||
|
||||
Err _ ->
|
||||
Pair i list
|
||||
Err(_) ->
|
||||
Pair(i, list)
|
||||
else
|
||||
Pair i list
|
||||
Pair(i, list)
|
||||
|
||||
swap : U64, U64, List a -> List a
|
||||
swap = \i, j, list ->
|
||||
when Pair (List.get list i) (List.get list j) is
|
||||
Pair (Ok atI) (Ok atJ) ->
|
||||
when Pair(List.get(list, i), List.get(list, j)) is
|
||||
Pair(Ok(at_i), Ok(at_j)) ->
|
||||
list
|
||||
|> List.set i atJ
|
||||
|> List.set j atI
|
||||
|> List.set(i, at_j)
|
||||
|> List.set(j, at_i)
|
||||
|
||||
_ ->
|
||||
[]
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
app [main!] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
import pf.Host
|
||||
|
||||
# adapted from https://github.com/koka-lang/koka/blob/master/test/bench/haskell/cfold.hs
|
||||
main : Task {} []
|
||||
main =
|
||||
{ value, isError } = PlatformTasks.getInt!
|
||||
inputResult =
|
||||
if isError then
|
||||
Err GetIntError
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
{ value, is_error } = Host.get_int!({})
|
||||
input_result =
|
||||
if is_error then
|
||||
Err(GetIntError)
|
||||
else
|
||||
Ok value
|
||||
Ok(value)
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
e = mkExpr n 1 # original koka n = 20 (set `ulimit -s unlimited` to avoid stack overflow for n = 20)
|
||||
unoptimized = eval e
|
||||
optimized = eval (constFolding (reassoc e))
|
||||
when input_result is
|
||||
Ok(n) ->
|
||||
e = mk_expr(n, 1) # original koka n = 20 (set `ulimit -s unlimited` to avoid stack overflow for n = 20)
|
||||
unoptimized = eval(e)
|
||||
optimized = eval(const_folding(reassoc(e)))
|
||||
|
||||
unoptimized
|
||||
|> Num.toStr
|
||||
|> Str.concat " & "
|
||||
|> Str.concat (Num.toStr optimized)
|
||||
|> PlatformTasks.putLine
|
||||
|> Num.to_str
|
||||
|> Str.concat(" & ")
|
||||
|> Str.concat(Num.to_str(optimized))
|
||||
|> Host.put_line!
|
||||
|
||||
Err GetIntError ->
|
||||
PlatformTasks.putLine "Error: Failed to get Integer from stdin."
|
||||
Err(GetIntError) ->
|
||||
Host.put_line!("Error: Failed to get Integer from stdin.")
|
||||
|
||||
Expr : [
|
||||
Add Expr Expr,
|
||||
|
@ -34,97 +34,97 @@ Expr : [
|
|||
Var I64,
|
||||
]
|
||||
|
||||
mkExpr : I64, I64 -> Expr
|
||||
mkExpr = \n, v ->
|
||||
mk_expr : I64, I64 -> Expr
|
||||
mk_expr = \n, v ->
|
||||
when n is
|
||||
0 ->
|
||||
if v == 0 then Var 1 else Val v
|
||||
if v == 0 then Var(1) else Val(v)
|
||||
|
||||
_ ->
|
||||
Add (mkExpr (n - 1) (v + 1)) (mkExpr (n - 1) (max (v - 1) 0))
|
||||
Add(mk_expr((n - 1), (v + 1)), mk_expr((n - 1), max((v - 1), 0)))
|
||||
|
||||
max : I64, I64 -> I64
|
||||
max = \a, b -> if a > b then a else b
|
||||
|
||||
appendAdd : Expr, Expr -> Expr
|
||||
appendAdd = \e1, e2 ->
|
||||
append_add : Expr, Expr -> Expr
|
||||
append_add = \e1, e2 ->
|
||||
when e1 is
|
||||
Add a1 a2 ->
|
||||
Add a1 (appendAdd a2 e2)
|
||||
Add(a1, a2) ->
|
||||
Add(a1, append_add(a2, e2))
|
||||
|
||||
_ ->
|
||||
Add e1 e2
|
||||
Add(e1, e2)
|
||||
|
||||
appendMul : Expr, Expr -> Expr
|
||||
appendMul = \e1, e2 ->
|
||||
append_mul : Expr, Expr -> Expr
|
||||
append_mul = \e1, e2 ->
|
||||
when e1 is
|
||||
Mul a1 a2 ->
|
||||
Mul a1 (appendMul a2 e2)
|
||||
Mul(a1, a2) ->
|
||||
Mul(a1, append_mul(a2, e2))
|
||||
|
||||
_ ->
|
||||
Mul e1 e2
|
||||
Mul(e1, e2)
|
||||
|
||||
eval : Expr -> I64
|
||||
eval = \e ->
|
||||
when e is
|
||||
Var _ ->
|
||||
Var(_) ->
|
||||
0
|
||||
|
||||
Val v ->
|
||||
Val(v) ->
|
||||
v
|
||||
|
||||
Add l r ->
|
||||
eval l + eval r
|
||||
Add(l, r) ->
|
||||
eval(l) + eval(r)
|
||||
|
||||
Mul l r ->
|
||||
eval l * eval r
|
||||
Mul(l, r) ->
|
||||
eval(l) * eval(r)
|
||||
|
||||
reassoc : Expr -> Expr
|
||||
reassoc = \e ->
|
||||
when e is
|
||||
Add e1 e2 ->
|
||||
x1 = reassoc e1
|
||||
x2 = reassoc e2
|
||||
Add(e1, e2) ->
|
||||
x1 = reassoc(e1)
|
||||
x2 = reassoc(e2)
|
||||
|
||||
appendAdd x1 x2
|
||||
append_add(x1, x2)
|
||||
|
||||
Mul e1 e2 ->
|
||||
x1 = reassoc e1
|
||||
x2 = reassoc e2
|
||||
Mul(e1, e2) ->
|
||||
x1 = reassoc(e1)
|
||||
x2 = reassoc(e2)
|
||||
|
||||
appendMul x1 x2
|
||||
append_mul(x1, x2)
|
||||
|
||||
_ ->
|
||||
e
|
||||
|
||||
constFolding : Expr -> Expr
|
||||
constFolding = \e ->
|
||||
const_folding : Expr -> Expr
|
||||
const_folding = \e ->
|
||||
when e is
|
||||
Add e1 e2 ->
|
||||
x1 = constFolding e1
|
||||
x2 = constFolding e2
|
||||
Add(e1, e2) ->
|
||||
x1 = const_folding(e1)
|
||||
x2 = const_folding(e2)
|
||||
|
||||
when x1 is
|
||||
Val a ->
|
||||
Val(a) ->
|
||||
when x2 is
|
||||
Val b -> Val (a + b)
|
||||
Add (Val b) x | Add x (Val b) -> Add (Val (a + b)) x
|
||||
_ -> Add x1 x2
|
||||
Val(b) -> Val((a + b))
|
||||
Add(Val(b), x) | Add(x, Val(b)) -> Add(Val((a + b)), x)
|
||||
_ -> Add(x1, x2)
|
||||
|
||||
_ -> Add x1 x2
|
||||
_ -> Add(x1, x2)
|
||||
|
||||
Mul e1 e2 ->
|
||||
x1 = constFolding e1
|
||||
x2 = constFolding e2
|
||||
Mul(e1, e2) ->
|
||||
x1 = const_folding(e1)
|
||||
x2 = const_folding(e2)
|
||||
|
||||
when x1 is
|
||||
Val a ->
|
||||
Val(a) ->
|
||||
when x2 is
|
||||
Val b -> Val (a * b)
|
||||
Mul (Val b) x | Mul x (Val b) -> Mul (Val (a * b)) x
|
||||
_ -> Mul x1 x2
|
||||
Val(b) -> Val((a * b))
|
||||
Mul(Val(b), x) | Mul(x, Val(b)) -> Mul(Val((a * b)), x)
|
||||
_ -> Mul(x1, x2)
|
||||
|
||||
_ -> Mul x1 x2
|
||||
_ -> Mul(x1, x2)
|
||||
|
||||
_ ->
|
||||
e
|
||||
|
|
|
@ -1,48 +1,50 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
app [main!] { pf: platform "platform/main.roc" }
|
||||
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
closure1({})
|
||||
|> Result.try(closure2)
|
||||
|> Result.try(closure3)
|
||||
|> Result.try(closure4)
|
||||
|> Result.with_default({})
|
||||
|
||||
main : Task {} []
|
||||
main =
|
||||
closure1 {}
|
||||
|> Task.await (\_ -> closure2 {})
|
||||
|> Task.await (\_ -> closure3 {})
|
||||
|> Task.await (\_ -> closure4 {})
|
||||
# ---
|
||||
closure1 : {} -> Task {} []
|
||||
closure1 : {} -> Result {} []
|
||||
closure1 = \_ ->
|
||||
Task.ok (foo toUnitBorrowed "a long string such that it's malloced")
|
||||
|> Task.map \_ -> {}
|
||||
Ok(foo(to_unit_borrowed, "a long string such that it's malloced"))
|
||||
|> Result.map_ok(\_ -> {})
|
||||
|
||||
toUnitBorrowed = \x -> Str.countUtf8Bytes x
|
||||
to_unit_borrowed = \x -> Str.count_utf8_bytes(x)
|
||||
|
||||
foo = \f, x -> f x
|
||||
foo = \f, x -> f(x)
|
||||
|
||||
# ---
|
||||
closure2 : {} -> Task {} []
|
||||
closure2 : {} -> Result {} []
|
||||
closure2 = \_ ->
|
||||
x : Str
|
||||
x = "a long string such that it's malloced"
|
||||
|
||||
Task.ok {}
|
||||
|> Task.map (\_ -> x)
|
||||
|> Task.map toUnit
|
||||
Ok({})
|
||||
|> Result.map_ok(\_ -> x)
|
||||
|> Result.map_ok(to_unit)
|
||||
|
||||
toUnit = \_ -> {}
|
||||
to_unit = \_ -> {}
|
||||
|
||||
# # ---
|
||||
closure3 : {} -> Task {} []
|
||||
closure3 : {} -> Result {} []
|
||||
closure3 = \_ ->
|
||||
x : Str
|
||||
x = "a long string such that it's malloced"
|
||||
|
||||
Task.ok {}
|
||||
|> Task.await (\_ -> Task.ok x |> Task.map (\_ -> {}))
|
||||
Ok({})
|
||||
|> Result.try(\_ -> Ok(x) |> Result.map_ok(\_ -> {}))
|
||||
|
||||
# # ---
|
||||
closure4 : {} -> Task {} []
|
||||
closure4 : {} -> Result {} []
|
||||
closure4 = \_ ->
|
||||
x : Str
|
||||
x = "a long string such that it's malloced"
|
||||
|
||||
Task.ok {}
|
||||
|> Task.await (\_ -> Task.ok x)
|
||||
|> Task.map (\_ -> {})
|
||||
Ok({})
|
||||
|> Result.try(\_ -> Ok(x))
|
||||
|> Result.map_ok(\_ -> {})
|
||||
|
|
|
@ -1,51 +1,49 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
app [main!] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
import pf.Host
|
||||
|
||||
# based on: https://github.com/koka-lang/koka/blob/master/test/bench/haskell/deriv.hs
|
||||
IO a : Task a []
|
||||
|
||||
main : Task {} []
|
||||
main =
|
||||
{ value, isError } = PlatformTasks.getInt!
|
||||
inputResult =
|
||||
if isError then
|
||||
Err GetIntError
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
{ value, is_error } = Host.get_int!({})
|
||||
input_result =
|
||||
if is_error then
|
||||
Err(GetIntError)
|
||||
else
|
||||
Ok value
|
||||
Ok(value)
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
when input_result is
|
||||
Ok(n) ->
|
||||
x : Expr
|
||||
x = Var "x"
|
||||
x = Var("x")
|
||||
|
||||
f : Expr
|
||||
f = pow x x
|
||||
f = pow(x, x)
|
||||
|
||||
nest deriv n f # original koka n = 10
|
||||
|> Task.map \_ -> {}
|
||||
_ = nest!(deriv!, n, f) # original koka n = 10
|
||||
{}
|
||||
|
||||
Err GetIntError ->
|
||||
PlatformTasks.putLine "Error: Failed to get Integer from stdin."
|
||||
Err(GetIntError) ->
|
||||
Host.put_line!("Error: Failed to get Integer from stdin.")
|
||||
|
||||
nestHelp : I64, (I64, Expr -> IO Expr), I64, Expr -> IO Expr
|
||||
nestHelp = \s, f, m, x ->
|
||||
nest_help! : I64, (I64, Expr => Expr), I64, Expr => Expr
|
||||
nest_help! = \s, f!, m, x ->
|
||||
when m is
|
||||
0 -> Task.ok x
|
||||
0 -> x
|
||||
_ ->
|
||||
w = f! (s - m) x
|
||||
nestHelp s f (m - 1) w
|
||||
w = f!((s - m), x)
|
||||
nest_help!(s, f!, (m - 1), w)
|
||||
|
||||
nest : (I64, Expr -> IO Expr), I64, Expr -> IO Expr
|
||||
nest = \f, n, e -> nestHelp n f n e
|
||||
nest! : (I64, Expr => Expr), I64, Expr => Expr
|
||||
nest! = \f!, n, e -> nest_help!(n, f!, n, e)
|
||||
|
||||
Expr : [Val I64, Var Str, Add Expr Expr, Mul Expr Expr, Pow Expr Expr, Ln Expr]
|
||||
|
||||
divmod : I64, I64 -> Result { div : I64, mod : I64 } [DivByZero]
|
||||
divmod = \l, r ->
|
||||
when Pair (Num.divTruncChecked l r) (Num.remChecked l r) is
|
||||
Pair (Ok div) (Ok mod) -> Ok { div, mod }
|
||||
_ -> Err DivByZero
|
||||
when Pair(Num.div_trunc_checked(l, r), Num.rem_checked(l, r)) is
|
||||
Pair(Ok(div), Ok(mod)) -> Ok({ div, mod })
|
||||
_ -> Err(DivByZero)
|
||||
|
||||
pown : I64, I64 -> I64
|
||||
pown = \a, n ->
|
||||
|
@ -53,119 +51,119 @@ pown = \a, n ->
|
|||
0 -> 1
|
||||
1 -> a
|
||||
_ ->
|
||||
when divmod n 2 is
|
||||
Ok { div, mod } ->
|
||||
b = pown a div
|
||||
when divmod(n, 2) is
|
||||
Ok({ div, mod }) ->
|
||||
b = pown(a, div)
|
||||
|
||||
b * b * (if mod == 0 then 1 else a)
|
||||
|
||||
Err DivByZero ->
|
||||
Err(DivByZero) ->
|
||||
-1
|
||||
|
||||
add : Expr, Expr -> Expr
|
||||
add = \a, b ->
|
||||
when Pair a b is
|
||||
Pair (Val n) (Val m) ->
|
||||
Val (n + m)
|
||||
when Pair(a, b) is
|
||||
Pair(Val(n), Val(m)) ->
|
||||
Val((n + m))
|
||||
|
||||
Pair (Val 0) f ->
|
||||
Pair(Val(0), f) ->
|
||||
f
|
||||
|
||||
Pair f (Val 0) ->
|
||||
Pair(f, Val(0)) ->
|
||||
f
|
||||
|
||||
Pair f (Val n) ->
|
||||
add (Val n) f
|
||||
Pair(f, Val(n)) ->
|
||||
add(Val(n), f)
|
||||
|
||||
Pair (Val n) (Add (Val m) f) ->
|
||||
add (Val (n + m)) f
|
||||
Pair(Val(n), Add(Val(m), f)) ->
|
||||
add(Val((n + m)), f)
|
||||
|
||||
Pair f (Add (Val n) g) ->
|
||||
add (Val n) (add f g)
|
||||
Pair(f, Add(Val(n), g)) ->
|
||||
add(Val(n), add(f, g))
|
||||
|
||||
Pair (Add f g) h ->
|
||||
add f (add g h)
|
||||
Pair(Add(f, g), h) ->
|
||||
add(f, add(g, h))
|
||||
|
||||
Pair f g ->
|
||||
Add f g
|
||||
Pair(f, g) ->
|
||||
Add(f, g)
|
||||
|
||||
mul : Expr, Expr -> Expr
|
||||
mul = \a, b ->
|
||||
when Pair a b is
|
||||
Pair (Val n) (Val m) ->
|
||||
Val (n * m)
|
||||
when Pair(a, b) is
|
||||
Pair(Val(n), Val(m)) ->
|
||||
Val((n * m))
|
||||
|
||||
Pair (Val 0) _ ->
|
||||
Val 0
|
||||
Pair(Val(0), _) ->
|
||||
Val(0)
|
||||
|
||||
Pair _ (Val 0) ->
|
||||
Val 0
|
||||
Pair(_, Val(0)) ->
|
||||
Val(0)
|
||||
|
||||
Pair (Val 1) f ->
|
||||
Pair(Val(1), f) ->
|
||||
f
|
||||
|
||||
Pair f (Val 1) ->
|
||||
Pair(f, Val(1)) ->
|
||||
f
|
||||
|
||||
Pair f (Val n) ->
|
||||
mul (Val n) f
|
||||
Pair(f, Val(n)) ->
|
||||
mul(Val(n), f)
|
||||
|
||||
Pair (Val n) (Mul (Val m) f) ->
|
||||
mul (Val (n * m)) f
|
||||
Pair(Val(n), Mul(Val(m), f)) ->
|
||||
mul(Val((n * m)), f)
|
||||
|
||||
Pair f (Mul (Val n) g) ->
|
||||
mul (Val n) (mul f g)
|
||||
Pair(f, Mul(Val(n), g)) ->
|
||||
mul(Val(n), mul(f, g))
|
||||
|
||||
Pair (Mul f g) h ->
|
||||
mul f (mul g h)
|
||||
Pair(Mul(f, g), h) ->
|
||||
mul(f, mul(g, h))
|
||||
|
||||
Pair f g ->
|
||||
Mul f g
|
||||
Pair(f, g) ->
|
||||
Mul(f, g)
|
||||
|
||||
pow : Expr, Expr -> Expr
|
||||
pow = \a, b ->
|
||||
when Pair a b is
|
||||
Pair (Val m) (Val n) -> Val (pown m n)
|
||||
Pair _ (Val 0) -> Val 1
|
||||
Pair f (Val 1) -> f
|
||||
Pair (Val 0) _ -> Val 0
|
||||
Pair f g -> Pow f g
|
||||
when Pair(a, b) is
|
||||
Pair(Val(m), Val(n)) -> Val(pown(m, n))
|
||||
Pair(_, Val(0)) -> Val(1)
|
||||
Pair(f, Val(1)) -> f
|
||||
Pair(Val(0), _) -> Val(0)
|
||||
Pair(f, g) -> Pow(f, g)
|
||||
|
||||
ln : Expr -> Expr
|
||||
ln = \f ->
|
||||
when f is
|
||||
Val 1 -> Val 0
|
||||
_ -> Ln f
|
||||
Val(1) -> Val(0)
|
||||
_ -> Ln(f)
|
||||
|
||||
d : Str, Expr -> Expr
|
||||
d = \x, expr ->
|
||||
when expr is
|
||||
Val _ -> Val 0
|
||||
Var y -> if x == y then Val 1 else Val 0
|
||||
Add f g -> add (d x f) (d x g)
|
||||
Mul f g -> add (mul f (d x g)) (mul g (d x f))
|
||||
Pow f g ->
|
||||
mul (pow f g) (add (mul (mul g (d x f)) (pow f (Val (-1)))) (mul (ln f) (d x g)))
|
||||
Val(_) -> Val(0)
|
||||
Var(y) -> if x == y then Val(1) else Val(0)
|
||||
Add(f, g) -> add(d(x, f), d(x, g))
|
||||
Mul(f, g) -> add(mul(f, d(x, g)), mul(g, d(x, f)))
|
||||
Pow(f, g) ->
|
||||
mul(pow(f, g), add(mul(mul(g, d(x, f)), pow(f, Val(-1))), mul(ln(f), d(x, g))))
|
||||
|
||||
Ln f ->
|
||||
mul (d x f) (pow f (Val (-1)))
|
||||
Ln(f) ->
|
||||
mul(d(x, f), pow(f, Val(-1)))
|
||||
|
||||
count : Expr -> I64
|
||||
count = \expr ->
|
||||
when expr is
|
||||
Val _ -> 1
|
||||
Var _ -> 1
|
||||
Add f g -> count f + count g
|
||||
Mul f g -> count f + count g
|
||||
Pow f g -> count f + count g
|
||||
Ln f -> count f
|
||||
Val(_) -> 1
|
||||
Var(_) -> 1
|
||||
Add(f, g) -> count(f) + count(g)
|
||||
Mul(f, g) -> count(f) + count(g)
|
||||
Pow(f, g) -> count(f) + count(g)
|
||||
Ln(f) -> count(f)
|
||||
|
||||
deriv : I64, Expr -> IO Expr
|
||||
deriv = \i, f ->
|
||||
fprime = d "x" f
|
||||
deriv! : I64, Expr => Expr
|
||||
deriv! = \i, f ->
|
||||
fprime = d("x", f)
|
||||
line =
|
||||
Num.toStr (i + 1)
|
||||
|> Str.concat " count: "
|
||||
|> Str.concat (Num.toStr (count fprime))
|
||||
PlatformTasks.putLine! line
|
||||
Task.ok fprime
|
||||
Num.to_str((i + 1))
|
||||
|> Str.concat(" count: ")
|
||||
|> Str.concat(Num.to_str(count(fprime)))
|
||||
Host.put_line!(line)
|
||||
fprime
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
app [main!] { pf: platform "platform/main.roc" }
|
||||
|
||||
import Issue2279Help
|
||||
import pf.PlatformTasks
|
||||
import pf.Host
|
||||
|
||||
main =
|
||||
main! = \{} ->
|
||||
text =
|
||||
if Bool.true then
|
||||
Issue2279Help.text
|
||||
else
|
||||
Issue2279Help.asText 42
|
||||
Issue2279Help.as_text(42)
|
||||
|
||||
PlatformTasks.putLine text
|
||||
Host.put_line!(text)
|
||||
|
|
|
@ -1,66 +1,66 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
app [main!] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
import pf.Host
|
||||
|
||||
main : Task {} []
|
||||
main =
|
||||
{ value, isError } = PlatformTasks.getInt!
|
||||
inputResult =
|
||||
if isError then
|
||||
Err GetIntError
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
{ value, is_error } = Host.get_int!({})
|
||||
input_result =
|
||||
if is_error then
|
||||
Err(GetIntError)
|
||||
else
|
||||
Ok value
|
||||
Ok(value)
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
queens n # original koka 13
|
||||
|> Num.toStr
|
||||
|> PlatformTasks.putLine
|
||||
when input_result is
|
||||
Ok(n) ->
|
||||
queens(n) # original koka 13
|
||||
|> Num.to_str
|
||||
|> Host.put_line!
|
||||
|
||||
Err GetIntError ->
|
||||
PlatformTasks.putLine "Error: Failed to get Integer from stdin."
|
||||
Err(GetIntError) ->
|
||||
Host.put_line!("Error: Failed to get Integer from stdin.")
|
||||
|
||||
ConsList a : [Nil, Cons a (ConsList a)]
|
||||
|
||||
queens = \n -> length (findSolutions n n)
|
||||
queens = \n -> length(find_solutions(n, n))
|
||||
|
||||
findSolutions = \n, k ->
|
||||
find_solutions = \n, k ->
|
||||
if k <= 0 then
|
||||
# should we use U64 as input type here instead?
|
||||
Cons Nil Nil
|
||||
Cons(Nil, Nil)
|
||||
else
|
||||
extend n Nil (findSolutions n (k - 1))
|
||||
extend(n, Nil, find_solutions(n, (k - 1)))
|
||||
|
||||
extend = \n, acc, solutions ->
|
||||
when solutions is
|
||||
Nil -> acc
|
||||
Cons soln rest -> extend n (appendSafe n soln acc) rest
|
||||
Cons(soln, rest) -> extend(n, append_safe(n, soln, acc), rest)
|
||||
|
||||
appendSafe : I64, ConsList I64, ConsList (ConsList I64) -> ConsList (ConsList I64)
|
||||
appendSafe = \k, soln, solns ->
|
||||
append_safe : I64, ConsList I64, ConsList (ConsList I64) -> ConsList (ConsList I64)
|
||||
append_safe = \k, soln, solns ->
|
||||
if k <= 0 then
|
||||
solns
|
||||
else if safe k 1 soln then
|
||||
appendSafe (k - 1) soln (Cons (Cons k soln) solns)
|
||||
else if safe(k, 1, soln) then
|
||||
append_safe((k - 1), soln, Cons(Cons(k, soln), solns))
|
||||
else
|
||||
appendSafe (k - 1) soln solns
|
||||
append_safe((k - 1), soln, solns)
|
||||
|
||||
safe : I64, I64, ConsList I64 -> Bool
|
||||
safe = \queen, diagonal, xs ->
|
||||
when xs is
|
||||
Nil -> Bool.true
|
||||
Cons q t ->
|
||||
Cons(q, t) ->
|
||||
if queen != q && queen != q + diagonal && queen != q - diagonal then
|
||||
safe queen (diagonal + 1) t
|
||||
safe(queen, (diagonal + 1), t)
|
||||
else
|
||||
Bool.false
|
||||
|
||||
length : ConsList a -> I64
|
||||
length = \xs ->
|
||||
lengthHelp xs 0
|
||||
length_help(xs, 0)
|
||||
|
||||
lengthHelp : ConsList a, I64 -> I64
|
||||
lengthHelp = \foobar, acc ->
|
||||
length_help : ConsList a, I64 -> I64
|
||||
length_help = \foobar, acc ->
|
||||
when foobar is
|
||||
Cons _ lrest -> lengthHelp lrest (1 + acc)
|
||||
Cons(_, lrest) -> length_help(lrest, (1 + acc))
|
||||
Nil -> acc
|
||||
|
|
9
crates/cli/tests/benchmarks/platform/Host.roc
Normal file
9
crates/cli/tests/benchmarks/platform/Host.roc
Normal file
|
@ -0,0 +1,9 @@
|
|||
hosted Host
|
||||
exposes [put_line!, put_int!, get_int!]
|
||||
imports []
|
||||
|
||||
put_line! : Str => {}
|
||||
|
||||
put_int! : I64 => {}
|
||||
|
||||
get_int! : {} => { value : I64, is_error : Bool }
|
|
@ -1,9 +0,0 @@
|
|||
hosted PlatformTasks
|
||||
exposes [putLine, putInt, getInt]
|
||||
imports []
|
||||
|
||||
putLine : Str -> Task {} *
|
||||
|
||||
putInt : I64 -> Task {} *
|
||||
|
||||
getInt : Task { value : I64, isError : Bool } *
|
|
@ -1,3 +1,4 @@
|
|||
app [main] { pf: platform "main.roc" }
|
||||
app [main!] { pf: platform "main.roc" }
|
||||
|
||||
main = Task.ok {}
|
||||
main! : {} => {}
|
||||
main! = \{} -> {}
|
||||
|
|
|
@ -10,11 +10,7 @@ const maxInt = std.math.maxInt;
|
|||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
extern fn roc__mainForHost_1_exposed_generic([*]u8) void;
|
||||
extern fn roc__mainForHost_1_exposed_size() i64;
|
||||
extern fn roc__mainForHost_0_caller(*const u8, [*]u8, [*]u8) void;
|
||||
extern fn roc__mainForHost_0_size() i64;
|
||||
extern fn roc__mainForHost_0_result_size() i64;
|
||||
extern fn roc__main_for_host_1_exposed() void;
|
||||
|
||||
const Align = 2 * @alignOf(usize);
|
||||
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
|
||||
|
@ -112,48 +108,12 @@ comptime {
|
|||
const Unit = extern struct {};
|
||||
|
||||
pub export fn main() u8 {
|
||||
// The size might be zero; if so, make it at least 8 so that we don't have a nullptr
|
||||
const size = @max(@as(usize, @intCast(roc__mainForHost_1_exposed_size())), 8);
|
||||
const raw_output = roc_alloc(@as(usize, @intCast(size)), @alignOf(u64)) orelse {
|
||||
std.log.err("Memory allocation failed", .{});
|
||||
return 1;
|
||||
};
|
||||
const output = @as([*]u8, @ptrCast(raw_output));
|
||||
|
||||
defer {
|
||||
roc_dealloc(raw_output, @alignOf(u64));
|
||||
}
|
||||
|
||||
roc__mainForHost_1_exposed_generic(output);
|
||||
|
||||
const closure_data_pointer = @as([*]u8, @ptrCast(output));
|
||||
|
||||
call_the_closure(closure_data_pointer);
|
||||
roc__main_for_host_1_exposed();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn call_the_closure(closure_data_pointer: [*]u8) void {
|
||||
const allocator = std.heap.page_allocator;
|
||||
|
||||
// The size might be zero; if so, make it at least 8 so that we don't have a nullptr
|
||||
const size = @max(roc__mainForHost_0_result_size(), 8);
|
||||
const raw_output = allocator.alignedAlloc(u8, @alignOf(u64), @as(usize, @intCast(size))) catch unreachable;
|
||||
const output = @as([*]u8, @ptrCast(raw_output));
|
||||
|
||||
defer {
|
||||
allocator.free(raw_output);
|
||||
}
|
||||
|
||||
const flags: u8 = 0;
|
||||
|
||||
roc__mainForHost_0_caller(&flags, closure_data_pointer, output);
|
||||
|
||||
// The closure returns result, nothing interesting to do with it
|
||||
return;
|
||||
}
|
||||
|
||||
pub export fn roc_fx_putInt(int: i64) i64 {
|
||||
pub export fn roc_fx_put_int(int: i64) i64 {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
|
||||
stdout.print("{d}", .{int}) catch unreachable;
|
||||
|
@ -163,7 +123,7 @@ pub export fn roc_fx_putInt(int: i64) i64 {
|
|||
return 0;
|
||||
}
|
||||
|
||||
export fn roc_fx_putLine(rocPath: *str.RocStr) callconv(.C) void {
|
||||
export fn roc_fx_put_line(rocPath: *str.RocStr) callconv(.C) void {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
|
||||
for (rocPath.asSlice()) |char| {
|
||||
|
@ -180,14 +140,14 @@ const GetInt = extern struct {
|
|||
|
||||
comptime {
|
||||
if (@sizeOf(usize) == 8) {
|
||||
@export(roc_fx_getInt_64bit, .{ .name = "roc_fx_getInt" });
|
||||
@export(roc_fx_get_int_64bit, .{ .name = "roc_fx_get_int" });
|
||||
} else {
|
||||
@export(roc_fx_getInt_32bit, .{ .name = "roc_fx_getInt" });
|
||||
@export(roc_fx_get_int_32bit, .{ .name = "roc_fx_get_int" });
|
||||
}
|
||||
}
|
||||
|
||||
fn roc_fx_getInt_64bit() callconv(.C) GetInt {
|
||||
if (roc_fx_getInt_help()) |value| {
|
||||
fn roc_fx_get_int_64bit() callconv(.C) GetInt {
|
||||
if (roc_fx_get_int_help()) |value| {
|
||||
const get_int = GetInt{ .is_error = false, .value = value };
|
||||
return get_int;
|
||||
} else |err| switch (err) {
|
||||
|
@ -202,8 +162,8 @@ fn roc_fx_getInt_64bit() callconv(.C) GetInt {
|
|||
return 0;
|
||||
}
|
||||
|
||||
fn roc_fx_getInt_32bit(output: *GetInt) callconv(.C) void {
|
||||
if (roc_fx_getInt_help()) |value| {
|
||||
fn roc_fx_get_int_32bit(output: *GetInt) callconv(.C) void {
|
||||
if (roc_fx_get_int_help()) |value| {
|
||||
const get_int = GetInt{ .is_error = false, .value = value };
|
||||
output.* = get_int;
|
||||
} else |err| switch (err) {
|
||||
|
@ -218,7 +178,7 @@ fn roc_fx_getInt_32bit(output: *GetInt) callconv(.C) void {
|
|||
return;
|
||||
}
|
||||
|
||||
fn roc_fx_getInt_help() !i64 {
|
||||
fn roc_fx_get_int_help() !i64 {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
stdout.print("Please enter an integer\n", .{}) catch unreachable;
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
platform "benchmarks"
|
||||
requires {} { main : Task {} [] }
|
||||
requires {} { main! : {} => {} }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
provides [main_for_host!]
|
||||
|
||||
mainForHost : Task {} []
|
||||
mainForHost = main
|
||||
main_for_host! : {} => {}
|
||||
main_for_host! = \{} -> main!({})
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
app [main!] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
import pf.Host
|
||||
|
||||
Color : [Red, Black]
|
||||
|
||||
|
@ -10,75 +10,75 @@ Map : Tree I64 Bool
|
|||
|
||||
ConsList a : [Nil, Cons a (ConsList a)]
|
||||
|
||||
makeMap : I64, I64 -> ConsList Map
|
||||
makeMap = \freq, n ->
|
||||
makeMapHelp freq n Leaf Nil
|
||||
make_map : I64, I64 -> ConsList Map
|
||||
make_map = \freq, n ->
|
||||
make_map_help(freq, n, Leaf, Nil)
|
||||
|
||||
makeMapHelp : I64, I64, Map, ConsList Map -> ConsList Map
|
||||
makeMapHelp = \freq, n, m, acc ->
|
||||
make_map_help : I64, I64, Map, ConsList Map -> ConsList Map
|
||||
make_map_help = \freq, n, m, acc ->
|
||||
when n is
|
||||
0 -> Cons m acc
|
||||
0 -> Cons(m, acc)
|
||||
_ ->
|
||||
powerOf10 =
|
||||
power_of10 =
|
||||
n % 10 == 0
|
||||
|
||||
m1 = insert m n powerOf10
|
||||
m1 = insert(m, n, power_of10)
|
||||
|
||||
isFrequency =
|
||||
is_frequency =
|
||||
n % freq == 0
|
||||
|
||||
x = (if isFrequency then Cons m1 acc else acc)
|
||||
x = (if is_frequency then Cons(m1, acc) else acc)
|
||||
|
||||
makeMapHelp freq (n - 1) m1 x
|
||||
make_map_help(freq, (n - 1), m1, x)
|
||||
|
||||
fold : (a, b, omega -> omega), Tree a b, omega -> omega
|
||||
fold = \f, tree, b ->
|
||||
when tree is
|
||||
Leaf -> b
|
||||
Node _ l k v r -> fold f r (f k v (fold f l b))
|
||||
Node(_, l, k, v, r) -> fold(f, r, f(k, v, fold(f, l, b)))
|
||||
|
||||
main : Task {} []
|
||||
main =
|
||||
{ value, isError } = PlatformTasks.getInt!
|
||||
inputResult =
|
||||
if isError then
|
||||
Err GetIntError
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
{ value, is_error } = Host.get_int!({})
|
||||
input_result =
|
||||
if is_error then
|
||||
Err(GetIntError)
|
||||
else
|
||||
Ok value
|
||||
Ok(value)
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
when input_result is
|
||||
Ok(n) ->
|
||||
# original koka n = 4_200_000
|
||||
ms : ConsList Map
|
||||
ms = makeMap 5 n
|
||||
ms = make_map(5, n)
|
||||
|
||||
when ms is
|
||||
Cons head _ ->
|
||||
val = fold (\_, v, r -> if v then r + 1 else r) head 0
|
||||
Cons(head, _) ->
|
||||
val = fold(\_, v, r -> if v then r + 1 else r, head, 0)
|
||||
|
||||
val
|
||||
|> Num.toStr
|
||||
|> PlatformTasks.putLine
|
||||
|> Num.to_str
|
||||
|> Host.put_line!
|
||||
|
||||
Nil ->
|
||||
PlatformTasks.putLine "fail"
|
||||
Host.put_line!("fail")
|
||||
|
||||
Err GetIntError ->
|
||||
PlatformTasks.putLine "Error: Failed to get Integer from stdin."
|
||||
Err(GetIntError) ->
|
||||
Host.put_line!("Error: Failed to get Integer from stdin.")
|
||||
|
||||
insert : Tree (Num k) v, Num k, v -> Tree (Num k) v
|
||||
insert = \t, k, v -> if isRed t then setBlack (ins t k v) else ins t k v
|
||||
insert = \t, k, v -> if is_red(t) then set_black(ins(t, k, v)) else ins(t, k, v)
|
||||
|
||||
setBlack : Tree a b -> Tree a b
|
||||
setBlack = \tree ->
|
||||
set_black : Tree a b -> Tree a b
|
||||
set_black = \tree ->
|
||||
when tree is
|
||||
Node _ l k v r -> Node Black l k v r
|
||||
Node(_, l, k, v, r) -> Node(Black, l, k, v, r)
|
||||
_ -> tree
|
||||
|
||||
isRed : Tree a b -> Bool
|
||||
isRed = \tree ->
|
||||
is_red : Tree a b -> Bool
|
||||
is_red = \tree ->
|
||||
when tree is
|
||||
Node Red _ _ _ _ -> Bool.true
|
||||
Node(Red, _, _, _, _) -> Bool.true
|
||||
_ -> Bool.false
|
||||
|
||||
lt = \x, y -> x < y
|
||||
|
@ -86,43 +86,43 @@ lt = \x, y -> x < y
|
|||
ins : Tree (Num k) v, Num k, v -> Tree (Num k) v
|
||||
ins = \tree, kx, vx ->
|
||||
when tree is
|
||||
Leaf -> Node Red Leaf kx vx Leaf
|
||||
Node Red a ky vy b ->
|
||||
if lt kx ky then
|
||||
Node Red (ins a kx vx) ky vy b
|
||||
else if lt ky kx then
|
||||
Node Red a ky vy (ins b kx vx)
|
||||
Leaf -> Node(Red, Leaf, kx, vx, Leaf)
|
||||
Node(Red, a, ky, vy, b) ->
|
||||
if lt(kx, ky) then
|
||||
Node(Red, ins(a, kx, vx), ky, vy, b)
|
||||
else if lt(ky, kx) then
|
||||
Node(Red, a, ky, vy, ins(b, kx, vx))
|
||||
else
|
||||
Node Red a ky vy (ins b kx vx)
|
||||
Node(Red, a, ky, vy, ins(b, kx, vx))
|
||||
|
||||
Node Black a ky vy b ->
|
||||
if lt kx ky then
|
||||
if isRed a then
|
||||
balance1 (Node Black Leaf ky vy b) (ins a kx vx)
|
||||
Node(Black, a, ky, vy, b) ->
|
||||
if lt(kx, ky) then
|
||||
if is_red(a) then
|
||||
balance1(Node(Black, Leaf, ky, vy, b), ins(a, kx, vx))
|
||||
else
|
||||
Node Black (ins a kx vx) ky vy b
|
||||
else if lt ky kx then
|
||||
if isRed b then
|
||||
balance2 (Node Black a ky vy Leaf) (ins b kx vx)
|
||||
Node(Black, ins(a, kx, vx), ky, vy, b)
|
||||
else if lt(ky, kx) then
|
||||
if is_red(b) then
|
||||
balance2(Node(Black, a, ky, vy, Leaf), ins(b, kx, vx))
|
||||
else
|
||||
Node Black a ky vy (ins b kx vx)
|
||||
Node(Black, a, ky, vy, ins(b, kx, vx))
|
||||
else
|
||||
Node Black a kx vx b
|
||||
Node(Black, a, kx, vx, b)
|
||||
|
||||
balance1 : Tree a b, Tree a b -> Tree a b
|
||||
balance1 = \tree1, tree2 ->
|
||||
when tree1 is
|
||||
Leaf -> Leaf
|
||||
Node _ _ kv vv t ->
|
||||
Node(_, _, kv, vv, t) ->
|
||||
when tree2 is
|
||||
Node _ (Node Red l kx vx r1) ky vy r2 ->
|
||||
Node Red (Node Black l kx vx r1) ky vy (Node Black r2 kv vv t)
|
||||
Node(_, Node(Red, l, kx, vx, r1), ky, vy, r2) ->
|
||||
Node(Red, Node(Black, l, kx, vx, r1), ky, vy, Node(Black, r2, kv, vv, t))
|
||||
|
||||
Node _ l1 ky vy (Node Red l2 kx vx r) ->
|
||||
Node Red (Node Black l1 ky vy l2) kx vx (Node Black r kv vv t)
|
||||
Node(_, l1, ky, vy, Node(Red, l2, kx, vx, r)) ->
|
||||
Node(Red, Node(Black, l1, ky, vy, l2), kx, vx, Node(Black, r, kv, vv, t))
|
||||
|
||||
Node _ l ky vy r ->
|
||||
Node Black (Node Red l ky vy r) kv vv t
|
||||
Node(_, l, ky, vy, r) ->
|
||||
Node(Black, Node(Red, l, ky, vy, r), kv, vv, t)
|
||||
|
||||
Leaf -> Leaf
|
||||
|
||||
|
@ -130,16 +130,16 @@ balance2 : Tree a b, Tree a b -> Tree a b
|
|||
balance2 = \tree1, tree2 ->
|
||||
when tree1 is
|
||||
Leaf -> Leaf
|
||||
Node _ t kv vv _ ->
|
||||
Node(_, t, kv, vv, _) ->
|
||||
when tree2 is
|
||||
Node _ (Node Red l kx1 vx1 r1) ky vy r2 ->
|
||||
Node Red (Node Black t kv vv l) kx1 vx1 (Node Black r1 ky vy r2)
|
||||
Node(_, Node(Red, l, kx1, vx1, r1), ky, vy, r2) ->
|
||||
Node(Red, Node(Black, t, kv, vv, l), kx1, vx1, Node(Black, r1, ky, vy, r2))
|
||||
|
||||
Node _ l1 ky vy (Node Red l2 kx2 vx2 r2) ->
|
||||
Node Red (Node Black t kv vv l1) ky vy (Node Black l2 kx2 vx2 r2)
|
||||
Node(_, l1, ky, vy, Node(Red, l2, kx2, vx2, r2)) ->
|
||||
Node(Red, Node(Black, t, kv, vv, l1), ky, vy, Node(Black, l2, kx2, vx2, r2))
|
||||
|
||||
Node _ l ky vy r ->
|
||||
Node Black t kv vv (Node Red l ky vy r)
|
||||
Node(_, l, ky, vy, r) ->
|
||||
Node(Black, t, kv, vv, Node(Red, l, ky, vy, r))
|
||||
|
||||
Leaf ->
|
||||
Leaf
|
||||
|
|
|
@ -1,45 +1,45 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
app [main!] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
import pf.Host
|
||||
|
||||
main : Task {} []
|
||||
main =
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
tree : RedBlackTree I64 {}
|
||||
tree = insert 0 {} Empty
|
||||
tree = insert(0, {}, Empty)
|
||||
|
||||
tree
|
||||
|> show
|
||||
|> PlatformTasks.putLine
|
||||
|> Host.put_line!
|
||||
|
||||
show : RedBlackTree I64 {} -> Str
|
||||
show = \tree -> showRBTree tree Num.toStr (\{} -> "{}")
|
||||
show = \tree -> show_rb_tree(tree, Num.to_str, \{} -> "{}")
|
||||
|
||||
showRBTree : RedBlackTree k v, (k -> Str), (v -> Str) -> Str
|
||||
showRBTree = \tree, showKey, showValue ->
|
||||
show_rb_tree : RedBlackTree k v, (k -> Str), (v -> Str) -> Str
|
||||
show_rb_tree = \tree, show_key, show_value ->
|
||||
when tree is
|
||||
Empty -> "Empty"
|
||||
Node color key value left right ->
|
||||
sColor = showColor color
|
||||
sKey = showKey key
|
||||
sValue = showValue value
|
||||
sL = nodeInParens left showKey showValue
|
||||
sR = nodeInParens right showKey showValue
|
||||
Node(color, key, value, left, right) ->
|
||||
s_color = show_color(color)
|
||||
s_key = show_key(key)
|
||||
s_value = show_value(value)
|
||||
s_l = node_in_parens(left, show_key, show_value)
|
||||
s_r = node_in_parens(right, show_key, show_value)
|
||||
|
||||
"Node $(sColor) $(sKey) $(sValue) $(sL) $(sR)"
|
||||
"Node ${s_color} ${s_key} ${s_value} ${s_l} ${s_r}"
|
||||
|
||||
nodeInParens : RedBlackTree k v, (k -> Str), (v -> Str) -> Str
|
||||
nodeInParens = \tree, showKey, showValue ->
|
||||
node_in_parens : RedBlackTree k v, (k -> Str), (v -> Str) -> Str
|
||||
node_in_parens = \tree, show_key, show_value ->
|
||||
when tree is
|
||||
Empty ->
|
||||
showRBTree tree showKey showValue
|
||||
show_rb_tree(tree, show_key, show_value)
|
||||
|
||||
Node _ _ _ _ _ ->
|
||||
inner = showRBTree tree showKey showValue
|
||||
Node(_, _, _, _, _) ->
|
||||
inner = show_rb_tree(tree, show_key, show_value)
|
||||
|
||||
"($(inner))"
|
||||
"(${inner})"
|
||||
|
||||
showColor : NodeColor -> Str
|
||||
showColor = \color ->
|
||||
show_color : NodeColor -> Str
|
||||
show_color = \color ->
|
||||
when color is
|
||||
Red -> "Red"
|
||||
Black -> "Black"
|
||||
|
@ -52,49 +52,51 @@ Key k : Num k
|
|||
|
||||
insert : Key k, v, RedBlackTree (Key k) v -> RedBlackTree (Key k) v
|
||||
insert = \key, value, dict ->
|
||||
when insertHelp key value dict is
|
||||
Node Red k v l r -> Node Black k v l r
|
||||
when insert_help(key, value, dict) is
|
||||
Node(Red, k, v, l, r) -> Node(Black, k, v, l, r)
|
||||
x -> x
|
||||
|
||||
insertHelp : Key k, v, RedBlackTree (Key k) v -> RedBlackTree (Key k) v
|
||||
insertHelp = \key, value, dict ->
|
||||
insert_help : Key k, v, RedBlackTree (Key k) v -> RedBlackTree (Key k) v
|
||||
insert_help = \key, value, dict ->
|
||||
when dict is
|
||||
Empty ->
|
||||
# New nodes are always red. If it violates the rules, it will be fixed
|
||||
# when balancing.
|
||||
Node Red key value Empty Empty
|
||||
Node(Red, key, value, Empty, Empty)
|
||||
|
||||
Node nColor nKey nValue nLeft nRight ->
|
||||
when Num.compare key nKey is
|
||||
LT -> balance nColor nKey nValue (insertHelp key value nLeft) nRight
|
||||
EQ -> Node nColor nKey value nLeft nRight
|
||||
GT -> balance nColor nKey nValue nLeft (insertHelp key value nRight)
|
||||
Node(n_color, n_key, n_value, n_left, n_right) ->
|
||||
when Num.compare(key, n_key) is
|
||||
LT -> balance(n_color, n_key, n_value, insert_help(key, value, n_left), n_right)
|
||||
EQ -> Node(n_color, n_key, value, n_left, n_right)
|
||||
GT -> balance(n_color, n_key, n_value, n_left, insert_help(key, value, n_right))
|
||||
|
||||
balance : NodeColor, k, v, RedBlackTree k v, RedBlackTree k v -> RedBlackTree k v
|
||||
balance = \color, key, value, left, right ->
|
||||
when right is
|
||||
Node Red rK rV rLeft rRight ->
|
||||
Node(Red, r_k, r_v, r_left, r_right) ->
|
||||
when left is
|
||||
Node Red lK lV lLeft lRight ->
|
||||
Node
|
||||
Red
|
||||
key
|
||||
value
|
||||
(Node Black lK lV lLeft lRight)
|
||||
(Node Black rK rV rLeft rRight)
|
||||
Node(Red, l_k, l_v, l_left, l_right) ->
|
||||
Node(
|
||||
Red,
|
||||
key,
|
||||
value,
|
||||
Node(Black, l_k, l_v, l_left, l_right),
|
||||
Node(Black, r_k, r_v, r_left, r_right),
|
||||
)
|
||||
|
||||
_ ->
|
||||
Node color rK rV (Node Red key value left rLeft) rRight
|
||||
Node(color, r_k, r_v, Node(Red, key, value, left, r_left), r_right)
|
||||
|
||||
_ ->
|
||||
when left is
|
||||
Node Red lK lV (Node Red llK llV llLeft llRight) lRight ->
|
||||
Node
|
||||
Red
|
||||
lK
|
||||
lV
|
||||
(Node Black llK llV llLeft llRight)
|
||||
(Node Black key value lRight right)
|
||||
Node(Red, l_k, l_v, Node(Red, ll_k, ll_v, ll_left, ll_right), l_right) ->
|
||||
Node(
|
||||
Red,
|
||||
l_k,
|
||||
l_v,
|
||||
Node(Black, ll_k, ll_v, ll_left, ll_right),
|
||||
Node(Black, key, value, l_right, right),
|
||||
)
|
||||
|
||||
_ ->
|
||||
Node color key value left right
|
||||
Node(color, key, value, left, right)
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
app [main!] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
import pf.Host
|
||||
import AStar
|
||||
|
||||
main =
|
||||
PlatformTasks.putLine! (showBool test1)
|
||||
main! = \{} ->
|
||||
Host.put_line!(show_bool(test1))
|
||||
|
||||
showBool : Bool -> Str
|
||||
showBool = \b ->
|
||||
show_bool : Bool -> Str
|
||||
show_bool = \b ->
|
||||
if
|
||||
b
|
||||
then
|
||||
|
@ -24,14 +24,14 @@ example1 =
|
|||
step : I64 -> Set I64
|
||||
step = \n ->
|
||||
when n is
|
||||
1 -> Set.fromList [2, 3]
|
||||
2 -> Set.fromList [4]
|
||||
3 -> Set.fromList [4]
|
||||
_ -> Set.fromList []
|
||||
1 -> Set.from_list([2, 3])
|
||||
2 -> Set.from_list([4])
|
||||
3 -> Set.from_list([4])
|
||||
_ -> Set.from_list([])
|
||||
|
||||
cost : I64, I64 -> F64
|
||||
cost = \_, _ -> 1
|
||||
|
||||
when AStar.findPath cost step 1 4 is
|
||||
Ok path -> path
|
||||
Err _ -> []
|
||||
when AStar.find_path(cost, step, 1, 4) is
|
||||
Ok(path) -> path
|
||||
Err(_) -> []
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
app [main!] { pf: platform "platform/main.roc" }
|
||||
|
||||
import Base64
|
||||
import pf.PlatformTasks
|
||||
import pf.Host
|
||||
|
||||
IO a : Task a []
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
when Base64.from_bytes(Str.to_utf8("Hello World")) is
|
||||
Err(_) -> Host.put_line!("sadness")
|
||||
Ok(encoded) ->
|
||||
Host.put_line!(Str.concat("encoded: ", encoded))
|
||||
|
||||
main : IO {}
|
||||
main =
|
||||
when Base64.fromBytes (Str.toUtf8 "Hello World") is
|
||||
Err _ -> PlatformTasks.putLine "sadness"
|
||||
Ok encoded ->
|
||||
PlatformTasks.putLine! (Str.concat "encoded: " encoded)
|
||||
|
||||
when Base64.toStr encoded is
|
||||
Ok decoded -> PlatformTasks.putLine (Str.concat "decoded: " decoded)
|
||||
Err _ -> PlatformTasks.putLine "sadness"
|
||||
when Base64.to_str(encoded) is
|
||||
Ok(decoded) -> Host.put_line!(Str.concat("decoded: ", decoded))
|
||||
Err(_) -> Host.put_line!("sadness")
|
||||
|
|
|
@ -50,12 +50,12 @@ mod cli_tests {
|
|||
const TEST_LEGACY_LINKER: bool = false;
|
||||
|
||||
#[test]
|
||||
#[ignore = "Works when run manually, but not in CI"]
|
||||
#[ignore = "Needs investigation, see also github.com/roc-lang/roc/pull/7231"]
|
||||
fn platform_switching_rust() {
|
||||
// pre-build the platform
|
||||
std::process::Command::new("bash")
|
||||
.arg(file_from_root(
|
||||
"examples/platform-switching/rust-platform",
|
||||
"crates/cli/tests/platform-switching/rust-platform",
|
||||
"build.sh",
|
||||
))
|
||||
.status()
|
||||
|
@ -63,7 +63,7 @@ mod cli_tests {
|
|||
|
||||
let cli_build = ExecCli::new(
|
||||
roc_cli::CMD_DEV,
|
||||
file_from_root("examples/platform-switching", "rocLovesRust.roc"),
|
||||
file_from_root("crates/cli/tests/platform-switching", "rocLovesRust.roc"),
|
||||
);
|
||||
|
||||
let expected_output = "Roc <3 Rust!\n";
|
||||
|
@ -80,7 +80,7 @@ mod cli_tests {
|
|||
|
||||
let cli_build = ExecCli::new(
|
||||
CMD_BUILD,
|
||||
file_from_root("examples/platform-switching", "rocLovesZig.roc"),
|
||||
file_from_root("crates/cli/tests/platform-switching", "rocLovesZig.roc"),
|
||||
)
|
||||
.arg(BUILD_HOST_FLAG)
|
||||
.arg(SUPPRESS_BUILD_HOST_WARNING_FLAG);
|
||||
|
@ -104,7 +104,10 @@ mod cli_tests {
|
|||
// so let's just check it for now
|
||||
let cli_check = ExecCli::new(
|
||||
CMD_CHECK,
|
||||
file_from_root("examples/platform-switching", "rocLovesWebAssembly.roc"),
|
||||
file_from_root(
|
||||
"crates/cli/tests/platform-switching",
|
||||
"rocLovesWebAssembly.roc",
|
||||
),
|
||||
);
|
||||
|
||||
let cli_check_out = cli_check.run();
|
||||
|
@ -160,34 +163,6 @@ mod cli_tests {
|
|||
);
|
||||
}
|
||||
|
||||
// TODO: write a new test once mono bugs are resolved in investigation
|
||||
// Encountering this TODO years later, I presume the new test should test the execution, not just roc check.
|
||||
#[test]
|
||||
#[cfg(not(debug_assertions))] // https://github.com/roc-lang/roc/issues/4806 - later observation: this issue is closed but the tests still hangs in debug mode
|
||||
fn check_virtual_dom_server() {
|
||||
let cli_check = ExecCli::new(
|
||||
CMD_CHECK,
|
||||
file_from_root("examples/virtual-dom-wip", "example-server.roc"),
|
||||
);
|
||||
|
||||
let cli_check_out = cli_check.run();
|
||||
cli_check_out.assert_clean_success();
|
||||
}
|
||||
|
||||
// TODO: write a new test once mono bugs are resolved in investigation
|
||||
// Encountering this TODO years later, I presume the new test should test the execution, not just roc check.
|
||||
#[test]
|
||||
#[cfg(not(debug_assertions))] // https://github.com/roc-lang/roc/issues/4806 - later observation: this issue is closed but the tests still hangs in debug mode
|
||||
fn check_virtual_dom_client() {
|
||||
let cli_check = ExecCli::new(
|
||||
CMD_CHECK,
|
||||
file_from_root("examples/virtual-dom-wip", "example-client.roc"),
|
||||
);
|
||||
|
||||
let cli_check_out = cli_check.run();
|
||||
cli_check_out.assert_clean_success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
// tea = The Elm Architecture
|
||||
|
@ -212,31 +187,35 @@ mod cli_tests {
|
|||
);
|
||||
}
|
||||
|
||||
// TODO check this out, there's more that's going wrong than a segfault
|
||||
//#[test]
|
||||
/*#[cfg_attr(
|
||||
any(target_os = "windows", target_os = "linux", target_os = "macos"),
|
||||
ignore = "Segfault, likely broken because of alias analysis: https://github.com/roc-lang/roc/issues/6544"
|
||||
)]*/
|
||||
/*
|
||||
#[test]
|
||||
// #[cfg_attr(windows, ignore)]
|
||||
#[ignore]
|
||||
fn false_interpreter() {
|
||||
let cli_build = ExecCli::new(
|
||||
CMD_BUILD,
|
||||
file_from_root("crates/cli/tests/test-projects/false-interpreter", "main.roc")
|
||||
)
|
||||
.arg(BUILD_HOST_FLAG)
|
||||
.arg(SUPPRESS_BUILD_HOST_WARNING_FLAG);
|
||||
CMD_BUILD,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/false-interpreter",
|
||||
"main.roc",
|
||||
),
|
||||
)
|
||||
.arg(BUILD_HOST_FLAG)
|
||||
.arg(SUPPRESS_BUILD_HOST_WARNING_FLAG);
|
||||
|
||||
let sqrt_false_path_buf = file_from_root("crates/cli/tests/test-projects/false-interpreter/examples", "sqrt.false");
|
||||
let sqrt_false_path_buf = file_from_root(
|
||||
"crates/cli/tests/test-projects/false-interpreter/examples",
|
||||
"sqrt.false",
|
||||
);
|
||||
|
||||
let app_args = ["--",
|
||||
sqrt_false_path_buf
|
||||
.as_path()
|
||||
.to_str()
|
||||
.unwrap()];
|
||||
let app_args = [sqrt_false_path_buf.as_path().to_str().unwrap()];
|
||||
|
||||
cli_build.full_check_build_and_run("1414", TEST_LEGACY_LINKER, ALLOW_VALGRIND, None, Some(&app_args));
|
||||
}*/
|
||||
cli_build.full_check_build_and_run(
|
||||
"1414",
|
||||
TEST_LEGACY_LINKER,
|
||||
ALLOW_VALGRIND,
|
||||
None,
|
||||
Some(&app_args),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
|
@ -874,7 +853,7 @@ mod cli_tests {
|
|||
),
|
||||
);
|
||||
|
||||
let expected_output = "(@Community {friends: [{2}, {2}, {0, 1}], people: [(@Person {age: 27, favoriteColor: Blue, firstName: \"John\", hasBeard: Bool.true, lastName: \"Smith\"}), (@Person {age: 47, favoriteColor: Green, firstName: \"Debby\", hasBeard: Bool.false, lastName: \"Johnson\"}), (@Person {age: 33, favoriteColor: (RGB (255, 255, 0)), firstName: \"Jane\", hasBeard: Bool.false, lastName: \"Doe\"})]})\n";
|
||||
let expected_output = "(@Community {friends: [{2}, {2}, {0, 1}], people: [(@Person {age: 27, favorite_color: Blue, first_name: \"John\", has_beard: Bool.true, last_name: \"Smith\"}), (@Person {age: 47, favorite_color: Green, first_name: \"Debby\", has_beard: Bool.false, last_name: \"Johnson\"}), (@Person {age: 33, favorite_color: (RGB (255, 255, 0)), first_name: \"Jane\", has_beard: Bool.false, last_name: \"Doe\"})]})\n";
|
||||
|
||||
cli_build.full_check_build_and_run(
|
||||
expected_output,
|
||||
|
@ -891,7 +870,7 @@ mod cli_tests {
|
|||
build_platform_host();
|
||||
|
||||
let cli_build = ExecCli::new(
|
||||
roc_cli::CMD_DEV,
|
||||
roc_cli::CMD_BUILD,
|
||||
file_from_root("crates/cli/tests/test-projects/effectful", "form.roc"),
|
||||
);
|
||||
|
||||
|
@ -911,14 +890,14 @@ mod cli_tests {
|
|||
fn effectful_hello() {
|
||||
build_platform_host();
|
||||
|
||||
let cli_build = ExecCli::new(
|
||||
let cli_dev = ExecCli::new(
|
||||
roc_cli::CMD_DEV,
|
||||
file_from_root("crates/cli/tests/test-projects/effectful/", "hello.roc"),
|
||||
);
|
||||
|
||||
let expected_out = "I'm an effect 👻\n";
|
||||
|
||||
cli_build.run().assert_clean_stdout(expected_out);
|
||||
cli_dev.run().assert_clean_stdout(expected_out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -926,14 +905,14 @@ mod cli_tests {
|
|||
fn effectful_loops() {
|
||||
build_platform_host();
|
||||
|
||||
let cli_build = ExecCli::new(
|
||||
let cli_dev = ExecCli::new(
|
||||
roc_cli::CMD_DEV,
|
||||
file_from_root("crates/cli/tests/test-projects/effectful/", "loops.roc"),
|
||||
);
|
||||
|
||||
let expected_out = "Lu\nMarce\nJoaquin\nChloé\nMati\nPedro\n";
|
||||
|
||||
cli_build.run().assert_clean_stdout(expected_out);
|
||||
cli_dev.run().assert_clean_stdout(expected_out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -941,7 +920,7 @@ mod cli_tests {
|
|||
fn effectful_untyped_passed_fx() {
|
||||
build_platform_host();
|
||||
|
||||
let cli_build = ExecCli::new(
|
||||
let cli_dev = ExecCli::new(
|
||||
roc_cli::CMD_DEV,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/effectful/",
|
||||
|
@ -951,7 +930,7 @@ mod cli_tests {
|
|||
|
||||
let expected_out = "Before hello\nHello, World!\nAfter hello\n";
|
||||
|
||||
cli_build.run().assert_clean_stdout(expected_out);
|
||||
cli_dev.run().assert_clean_stdout(expected_out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -959,7 +938,7 @@ mod cli_tests {
|
|||
fn effectful_ignore_result() {
|
||||
build_platform_host();
|
||||
|
||||
let cli_build = ExecCli::new(
|
||||
let cli_dev = ExecCli::new(
|
||||
roc_cli::CMD_DEV,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/effectful/",
|
||||
|
@ -969,7 +948,7 @@ mod cli_tests {
|
|||
|
||||
let expected_out = "I asked for input and I ignored it. Deal with it! 😎\n";
|
||||
|
||||
cli_build.run().assert_clean_stdout(expected_out);
|
||||
cli_dev.run().assert_clean_stdout(expected_out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -978,14 +957,14 @@ mod cli_tests {
|
|||
build_platform_host();
|
||||
|
||||
let cli_build = ExecCli::new(
|
||||
roc_cli::CMD_DEV,
|
||||
roc_cli::CMD_BUILD,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/effectful",
|
||||
"suffixed_record_field.roc",
|
||||
),
|
||||
);
|
||||
|
||||
let expected_output = "notEffectful: hardcoded\neffectful: from stdin\n";
|
||||
let expected_output = "not_effectful: hardcoded\neffectful: from stdin\n";
|
||||
|
||||
cli_build.check_build_and_run(
|
||||
expected_output,
|
||||
|
@ -1001,7 +980,7 @@ mod cli_tests {
|
|||
build_platform_host();
|
||||
|
||||
let cli_build = ExecCli::new(
|
||||
roc_cli::CMD_DEV,
|
||||
roc_cli::CMD_BUILD,
|
||||
file_from_root("crates/cli/tests/test-projects/effectful", "on_err.roc"),
|
||||
);
|
||||
|
||||
|
@ -1016,7 +995,7 @@ mod cli_tests {
|
|||
build_platform_host();
|
||||
|
||||
let cli_build = ExecCli::new(
|
||||
roc_cli::CMD_DEV,
|
||||
roc_cli::CMD_BUILD,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/effectful",
|
||||
"for_each_try.roc",
|
||||
|
@ -1302,6 +1281,7 @@ mod cli_tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "flaky currently due to 7022"]
|
||||
fn known_type_error() {
|
||||
let cli_check = ExecCli::new(
|
||||
CMD_CHECK,
|
||||
|
|
14
crates/cli/tests/platform-switching/README.md
Normal file
14
crates/cli/tests/platform-switching/README.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
# Platform switching
|
||||
|
||||
To run, `cd` into this directory and run this in your terminal:
|
||||
|
||||
```bash
|
||||
roc --build-host --suppress-build-host-warning rocLovesC.roc
|
||||
```
|
||||
|
||||
## About these examples
|
||||
|
||||
They use a very simple [platform](https://www.roc-lang.org/platforms) which does nothing more than printing the string you give it.
|
||||
|
||||
If you want to start building your own platforms, these are some very simple example platforms to use as starting points.
|
|
@ -85,12 +85,12 @@ size_t roc_str_len(struct RocStr str) {
|
|||
}
|
||||
}
|
||||
|
||||
extern void roc__mainForHost_1_exposed_generic(struct RocStr *string);
|
||||
extern void roc__main_for_host_1_exposed_generic(struct RocStr *string);
|
||||
|
||||
int main() {
|
||||
|
||||
struct RocStr str;
|
||||
roc__mainForHost_1_exposed_generic(&str);
|
||||
roc__main_for_host_1_exposed_generic(&str);
|
||||
|
||||
// Determine str_len and the str_bytes pointer,
|
||||
// taking into account the small string optimization.
|
|
@ -3,7 +3,7 @@ platform "echo-in-c"
|
|||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
provides [main_for_host]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
||||
main_for_host : Str
|
||||
main_for_host = main
|
|
@ -1,5 +1,9 @@
|
|||
app [main] { pf: platform "c-platform/main.roc" }
|
||||
|
||||
# run with `roc --build-host --suppress-build-host-warning rocLovesZig.roc`
|
||||
# may require:
|
||||
# ubuntu: sudo apt install build-essential clang
|
||||
# fedora: sudo dnf install clang
|
||||
|
||||
# run with `roc --build-host --suppress-build-host-warning rocLovesC.roc`
|
||||
|
||||
main = "Roc <3 C!\n"
|
10
crates/cli/tests/platform-switching/rocLovesZig.roc
Normal file
10
crates/cli/tests/platform-switching/rocLovesZig.roc
Normal file
|
@ -0,0 +1,10 @@
|
|||
app [main] { pf: platform "zig-platform/main.roc" }
|
||||
|
||||
# To run:
|
||||
# cd examples/platform-switching/zig-platform
|
||||
# mkdir glue
|
||||
# cp crates/compiler/builtins/bitcode/src/* ./glue
|
||||
# cd -
|
||||
# roc --build-host --suppress-build-host-warning rocLovesZig.roc
|
||||
|
||||
main = "Roc <3 Zig!\n"
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// ```
|
||||
// = note: Undefined symbols for architecture arm64:
|
||||
// "_roc__mainForHost_1_exposed_generic", referenced from:
|
||||
// "_roc__main_for_host_1_exposed_generic", referenced from:
|
||||
// _main in rustplatform-df9e357e0cc989a6.rustplatform.863be87f3956573-cgu.0.rcgu.o
|
||||
// ld: symbol(s) not found for architecture arm64
|
||||
// clang-16: error: linker command failed with exit code 1 (use -v to see invocation)
|
|
@ -3,7 +3,7 @@ platform "echo-in-rust"
|
|||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
provides [main_for_host]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
||||
main_for_host : Str
|
||||
main_for_host = main
|
|
@ -1,9 +1,9 @@
|
|||
[toolchain]
|
||||
channel = "1.77.2"
|
||||
|
||||
profile = "default"
|
||||
|
||||
components = [
|
||||
# for usages of rust-analyzer or similar tools inside `nix develop`
|
||||
"rust-src"
|
||||
[toolchain]
|
||||
channel = "1.77.2"
|
||||
|
||||
profile = "default"
|
||||
|
||||
components = [
|
||||
# for usages of rust-analyzer or similar tools inside `nix develop`
|
||||
"rust-src"
|
||||
]
|
|
@ -6,7 +6,7 @@ use roc_std::RocStr;
|
|||
use std::io::Write;
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "roc__mainForHost_1_exposed_generic"]
|
||||
#[link_name = "roc__main_for_host_1_exposed_generic"]
|
||||
fn roc_main(_: &mut RocStr);
|
||||
}
|
||||
|
|
@ -35,14 +35,14 @@ export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
|||
|
||||
// NOTE roc_panic and roc_dbg is provided in the JS file, so it can throw an exception
|
||||
|
||||
extern fn roc__mainForHost_1_exposed(*RocStr) void;
|
||||
extern fn roc__main_for_host_1_exposed(*RocStr) void;
|
||||
|
||||
extern fn js_display_roc_string(str_bytes: ?[*]u8, str_len: usize) void;
|
||||
|
||||
pub export fn main() u8 {
|
||||
// actually call roc to populate the callresult
|
||||
var callresult = RocStr.empty();
|
||||
roc__mainForHost_1_exposed(&callresult);
|
||||
roc__main_for_host_1_exposed(&callresult);
|
||||
|
||||
// display the result using JavaScript
|
||||
js_display_roc_string(callresult.asU8ptrMut(), callresult.len());
|
|
@ -3,7 +3,7 @@ platform "echo-in-web-assembly"
|
|||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
provides [main_for_host]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
||||
main_for_host : Str
|
||||
main_for_host = main
|
|
@ -102,7 +102,7 @@ comptime {
|
|||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
extern fn roc__mainForHost_1_exposed_generic(*RocStr) void;
|
||||
extern fn roc__main_for_host_1_exposed_generic(*RocStr) void;
|
||||
|
||||
const Unit = extern struct {};
|
||||
|
||||
|
@ -111,7 +111,7 @@ pub export fn main() u8 {
|
|||
|
||||
// actually call roc to populate the callresult
|
||||
var callresult = RocStr.empty();
|
||||
roc__mainForHost_1_exposed_generic(&callresult);
|
||||
roc__main_for_host_1_exposed_generic(&callresult);
|
||||
|
||||
// stdout the result
|
||||
stdout.print("{s}", .{callresult.asSlice()}) catch unreachable;
|
|
@ -3,7 +3,7 @@ platform "echo-in-zig"
|
|||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
provides [main_for_host]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
||||
main_for_host : Str
|
||||
main_for_host = main
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_check_out.normalize_stdout_and_stderr()
|
||||
snapshot_kind: text
|
||||
---
|
||||
|
||||
── MISSING DEFINITION in tests/test-projects/known_bad/ExposedNotDefined.roc ───
|
||||
|
@ -12,4 +13,5 @@ from exposes.
|
|||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
1 error and 0 warning found in <ignored for test> ms
|
||||
1 error and 0 warnings found in <ignored for test> ms.
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_check_out.normalize_stdout_and_stderr()
|
||||
snapshot_kind: text
|
||||
---
|
||||
|
||||
── TYPE MISMATCH in tests/test-projects/known_bad/TypeError.roc ────────────────
|
||||
|
@ -25,4 +26,5 @@ this out.
|
|||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
1 error and 0 warning found in <ignored for test> ms
|
||||
1 error and 0 warnings found in <ignored for test> ms.
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_check_out.normalize_stdout_and_stderr()
|
||||
snapshot_kind: text
|
||||
---
|
||||
|
||||
── UNUSED IMPORT in ...nown_bad/UnusedImportButWithALongFileNameForTesting.roc ─
|
||||
|
@ -14,4 +15,5 @@ Since Symbol isn't used, you don't need to import it.
|
|||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
0 error and 1 warning found in <ignored for test> ms
|
||||
0 errors and 1 warning found in <ignored for test> ms.
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_test_out.normalize_stdout_and_stderr()
|
||||
snapshot_kind: text
|
||||
---
|
||||
── EXPECT FAILED in tests/test-projects/expects/expects.roc ────────────────────
|
||||
|
||||
|
@ -31,7 +32,7 @@ a = 1
|
|||
This expectation failed:
|
||||
|
||||
11│> expect
|
||||
12│> a = makeA
|
||||
12│> a = make_a
|
||||
13│> b = 2i64
|
||||
14│>
|
||||
15│> a == b
|
||||
|
|
|
@ -6,10 +6,10 @@ snapshot_kind: text
|
|||
|
||||
── TOO MANY ARGS in tests/test-projects/module_params/arity_mismatch.roc ───────
|
||||
|
||||
The getUser function expects 1 argument, but it got 2 instead:
|
||||
The get_user function expects 1 argument, but it got 2 instead:
|
||||
|
||||
12│ $(Api.getUser 1 2)
|
||||
^^^^^^^^^^^
|
||||
12│ ${Api.get_user(1, 2)}
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Are there any missing commas? Or missing parentheses?
|
||||
|
||||
|
@ -18,18 +18,18 @@ Are there any missing commas? Or missing parentheses?
|
|||
|
||||
This value is not a function, but it was given 1 argument:
|
||||
|
||||
13│ $(Api.baseUrl 1)
|
||||
^^^^^^^^^^^
|
||||
13│ ${Api.base_url(1)}
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Are there any missing commas? Or missing parentheses?
|
||||
|
||||
|
||||
── TOO FEW ARGS in tests/test-projects/module_params/arity_mismatch.roc ────────
|
||||
|
||||
The getPostComment function expects 2 arguments, but it got only 1:
|
||||
The get_post_comment function expects 2 arguments, but it got only 1:
|
||||
|
||||
16│ $(Api.getPostComment 1)
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
16│ ${Api.get_post_comment(1)}
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Roc does not allow functions to be partially applied. Use a closure to
|
||||
make partial application explicit.
|
||||
|
|
|
@ -6,34 +6,35 @@ snapshot_kind: text
|
|||
|
||||
── TYPE MISMATCH in tests/test-projects/module_params/BadAnn.roc ───────────────
|
||||
|
||||
Something is off with the body of the fnAnnotatedAsValue definition:
|
||||
Something is off with the body of the
|
||||
fn_annotated_as_value definition:
|
||||
|
||||
3│ fnAnnotatedAsValue : Str
|
||||
4│> fnAnnotatedAsValue = \postId, commentId ->
|
||||
5│> "/posts/$(postId)/comments/$(Num.toStr commentId)"
|
||||
3│ fn_annotated_as_value : Str
|
||||
4│> fn_annotated_as_value = \post_id, comment_id ->
|
||||
5│> "/posts/${post_id}/comments/${Num.to_str(comment_id)}"
|
||||
|
||||
The body is an anonymous function of type:
|
||||
|
||||
Str, Num * -> Str
|
||||
|
||||
But the type annotation on fnAnnotatedAsValue says it should be:
|
||||
But the type annotation on fn_annotated_as_value says it should be:
|
||||
|
||||
Str
|
||||
|
||||
|
||||
── TYPE MISMATCH in tests/test-projects/module_params/BadAnn.roc ───────────────
|
||||
|
||||
Something is off with the body of the missingArg definition:
|
||||
Something is off with the body of the missing_arg definition:
|
||||
|
||||
7│ missingArg : Str -> Str
|
||||
8│> missingArg = \postId, _ ->
|
||||
9│> "/posts/$(postId)/comments"
|
||||
7│ missing_arg : Str -> Str
|
||||
8│> missing_arg = \post_id, _ ->
|
||||
9│> "/posts/${post_id}/comments"
|
||||
|
||||
The body is an anonymous function of type:
|
||||
|
||||
(Str, ? -> Str)
|
||||
|
||||
But the type annotation on missingArg says it should be:
|
||||
But the type annotation on missing_arg says it should be:
|
||||
|
||||
(Str -> Str)
|
||||
|
||||
|
|
|
@ -8,9 +8,8 @@ snapshot_kind: text
|
|||
|
||||
This argument to this string interpolation has an unexpected type:
|
||||
|
||||
10│ """
|
||||
11│> $(Api.getPost)
|
||||
12│ """
|
||||
10│ "${Api.get_post}"
|
||||
^^^^^^^^^^^^
|
||||
|
||||
The argument is an anonymous function of type:
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_check_out.normalize_stdout_and_stderr()
|
||||
snapshot_kind: text
|
||||
---
|
||||
|
||||
── UNUSED IMPORT in tests/test-projects/known_bad/UnusedImport.roc ─────────────
|
||||
|
@ -14,4 +15,4 @@ Since Symbol isn't used, you don't need to import it.
|
|||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
0 error and 1 warning found in <ignored for test> ms
|
||||
0 errors and 1 warning found in <ignored for test> ms.
|
||||
|
|
|
@ -11,8 +11,8 @@ const mem = std.mem;
|
|||
const Allocator = mem.Allocator;
|
||||
|
||||
// NOTE the LLVM backend expects this signature
|
||||
// extern fn roc__mainForHost_1_exposed(i64, *i64) void;
|
||||
extern fn roc__mainForHost_1_exposed(i64) i64;
|
||||
// extern fn roc__main_for_host_1_exposed(i64, *i64) void;
|
||||
extern fn roc__main_for_host_1_exposed(i64) i64;
|
||||
|
||||
const Align = 2 * @alignOf(usize);
|
||||
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
|
||||
|
@ -110,7 +110,7 @@ comptime {
|
|||
pub export fn main() u8 {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
|
||||
const result = roc__mainForHost_1_exposed(10);
|
||||
const result = roc__main_for_host_1_exposed(10);
|
||||
|
||||
stdout.print("{d}\n", .{result}) catch unreachable;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ platform "fibonacci"
|
|||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
provides [main_for_host]
|
||||
|
||||
mainForHost : I64 -> I64
|
||||
mainForHost = \a -> main a
|
||||
main_for_host : I64 -> I64
|
||||
main_for_host = \a -> main(a)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
app [main] { pf: platform "fibonacci-platform/main.roc" }
|
||||
|
||||
main = \n -> fib n 0 1
|
||||
main = \n -> fib(n, 0, 1)
|
||||
|
||||
# the clever implementation requires join points
|
||||
fib = \n, a, b ->
|
||||
if n == 0 then
|
||||
a
|
||||
else
|
||||
fib (n - 1) b (a + b)
|
||||
fib((n - 1), b, (a + b))
|
||||
|
|
|
@ -9,7 +9,7 @@ const expect = testing.expect;
|
|||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
extern fn roc__mainForHost_1_exposed(input: RocList) callconv(.C) RocList;
|
||||
extern fn roc__main_for_host_1_exposed(input: RocList) callconv(.C) RocList;
|
||||
|
||||
const Align = 2 * @alignOf(usize);
|
||||
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
|
||||
|
@ -117,7 +117,7 @@ pub export fn main() u8 {
|
|||
var raw_numbers: [NUM_NUMS + 1]i64 = undefined;
|
||||
|
||||
// set refcount to one
|
||||
raw_numbers[0] = -9223372036854775808;
|
||||
raw_numbers[0] = 1;
|
||||
|
||||
var numbers = raw_numbers[1..];
|
||||
|
||||
|
@ -128,7 +128,7 @@ pub export fn main() u8 {
|
|||
const roc_list = RocList{ .elements = numbers, .length = NUM_NUMS, .capacity = NUM_NUMS };
|
||||
|
||||
// actually call roc to populate the callresult
|
||||
const callresult: RocList = roc__mainForHost_1_exposed(roc_list);
|
||||
const callresult: RocList = roc__main_for_host_1_exposed(roc_list);
|
||||
|
||||
// stdout the result
|
||||
const length = @min(20, callresult.length);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue