mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
Merge branch 'main' into constrain-early-return-functions
This commit is contained in:
commit
7ca305b5dc
371 changed files with 6427 additions and 8505 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
@ -1,4 +1,5 @@
|
|||
# Require roc files to be checked out with Unix line endings, even on windows
|
||||
*.roc text eol=lf
|
||||
* text=auto eol=lf
|
||||
|
||||
crates/compiler/test_mono/generated/* linguist-generated=true
|
8
.github/workflows/ci_manager.yml
vendored
8
.github/workflows/ci_manager.yml
vendored
|
@ -124,6 +124,11 @@ jobs:
|
|||
if: needs.check-changes.outputs.run_tests == 'full'
|
||||
uses: ./.github/workflows/benchmarks.yml
|
||||
|
||||
start-panic-check:
|
||||
needs: check-changes
|
||||
if: needs.check-changes.outputs.run_tests == 'full'
|
||||
uses: ./.github/workflows/improve_panics.yml
|
||||
|
||||
ran-full:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [
|
||||
|
@ -136,7 +141,8 @@ jobs:
|
|||
start-ubuntu-x86-64-nix-tests-debug,
|
||||
start-windows-release-build-test,
|
||||
start-windows-tests,
|
||||
start-roc-benchmarks
|
||||
start-roc-benchmarks,
|
||||
start-panic-check
|
||||
]
|
||||
steps:
|
||||
- run: echo "all workflows succeeded!"
|
||||
|
|
37
.github/workflows/docker.yml
vendored
37
.github/workflows/docker.yml
vendored
|
@ -1,7 +1,6 @@
|
|||
on:
|
||||
workflow_dispatch:
|
||||
#pull_request:
|
||||
# TODO remove pull_request trigger
|
||||
|
||||
name: Docker images tests
|
||||
|
||||
|
@ -19,8 +18,10 @@ jobs:
|
|||
- name: Build image
|
||||
run: docker compose -f docker/nightly-ubuntu-latest/docker-compose.yml build
|
||||
|
||||
- name: Run hello world test
|
||||
run: docker compose -f docker/nightly-ubuntu-latest/docker-compose.yml run roc examples/helloWorld.roc
|
||||
- name: Test with hello world
|
||||
run: |
|
||||
curl -OL https://raw.githubusercontent.com/roc-lang/examples/refs/heads/main/examples/HelloWorld/main.roc
|
||||
docker compose -f docker/nightly-ubuntu-latest/docker-compose.yml run roc main.roc
|
||||
|
||||
|
||||
nightly-ubuntu-2204:
|
||||
|
@ -36,8 +37,10 @@ jobs:
|
|||
- name: Build image
|
||||
run: docker compose -f docker/nightly-ubuntu-2204/docker-compose.yml build
|
||||
|
||||
- name: Run hello world test
|
||||
run: docker compose -f docker/nightly-ubuntu-2204/docker-compose.yml run roc examples/helloWorld.roc
|
||||
- name: Test with hello world
|
||||
run: |
|
||||
curl -OL https://raw.githubusercontent.com/roc-lang/examples/refs/heads/main/examples/HelloWorld/main.roc
|
||||
docker compose -f docker/nightly-ubuntu-2204/docker-compose.yml run roc main.roc
|
||||
|
||||
nightly-ubuntu-2004:
|
||||
name: nightly-ubuntu-2004
|
||||
|
@ -52,8 +55,10 @@ jobs:
|
|||
- name: Build image
|
||||
run: docker compose -f docker/nightly-ubuntu-2004/docker-compose.yml build
|
||||
|
||||
- name: Run hello world test
|
||||
run: docker compose -f docker/nightly-ubuntu-2004/docker-compose.yml run roc examples/helloWorld.roc
|
||||
- name: Test with hello world
|
||||
run: |
|
||||
curl -OL https://raw.githubusercontent.com/roc-lang/examples/refs/heads/main/examples/HelloWorld/main.roc
|
||||
docker compose -f docker/nightly-ubuntu-2004/docker-compose.yml run roc main.roc
|
||||
|
||||
nightly-debian-latest:
|
||||
name: nightly-debian-latest
|
||||
|
@ -68,8 +73,10 @@ jobs:
|
|||
- name: Build image
|
||||
run: docker compose -f docker/nightly-debian-latest/docker-compose.yml build
|
||||
|
||||
- name: Run hello world test
|
||||
run: docker compose -f docker/nightly-debian-latest/docker-compose.yml run roc examples/helloWorld.roc
|
||||
- name: Test with hello world
|
||||
run: |
|
||||
curl -OL https://raw.githubusercontent.com/roc-lang/examples/refs/heads/main/examples/HelloWorld/main.roc
|
||||
docker compose -f docker/nightly-debian-latest/docker-compose.yml run roc main.roc
|
||||
|
||||
nightly-debian-bookworm:
|
||||
name: nightly-debian-bookworm
|
||||
|
@ -84,8 +91,10 @@ jobs:
|
|||
- name: Build image
|
||||
run: docker compose -f docker/nightly-debian-bookworm/docker-compose.yml build
|
||||
|
||||
- name: Run hello world test
|
||||
run: docker compose -f docker/nightly-debian-bookworm/docker-compose.yml run roc examples/helloWorld.roc
|
||||
- name: Test with hello world
|
||||
run: |
|
||||
curl -OL https://raw.githubusercontent.com/roc-lang/examples/refs/heads/main/examples/HelloWorld/main.roc
|
||||
docker compose -f docker/nightly-debian-bookworm/docker-compose.yml run roc main.roc
|
||||
|
||||
nightly-debian-buster:
|
||||
name: nightly-debian-buster
|
||||
|
@ -100,5 +109,7 @@ jobs:
|
|||
- name: Build image
|
||||
run: docker compose -f docker/nightly-debian-buster/docker-compose.yml build
|
||||
|
||||
- name: Run hello world test
|
||||
run: docker compose -f docker/nightly-debian-buster/docker-compose.yml run roc examples/helloWorld.roc
|
||||
- name: Test with hello world
|
||||
run: |
|
||||
curl -OL https://raw.githubusercontent.com/roc-lang/examples/refs/heads/main/examples/HelloWorld/main.roc
|
||||
docker compose -f docker/nightly-debian-buster/docker-compose.yml run roc main.roc
|
||||
|
|
56
.github/workflows/improve_panics.yml
vendored
Normal file
56
.github/workflows/improve_panics.yml
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
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
|
|
@ -2,7 +2,7 @@ on:
|
|||
#pull_request:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 9 * * *'
|
||||
- cron: "0 9 * * *"
|
||||
|
||||
name: Nightly Release macOS Apple Silicon
|
||||
|
||||
|
@ -56,8 +56,9 @@ jobs:
|
|||
- name: extract tar for a quick test
|
||||
run: ls | grep tar | xargs tar -xf
|
||||
|
||||
- name: test with rust platform
|
||||
run: cd ${{ env.RELEASE_FOLDER_NAME }} && ./roc examples/platform-switching/rocLovesRust.roc
|
||||
- name: test with zig platform
|
||||
run: |
|
||||
cd ${{ env.RELEASE_FOLDER_NAME }} && ./roc --build-host --suppress-build-host-warning examples/platform-switching/rocLovesZig.roc
|
||||
|
||||
- name: print short commit SHA
|
||||
run: git rev-parse --short "$GITHUB_SHA"
|
||||
|
|
2
.github/workflows/nix_linux_x86_64.yml
vendored
2
.github/workflows/nix_linux_x86_64.yml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
|||
- name: roc test all builtins
|
||||
run: nix develop -c ./ci/roc_test_builtins.sh
|
||||
|
||||
- name: test wasm32 cli_run
|
||||
- name: test wasm32 cli_tests
|
||||
run: nix develop -c cargo test --locked --release --features="wasm32-cli-run"
|
||||
|
||||
- name: test the dev backend # these tests require an explicit feature flag
|
||||
|
|
|
@ -34,17 +34,11 @@ jobs:
|
|||
|
||||
# for skipped tests: see issue 6274
|
||||
- name: execute tests with --release
|
||||
run: nix develop -c cargo test --locked --release -- --skip cli_run::inspect_gui --skip cli_run::hello_gui
|
||||
run: nix develop -c cargo test --locked --release -- --skip cli_tests::inspect_gui --skip cli_tests::hello_gui
|
||||
|
||||
- name: roc test all builtins
|
||||
run: nix develop -c ./ci/roc_test_builtins.sh
|
||||
|
||||
- name: make a libapp.so for the next step
|
||||
run: nix develop -c cargo run -- gen-stub-lib examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
- name: check that the platform`s produced dylib is loadable
|
||||
run: cd examples/platform-switching/rust-platform && nix develop -c cargo test --release --locked
|
||||
|
||||
- name: test aarch64 dev backend
|
||||
run: nix develop -c cargo nextest-gen-dev --locked --release --no-fail-fast
|
||||
|
||||
|
|
8
.github/workflows/nix_macos_x86_64.yml
vendored
8
.github/workflows/nix_macos_x86_64.yml
vendored
|
@ -16,15 +16,9 @@ jobs:
|
|||
|
||||
- uses: cachix/install-nix-action@v22
|
||||
|
||||
- name: execute cli_run tests only, the full tests take too long but are run nightly
|
||||
- name: execute cli_tests tests only, the full tests take too long but are run nightly
|
||||
run: nix develop -c cargo test --locked --release -p roc_cli -- --skip hello_gui
|
||||
# see 5932 for hello_gui
|
||||
|
||||
- name: roc test all builtins
|
||||
run: nix develop -c ./ci/roc_test_builtins.sh
|
||||
|
||||
- name: make a libapp.so for the next step
|
||||
run: nix develop -c cargo run -- gen-stub-lib examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
- name: check that the platform`s produced dylib is loadable
|
||||
run: cd examples/platform-switching/rust-platform && nix develop -c cargo test --release --locked
|
||||
|
|
|
@ -26,17 +26,11 @@ jobs:
|
|||
- name: rename nightly folder
|
||||
run: mv roc_nightly* roc_nightly
|
||||
|
||||
- name: test roc hello world
|
||||
run: cd roc_nightly && ./roc examples/helloWorld.roc
|
||||
|
||||
- name: test platform switching rust
|
||||
run: cd roc_nightly && ./roc examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
- name: test platform switching zig
|
||||
run: cd roc_nightly && ./roc examples/platform-switching/rocLovesZig.roc
|
||||
run: cd roc_nightly && ./roc examples/platform-switching/rocLovesZig.roc --build-host --suppress-build-host-warning
|
||||
|
||||
- name: test platform switching c
|
||||
run: cd roc_nightly && ./roc examples/platform-switching/rocLovesC.roc
|
||||
run: cd roc_nightly && ./roc examples/platform-switching/rocLovesC.roc --build-host --suppress-build-host-warning
|
||||
|
||||
- name: test repl
|
||||
run: |
|
||||
|
|
5
.github/workflows/ubuntu_x86_64.yml
vendored
5
.github/workflows/ubuntu_x86_64.yml
vendored
|
@ -37,14 +37,11 @@ jobs:
|
|||
|
||||
- name: regular rust tests
|
||||
# see #5904 for skipped test
|
||||
run: cargo test --locked --release -- --skip cli_run::expects_dev_and_test
|
||||
run: cargo test --locked --release -- --skip cli_tests::expects_dev_and_test
|
||||
|
||||
- name: tests examples in docs
|
||||
run: cargo test --doc --release
|
||||
|
||||
- name: check that the platform`s produced dylib is loadable
|
||||
run: cd examples/platform-switching/rust-platform && LD_LIBRARY_PATH=. cargo test --release --locked
|
||||
|
||||
- name: test the dev backend # these tests require an explicit feature flag
|
||||
run: cargo test --locked --release --package test_gen --no-default-features --features gen-dev
|
||||
|
||||
|
|
33
Cargo.lock
generated
33
Cargo.lock
generated
|
@ -463,20 +463,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
|
||||
|
||||
[[package]]
|
||||
name = "cli_utils"
|
||||
name = "cli_test_utils"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"const_format",
|
||||
"criterion",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"rlimit",
|
||||
"roc_cli",
|
||||
"roc_collections",
|
||||
"roc_command_utils",
|
||||
"roc_load",
|
||||
"roc_module",
|
||||
"roc_reporting",
|
||||
"serde",
|
||||
"serde-xml-rs",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
|
@ -2383,13 +2385,14 @@ dependencies = [
|
|||
"bumpalo",
|
||||
"chrono",
|
||||
"clap 4.4.6",
|
||||
"cli_utils",
|
||||
"cli_test_utils",
|
||||
"const_format",
|
||||
"criterion",
|
||||
"distance",
|
||||
"errno",
|
||||
"indoc",
|
||||
"inkwell",
|
||||
"insta",
|
||||
"libc",
|
||||
"libloading",
|
||||
"mimalloc",
|
||||
|
@ -2418,10 +2421,8 @@ dependencies = [
|
|||
"roc_repl_expect",
|
||||
"roc_reporting",
|
||||
"roc_target",
|
||||
"roc_test_utils",
|
||||
"roc_tracing",
|
||||
"roc_wasm_interp",
|
||||
"serial_test",
|
||||
"signal-hook",
|
||||
"strum",
|
||||
"target-lexicon",
|
||||
|
@ -2626,7 +2627,7 @@ name = "roc_glue"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"cli_utils",
|
||||
"cli_test_utils",
|
||||
"dircpy",
|
||||
"fnv",
|
||||
"indexmap",
|
||||
|
@ -3445,18 +3446,6 @@ dependencies = [
|
|||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-xml-rs"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_cbor"
|
||||
version = "0.11.2"
|
||||
|
@ -4362,7 +4351,7 @@ name = "valgrind"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"cli_utils",
|
||||
"cli_test_utils",
|
||||
"indoc",
|
||||
"roc_build",
|
||||
"roc_command_utils",
|
||||
|
@ -4828,12 +4817,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
|
|
|
@ -5,7 +5,7 @@ members = [
|
|||
"crates/fs",
|
||||
"crates/glue",
|
||||
"crates/cli",
|
||||
"crates/cli_utils",
|
||||
"crates/cli_test_utils",
|
||||
"crates/highlight",
|
||||
"crates/error_macros",
|
||||
"crates/reporting",
|
||||
|
@ -19,7 +19,7 @@ members = [
|
|||
"crates/roc_std",
|
||||
"crates/test_utils",
|
||||
"crates/test_utils_dir",
|
||||
"crates/valgrind",
|
||||
"crates/valgrind_tests",
|
||||
"crates/tracing",
|
||||
"crates/utils/*",
|
||||
"crates/soa",
|
||||
|
@ -173,7 +173,6 @@ schemars = "0.8.12"
|
|||
serde = { version = "1.0.153", features = [
|
||||
"derive",
|
||||
] } # update roc_std/Cargo.toml on change
|
||||
serde-xml-rs = "0.6.0"
|
||||
serde_json = "1.0.94" # update roc_std/Cargo.toml on change
|
||||
serial_test = "1.0.0"
|
||||
signal-hook = "0.3.15"
|
||||
|
|
|
@ -28,10 +28,8 @@ mv roc_nightly* roc_nightly
|
|||
|
||||
cd roc_nightly
|
||||
|
||||
# test roc hello world
|
||||
./roc examples/helloWorld.roc
|
||||
|
||||
# test rust platform
|
||||
# test rust platform (first prebuild the host)
|
||||
examples/platform-switching/rust-platform/build.sh
|
||||
./roc examples/platform-switching/rocLovesRust.roc
|
||||
|
||||
# test zig platform
|
||||
|
|
|
@ -54,6 +54,6 @@ fi
|
|||
./jump-start.sh
|
||||
|
||||
# build the basic cli platform
|
||||
roc build.roc --prebuilt-platform
|
||||
roc build.roc
|
||||
|
||||
cd ..
|
||||
|
|
|
@ -47,6 +47,6 @@ cd ..
|
|||
|
||||
cd basic-webserver
|
||||
|
||||
roc build.roc --prebuilt-platform
|
||||
roc build.roc
|
||||
|
||||
cd ..
|
||||
|
|
|
@ -12,7 +12,7 @@ mkdir -p $1 $1/examples $1/crates/compiler/builtins/bitcode
|
|||
mv target/release-with-lto/{roc,roc_language_server,lib} $1
|
||||
mv LICENSE LEGAL_DETAILS $1
|
||||
|
||||
mv examples/{helloWorld.roc,platform-switching,cli} $1/examples
|
||||
mv examples/{platform-switching,cli} $1/examples
|
||||
|
||||
mv crates/roc_std $1/crates
|
||||
mv crates/compiler/builtins/bitcode/src $1/crates/compiler/builtins/bitcode
|
||||
|
|
|
@ -12,9 +12,9 @@ cargo doc --package roc_ast --open
|
|||
|
||||
The `roc` binary that brings together all functionality in the Roc toolset.
|
||||
|
||||
## `cli_utils/` - `cli_utils`
|
||||
## `cli_test_utils/` - `cli_test_utils`
|
||||
|
||||
Provides shared code for cli tests and benchmarks.
|
||||
Provides shared code for cli tests, cli benchmarks, glue tests, valgrind crate.
|
||||
|
||||
## `compiler/`
|
||||
|
||||
|
|
|
@ -90,15 +90,14 @@ roc_repl_expect = { path = "../repl_expect" }
|
|||
|
||||
|
||||
[dev-dependencies]
|
||||
cli_utils = { path = "../cli_utils" }
|
||||
roc_test_utils = { path = "../test_utils" }
|
||||
cli_test_utils = { path = "../cli_test_utils" }
|
||||
roc_command_utils = { path = "../utils/command" }
|
||||
|
||||
criterion.workspace = true
|
||||
indoc.workspace = true
|
||||
parking_lot.workspace = true
|
||||
pretty_assertions.workspace = true
|
||||
serial_test.workspace = true
|
||||
insta.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
chrono.workspace = true
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use cli_utils::bench_utils::{
|
||||
use cli_test_utils::bench_utils::{
|
||||
bench_cfold, bench_deriv, bench_nqueens, bench_quicksort, bench_rbtree_ck,
|
||||
};
|
||||
use criterion::{measurement::WallTime, BenchmarkGroup, Criterion, SamplingMode};
|
||||
|
|
|
@ -263,7 +263,7 @@ mod tests {
|
|||
use std::io::Write;
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
const FORMATTED_ROC: &str = r#"app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
const FORMATTED_ROC: &str = r#"app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.Stdout
|
||||
import pf.Stdin
|
||||
|
@ -273,11 +273,7 @@ main =
|
|||
name = Stdin.line!
|
||||
Stdout.line! "Hi $(name)!""#;
|
||||
|
||||
const UNFORMATTED_ROC: &str = r#"app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
|
||||
import pf.Stdout
|
||||
import pf.Stdin
|
||||
const UNFORMATTED_ROC: &str = r#"app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
main =
|
||||
Stdout.line! "What's your name?"
|
||||
|
|
|
@ -54,7 +54,6 @@ pub const CMD_VERSION: &str = "version";
|
|||
pub const CMD_FORMAT: &str = "format";
|
||||
pub const CMD_TEST: &str = "test";
|
||||
pub const CMD_GLUE: &str = "glue";
|
||||
pub const CMD_GEN_STUB_LIB: &str = "gen-stub-lib";
|
||||
pub const CMD_PREPROCESS_HOST: &str = "preprocess-host";
|
||||
|
||||
pub const FLAG_EMIT_LLVM_IR: &str = "emit-llvm-ir";
|
||||
|
@ -72,7 +71,8 @@ pub const FLAG_VERBOSE: &str = "verbose";
|
|||
pub const FLAG_NO_COLOR: &str = "no-color";
|
||||
pub const FLAG_NO_HEADER: &str = "no-header";
|
||||
pub const FLAG_LINKER: &str = "linker";
|
||||
pub const FLAG_PREBUILT: &str = "prebuilt-platform";
|
||||
pub const FLAG_BUILD_HOST: &str = "build-host";
|
||||
pub const FLAG_SUPPRESS_BUILD_HOST_WARNING: &str = "suppress-build-host-warning";
|
||||
pub const FLAG_CHECK: &str = "check";
|
||||
pub const FLAG_STDIN: &str = "stdin";
|
||||
pub const FLAG_STDOUT: &str = "stdout";
|
||||
|
@ -142,9 +142,15 @@ pub fn build_app() -> Command {
|
|||
.value_parser(["surgical", "legacy"])
|
||||
.required(false);
|
||||
|
||||
let flag_prebuilt = Arg::new(FLAG_PREBUILT)
|
||||
.long(FLAG_PREBUILT)
|
||||
.help("Assume the platform has been prebuilt and skip rebuilding the platform\n(This is enabled implicitly when using `roc build` with a --target other than `--target <current machine>`, unless the target is wasm.)")
|
||||
let flag_build_host = Arg::new(FLAG_BUILD_HOST)
|
||||
.long(FLAG_BUILD_HOST)
|
||||
.help("WARNING: platforms are responsible for building hosts, this flag will be removed when internal test platforms have a build script")
|
||||
.action(ArgAction::SetTrue)
|
||||
.required(false);
|
||||
|
||||
let flag_suppress_build_host_warning = Arg::new(FLAG_SUPPRESS_BUILD_HOST_WARNING)
|
||||
.long(FLAG_SUPPRESS_BUILD_HOST_WARNING)
|
||||
.help("WARNING: platforms are responsible for building hosts, this flag will be removed when internal test platforms have a build script")
|
||||
.action(ArgAction::SetTrue)
|
||||
.required(false);
|
||||
|
||||
|
@ -201,7 +207,8 @@ pub fn build_app() -> Command {
|
|||
.arg(flag_profiling.clone())
|
||||
.arg(flag_time.clone())
|
||||
.arg(flag_linker.clone())
|
||||
.arg(flag_prebuilt.clone())
|
||||
.arg(flag_build_host.clone())
|
||||
.arg(flag_suppress_build_host_warning.clone())
|
||||
.arg(flag_fuzz.clone())
|
||||
.arg(flag_wasm_stack_size_kb)
|
||||
.arg(
|
||||
|
@ -253,7 +260,8 @@ pub fn build_app() -> Command {
|
|||
.arg(flag_profiling.clone())
|
||||
.arg(flag_time.clone())
|
||||
.arg(flag_linker.clone())
|
||||
.arg(flag_prebuilt.clone())
|
||||
.arg(flag_build_host.clone())
|
||||
.arg(flag_suppress_build_host_warning.clone())
|
||||
.arg(flag_fuzz.clone())
|
||||
.arg(
|
||||
Arg::new(FLAG_VERBOSE)
|
||||
|
@ -266,6 +274,7 @@ pub fn build_app() -> Command {
|
|||
Arg::new(ROC_FILE)
|
||||
.help("The .roc file to test")
|
||||
.value_parser(value_parser!(PathBuf))
|
||||
.num_args(0..)
|
||||
.required(false)
|
||||
.default_value(DEFAULT_ROC_FILENAME)
|
||||
)
|
||||
|
@ -298,7 +307,8 @@ pub fn build_app() -> Command {
|
|||
.arg(flag_profiling.clone())
|
||||
.arg(flag_time.clone())
|
||||
.arg(flag_linker.clone())
|
||||
.arg(flag_prebuilt.clone())
|
||||
.arg(flag_build_host.clone())
|
||||
.arg(flag_suppress_build_host_warning.clone())
|
||||
.arg(flag_fuzz.clone())
|
||||
.arg(roc_file_to_run.clone())
|
||||
.arg(args_for_app.clone().last(true))
|
||||
|
@ -313,7 +323,8 @@ pub fn build_app() -> Command {
|
|||
.arg(flag_profiling.clone())
|
||||
.arg(flag_time.clone())
|
||||
.arg(flag_linker.clone())
|
||||
.arg(flag_prebuilt.clone())
|
||||
.arg(flag_build_host.clone())
|
||||
.arg(flag_suppress_build_host_warning.clone())
|
||||
.arg(flag_fuzz.clone())
|
||||
.arg(roc_file_to_run.clone())
|
||||
.arg(args_for_app.clone().last(true))
|
||||
|
@ -404,23 +415,6 @@ pub fn build_app() -> Command {
|
|||
.default_value(DEFAULT_ROC_FILENAME)
|
||||
)
|
||||
)
|
||||
.subcommand(Command::new(CMD_GEN_STUB_LIB)
|
||||
.about("Generate a stubbed shared library that can be used for linking a platform binary.\nThe stubbed library has prototypes, but no function bodies.\n\nNote: This command will be removed in favor of just using `roc build` once all platforms support the surgical linker")
|
||||
.arg(
|
||||
Arg::new(ROC_FILE)
|
||||
.help("The .roc file for an app using the platform")
|
||||
.value_parser(value_parser!(PathBuf))
|
||||
.required(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::new(FLAG_TARGET)
|
||||
.long(FLAG_TARGET)
|
||||
.help("Choose a different target")
|
||||
.default_value(Into::<&'static str>::into(Target::default()))
|
||||
.value_parser(build_target_values_parser.clone())
|
||||
.required(false),
|
||||
)
|
||||
)
|
||||
.subcommand(Command::new(CMD_PREPROCESS_HOST)
|
||||
.about("Runs the surgical linker preprocessor to generate `.rh` and `.rm` files.")
|
||||
.arg(
|
||||
|
@ -465,7 +459,8 @@ pub fn build_app() -> Command {
|
|||
.arg(flag_profiling)
|
||||
.arg(flag_time)
|
||||
.arg(flag_linker)
|
||||
.arg(flag_prebuilt)
|
||||
.arg(flag_build_host)
|
||||
.arg(flag_suppress_build_host_warning)
|
||||
.arg(flag_fuzz)
|
||||
.arg(roc_file_to_run)
|
||||
.arg(args_for_app.trailing_var_arg(true))
|
||||
|
@ -522,8 +517,11 @@ pub fn test(matches: &ArgMatches, target: Target) -> io::Result<i32> {
|
|||
Some(n) => Threading::AtMost(*n),
|
||||
};
|
||||
|
||||
let path = matches.get_one::<PathBuf>(ROC_FILE).unwrap();
|
||||
let paths: Vec<_> = matches.get_many::<PathBuf>(ROC_FILE).unwrap().collect();
|
||||
|
||||
let paths: Vec<_> = {
|
||||
let mut flatten_paths: Vec<_> = vec![];
|
||||
for path in paths.into_iter() {
|
||||
// Spawn the root task
|
||||
if !path.exists() {
|
||||
let current_dir = env::current_dir().unwrap();
|
||||
|
@ -541,10 +539,20 @@ pub fn test(matches: &ArgMatches, target: Target) -> io::Result<i32> {
|
|||
}
|
||||
_ => eprintln!("\nThis file was not found: {expected_file_path_string}\n\nYou can run `roc help` for more information on how to provide a .roc file.\n"),
|
||||
}
|
||||
|
||||
process::exit(1);
|
||||
} else if path.is_dir() {
|
||||
find_all_roc_files(path, &mut flatten_paths);
|
||||
} else {
|
||||
flatten_paths.push(path.clone());
|
||||
}
|
||||
}
|
||||
flatten_paths
|
||||
};
|
||||
|
||||
let mut all_files_total_failed_count = 0;
|
||||
let mut all_files_total_passed_count = 0;
|
||||
|
||||
for path in paths.iter() {
|
||||
let arena = &arena;
|
||||
let function_kind = FunctionKind::from_env();
|
||||
|
||||
|
@ -649,8 +657,23 @@ pub fn test(matches: &ArgMatches, target: Target) -> io::Result<i32> {
|
|||
}
|
||||
|
||||
let total_duration = start_time.elapsed();
|
||||
|
||||
all_files_total_failed_count += total_failed_count;
|
||||
all_files_total_passed_count += total_passed_count;
|
||||
if total_failed_count == 0 && total_passed_count == 0 {
|
||||
// Only report no expectations found once.
|
||||
continue;
|
||||
} else if matches.get_flag(FLAG_VERBOSE) {
|
||||
println!("Compiled in {} ms.", compilation_duration.as_millis());
|
||||
for module_test_results in results_by_module {
|
||||
print_test_results(module_test_results, &sources);
|
||||
}
|
||||
} else {
|
||||
let test_summary_str =
|
||||
test_summary(total_failed_count, total_passed_count, total_duration);
|
||||
println!("{test_summary_str}");
|
||||
}
|
||||
}
|
||||
if all_files_total_failed_count == 0 && all_files_total_passed_count == 0 {
|
||||
// TODO print this in a more nicely formatted way!
|
||||
println!("No expectations were found.");
|
||||
|
||||
|
@ -661,18 +684,32 @@ pub fn test(matches: &ArgMatches, target: Target) -> io::Result<i32> {
|
|||
// running tests altogether!
|
||||
Ok(2)
|
||||
} else {
|
||||
if matches.get_flag(FLAG_VERBOSE) {
|
||||
println!("Compiled in {} ms.", compilation_duration.as_millis());
|
||||
for module_test_results in results_by_module {
|
||||
print_test_results(module_test_results, &sources);
|
||||
Ok((all_files_total_failed_count > 0) as i32)
|
||||
}
|
||||
} else {
|
||||
let test_summary_str =
|
||||
test_summary(total_failed_count, total_passed_count, total_duration);
|
||||
println!("{test_summary_str}");
|
||||
}
|
||||
|
||||
Ok((total_failed_count > 0) as i32)
|
||||
fn find_all_roc_files(path: &PathBuf, flatten_paths: &mut Vec<PathBuf>) {
|
||||
if path.is_dir() {
|
||||
if let Ok(entries) = std::fs::read_dir(path) {
|
||||
entries.for_each(|entry| {
|
||||
if let Ok(entry) = entry {
|
||||
let entry_path = entry.path();
|
||||
find_all_roc_files(&entry_path, flatten_paths);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
eprintln!(
|
||||
"\nSomething went wrong opening the directory {}\n",
|
||||
path.display()
|
||||
);
|
||||
}
|
||||
} else if path.is_file() {
|
||||
match path.extension() {
|
||||
Some(extension) if extension == "roc" => {
|
||||
flatten_paths.push(path.clone());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -731,7 +768,6 @@ pub fn build(
|
|||
roc_cache_dir: RocCacheDir<'_>,
|
||||
link_type: LinkType,
|
||||
) -> io::Result<i32> {
|
||||
use roc_build::program::build_file;
|
||||
use BuildConfig::*;
|
||||
|
||||
let path = matches.get_one::<PathBuf>(ROC_FILE).unwrap();
|
||||
|
@ -879,17 +915,10 @@ pub fn build(
|
|||
LinkingStrategy::Surgical
|
||||
};
|
||||
|
||||
let prebuilt = {
|
||||
let cross_compile = target != Target::default();
|
||||
let targeting_wasm = matches!(target.architecture(), Architecture::Wasm32);
|
||||
|
||||
matches.get_flag(FLAG_PREBUILT) ||
|
||||
// When compiling for a different target, assume a prebuilt platform.
|
||||
// Otherwise compilation would most likely fail because many toolchains
|
||||
// assume you're compiling for the current machine. We make an exception
|
||||
// for Wasm, because cross-compiling is the norm in that case.
|
||||
(cross_compile && !targeting_wasm)
|
||||
};
|
||||
// All hosts should be prebuilt, this flag keeps the rebuilding behvaiour
|
||||
// as required for internal tests
|
||||
let build_host = matches.get_flag(FLAG_BUILD_HOST);
|
||||
let suppress_build_host_warning = matches.get_flag(FLAG_SUPPRESS_BUILD_HOST_WARNING);
|
||||
|
||||
let fuzz = matches.get_flag(FLAG_FUZZ);
|
||||
if fuzz && !matches!(code_gen_backend, CodeGenBackend::Llvm(_)) {
|
||||
|
@ -917,7 +946,7 @@ pub fn build(
|
|||
|
||||
let load_config = standard_load_config(target, build_ordering, threading);
|
||||
|
||||
let res_binary_path = build_file(
|
||||
let res_binary_path = roc_build::program::build_file(
|
||||
&arena,
|
||||
target,
|
||||
path.to_owned(),
|
||||
|
@ -925,7 +954,8 @@ pub fn build(
|
|||
emit_timings,
|
||||
link_type,
|
||||
linking_strategy,
|
||||
prebuilt,
|
||||
build_host,
|
||||
suppress_build_host_warning,
|
||||
wasm_dev_stack_bytes,
|
||||
roc_cache_dir,
|
||||
load_config,
|
||||
|
|
|
@ -4,17 +4,16 @@ use roc_build::link::LinkType;
|
|||
use roc_build::program::{check_file, CodeGenBackend};
|
||||
use roc_cli::{
|
||||
build_app, format_files, format_src, test, BuildConfig, FormatMode, CMD_BUILD, CMD_CHECK,
|
||||
CMD_DEV, CMD_DOCS, CMD_FORMAT, CMD_GEN_STUB_LIB, 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_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,
|
||||
CMD_DEV, CMD_DOCS, CMD_FORMAT, 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_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,
|
||||
};
|
||||
use roc_docs::generate_docs_html;
|
||||
use roc_error_macros::user_error;
|
||||
use roc_gen_dev::AssemblyBackendMode;
|
||||
use roc_gen_llvm::llvm::build::LlvmBackendMode;
|
||||
use roc_load::{FunctionKind, LoadingProblem, Threading};
|
||||
use roc_load::{LoadingProblem, Threading};
|
||||
use roc_packaging::cache::{self, RocCacheDir};
|
||||
use roc_target::Target;
|
||||
use std::fs::{self, FileType};
|
||||
|
@ -120,21 +119,6 @@ fn main() -> io::Result<()> {
|
|||
Ok(1)
|
||||
}
|
||||
}
|
||||
Some((CMD_GEN_STUB_LIB, matches)) => {
|
||||
let input_path = matches.get_one::<PathBuf>(ROC_FILE).unwrap();
|
||||
let target = matches
|
||||
.get_one::<String>(FLAG_TARGET)
|
||||
.and_then(|s| Target::from_str(s).ok())
|
||||
.unwrap_or_default();
|
||||
let function_kind = FunctionKind::from_env();
|
||||
roc_linker::generate_stub_lib(
|
||||
input_path,
|
||||
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
|
||||
target,
|
||||
function_kind,
|
||||
);
|
||||
Ok(0)
|
||||
}
|
||||
Some((CMD_PREPROCESS_HOST, matches)) => {
|
||||
let preprocess_host_err =
|
||||
{ |msg: String| user_error!("\n\n ERROR PRE-PROCESSING HOST: {}\n\n", msg) };
|
||||
|
@ -169,10 +153,14 @@ fn main() -> io::Result<()> {
|
|||
|
||||
let verbose_and_time = matches.get_one::<bool>(roc_cli::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());
|
||||
|
||||
roc_linker::preprocess_host(
|
||||
target,
|
||||
host_path,
|
||||
platform_path,
|
||||
metadata_path.as_path(),
|
||||
preprocessed_path.as_path(),
|
||||
dylib_path,
|
||||
*verbose_and_time,
|
||||
*verbose_and_time,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
# see https://github.com/roc-lang/roc/issues/985
|
||||
main : Task {} []
|
||||
main = closure1 {}
|
||||
# |> Task.after (\_ -> closure2 {})
|
||||
# |> Task.after (\_ -> closure3 {})
|
||||
# |> Task.after (\_ -> closure4 {})
|
||||
main =
|
||||
closure1 {}
|
||||
|> Task.await (\_ -> closure2 {})
|
||||
|> Task.await (\_ -> closure3 {})
|
||||
|> Task.await (\_ -> closure4 {})
|
||||
# ---
|
||||
closure1 : {} -> Task {} []
|
||||
closure1 = \_ ->
|
||||
|
@ -17,32 +17,32 @@ toUnitBorrowed = \x -> Str.countUtf8Bytes x
|
|||
foo = \f, x -> f x
|
||||
|
||||
# ---
|
||||
# closure2 : {} -> Task.Task {} []
|
||||
# closure2 = \_ ->
|
||||
# x : Str
|
||||
# x = "a long string such that it's malloced"
|
||||
#
|
||||
# Task.succeed {}
|
||||
# |> Task.map (\_ -> x)
|
||||
# |> Task.map toUnit
|
||||
#
|
||||
# toUnit = \_ -> {}
|
||||
#
|
||||
closure2 : {} -> Task {} []
|
||||
closure2 = \_ ->
|
||||
x : Str
|
||||
x = "a long string such that it's malloced"
|
||||
|
||||
Task.ok {}
|
||||
|> Task.map (\_ -> x)
|
||||
|> Task.map toUnit
|
||||
|
||||
toUnit = \_ -> {}
|
||||
|
||||
# # ---
|
||||
# closure3 : {} -> Task.Task {} []
|
||||
# closure3 = \_ ->
|
||||
# x : Str
|
||||
# x = "a long string such that it's malloced"
|
||||
#
|
||||
# Task.succeed {}
|
||||
# |> Task.after (\_ -> Task.succeed x |> Task.map (\_ -> {}))
|
||||
#
|
||||
closure3 : {} -> Task {} []
|
||||
closure3 = \_ ->
|
||||
x : Str
|
||||
x = "a long string such that it's malloced"
|
||||
|
||||
Task.ok {}
|
||||
|> Task.await (\_ -> Task.ok x |> Task.map (\_ -> {}))
|
||||
|
||||
# # ---
|
||||
# closure4 : {} -> Task.Task {} []
|
||||
# closure4 = \_ ->
|
||||
# x : Str
|
||||
# x = "a long string such that it's malloced"
|
||||
#
|
||||
# Task.succeed {}
|
||||
# |> Task.after (\_ -> Task.succeed x)
|
||||
# |> Task.map (\_ -> {})
|
||||
closure4 : {} -> Task {} []
|
||||
closure4 = \_ ->
|
||||
x : Str
|
||||
x = "a long string such that it's malloced"
|
||||
|
||||
Task.ok {}
|
||||
|> Task.await (\_ -> Task.ok x)
|
||||
|> Task.map (\_ -> {})
|
||||
|
|
3
crates/cli/tests/benchmarks/platform/app.roc
Normal file
3
crates/cli/tests/benchmarks/platform/app.roc
Normal file
|
@ -0,0 +1,3 @@
|
|||
app [main] { pf: platform "main.roc" }
|
||||
|
||||
main = Task.ok {}
|
|
@ -112,8 +112,6 @@ comptime {
|
|||
const Unit = extern struct {};
|
||||
|
||||
pub fn main() !u8 {
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
|
||||
// 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)).?;
|
||||
|
@ -123,26 +121,15 @@ pub fn main() !u8 {
|
|||
roc_dealloc(raw_output, @alignOf(u64));
|
||||
}
|
||||
|
||||
var timer = std.time.Timer.start() catch unreachable;
|
||||
|
||||
roc__mainForHost_1_exposed_generic(output);
|
||||
|
||||
const closure_data_pointer = @as([*]u8, @ptrCast(output));
|
||||
|
||||
call_the_closure(closure_data_pointer);
|
||||
|
||||
const nanos = timer.read();
|
||||
const seconds = (@as(f64, @floatFromInt(nanos)) / 1_000_000_000.0);
|
||||
|
||||
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn to_seconds(tms: std.os.timespec) f64 {
|
||||
return @as(f64, @floatFromInt(tms.tv_sec)) + (@as(f64, @floatFromInt(tms.tv_nsec)) / 1_000_000_000.0);
|
||||
}
|
||||
|
||||
fn call_the_closure(closure_data_pointer: [*]u8) void {
|
||||
const allocator = std.heap.page_allocator;
|
||||
|
||||
|
|
|
@ -1,255 +0,0 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
|
||||
Color : [Red, Black]
|
||||
|
||||
Tree a b : [Leaf, Node Color (Tree a b) a b (Tree a b)]
|
||||
|
||||
Map : Tree I64 Bool
|
||||
|
||||
ConsList a : [Nil, Cons a (ConsList a)]
|
||||
|
||||
main : Task {} []
|
||||
main =
|
||||
{ value, isError } = PlatformTasks.getInt!
|
||||
inputResult =
|
||||
if isError then
|
||||
Err GetIntError
|
||||
else
|
||||
Ok value
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
m = makeMap n # koka original n = 4_200_000
|
||||
val = fold (\_, v, r -> if v then r + 1 else r) m 0
|
||||
|
||||
val
|
||||
|> Num.toStr
|
||||
|> PlatformTasks.putLine
|
||||
|
||||
Err GetIntError ->
|
||||
PlatformTasks.putLine "Error: Failed to get Integer from stdin."
|
||||
|
||||
boom : Str -> a
|
||||
boom = \_ -> boom ""
|
||||
|
||||
makeMap : I64 -> Map
|
||||
makeMap = \n ->
|
||||
makeMapHelp n n Leaf
|
||||
|
||||
makeMapHelp : I64, I64, Map -> Map
|
||||
makeMapHelp = \total, n, m ->
|
||||
when n is
|
||||
0 -> m
|
||||
_ ->
|
||||
n1 = n - 1
|
||||
|
||||
powerOf10 =
|
||||
n |> Num.isMultipleOf 10
|
||||
|
||||
t1 = insert m n powerOf10
|
||||
|
||||
isFrequency =
|
||||
n |> Num.isMultipleOf 4
|
||||
|
||||
key = n1 + ((total - n1) // 5)
|
||||
t2 = if isFrequency then delete t1 key else t1
|
||||
|
||||
makeMapHelp total n1 t2
|
||||
|
||||
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))
|
||||
|
||||
depth : Tree * * -> I64
|
||||
depth = \tree ->
|
||||
when tree is
|
||||
Leaf -> 1
|
||||
Node _ l _ _ r -> 1 + depth l + depth r
|
||||
|
||||
insert : Map, I64, Bool -> Map
|
||||
insert = \t, k, v -> if isRed t then setBlack (ins t k v) else ins t k v
|
||||
|
||||
setBlack : Tree a b -> Tree a b
|
||||
setBlack = \tree ->
|
||||
when tree is
|
||||
Node _ l k v r -> Node Black l k v r
|
||||
_ -> tree
|
||||
|
||||
isRed : Tree a b -> Bool
|
||||
isRed = \tree ->
|
||||
when tree is
|
||||
Node Red _ _ _ _ -> Bool.true
|
||||
_ -> Bool.false
|
||||
|
||||
ins : Tree I64 Bool, I64, Bool -> Tree I64 Bool
|
||||
ins = \tree, kx, vx ->
|
||||
when tree is
|
||||
Leaf ->
|
||||
Node Red Leaf kx vx Leaf
|
||||
|
||||
Node Red a ky vy b ->
|
||||
when Num.compare kx ky is
|
||||
LT -> Node Red (ins a kx vx) ky vy b
|
||||
GT -> Node Red a ky vy (ins b kx vx)
|
||||
EQ -> Node Red a ky vy (ins b kx vx)
|
||||
|
||||
Node Black a ky vy b ->
|
||||
when Num.compare kx ky is
|
||||
LT ->
|
||||
when isRed a is
|
||||
Bool.true -> balanceLeft (ins a kx vx) ky vy b
|
||||
Bool.false -> Node Black (ins a kx vx) ky vy b
|
||||
|
||||
GT ->
|
||||
when isRed b is
|
||||
Bool.true -> balanceRight a ky vy (ins b kx vx)
|
||||
Bool.false -> Node Black a ky vy (ins b kx vx)
|
||||
|
||||
EQ ->
|
||||
Node Black a kx vx b
|
||||
|
||||
balanceLeft : Tree a b, a, b, Tree a b -> Tree a b
|
||||
balanceLeft = \l, k, v, r ->
|
||||
when l is
|
||||
Leaf ->
|
||||
Leaf
|
||||
|
||||
Node _ (Node Red lx kx vx rx) ky vy ry ->
|
||||
Node Red (Node Black lx kx vx rx) ky vy (Node Black ry k v r)
|
||||
|
||||
Node _ ly ky vy (Node Red lx kx vx rx) ->
|
||||
Node Red (Node Black ly ky vy lx) kx vx (Node Black rx k v r)
|
||||
|
||||
Node _ lx kx vx rx ->
|
||||
Node Black (Node Red lx kx vx rx) k v r
|
||||
|
||||
balanceRight : Tree a b, a, b, Tree a b -> Tree a b
|
||||
balanceRight = \l, k, v, r ->
|
||||
when r is
|
||||
Leaf ->
|
||||
Leaf
|
||||
|
||||
Node _ (Node Red lx kx vx rx) ky vy ry ->
|
||||
Node Red (Node Black l k v lx) kx vx (Node Black rx ky vy ry)
|
||||
|
||||
Node _ lx kx vx (Node Red ly ky vy ry) ->
|
||||
Node Red (Node Black l k v lx) kx vx (Node Black ly ky vy ry)
|
||||
|
||||
Node _ lx kx vx rx ->
|
||||
Node Black l k v (Node Red lx kx vx rx)
|
||||
|
||||
isBlack : Color -> Bool
|
||||
isBlack = \c ->
|
||||
when c is
|
||||
Black -> Bool.true
|
||||
Red -> Bool.false
|
||||
|
||||
Del a b : [Del (Tree a b) Bool]
|
||||
|
||||
setRed : Map -> Map
|
||||
setRed = \t ->
|
||||
when t is
|
||||
Node _ l k v r ->
|
||||
Node Red l k v r
|
||||
|
||||
_ ->
|
||||
t
|
||||
|
||||
makeBlack : Map -> Del I64 Bool
|
||||
makeBlack = \t ->
|
||||
when t is
|
||||
Node Red l k v r ->
|
||||
Del (Node Black l k v r) Bool.false
|
||||
|
||||
_ ->
|
||||
Del t Bool.true
|
||||
|
||||
rebalanceLeft = \c, l, k, v, r ->
|
||||
when l is
|
||||
Node Black _ _ _ _ ->
|
||||
Del (balanceLeft (setRed l) k v r) (isBlack c)
|
||||
|
||||
Node Red lx kx vx rx ->
|
||||
Del (Node Black lx kx vx (balanceLeft (setRed rx) k v r)) Bool.false
|
||||
|
||||
_ ->
|
||||
boom "unreachable"
|
||||
|
||||
rebalanceRight = \c, l, k, v, r ->
|
||||
when r is
|
||||
Node Black _ _ _ _ ->
|
||||
Del (balanceRight l k v (setRed r)) (isBlack c)
|
||||
|
||||
Node Red lx kx vx rx ->
|
||||
Del (Node Black (balanceRight l k v (setRed lx)) kx vx rx) Bool.false
|
||||
|
||||
_ ->
|
||||
boom "unreachable"
|
||||
|
||||
delMin = \t ->
|
||||
when t is
|
||||
Node Black Leaf k v r ->
|
||||
when r is
|
||||
Leaf ->
|
||||
Delmin (Del Leaf Bool.true) k v
|
||||
|
||||
_ ->
|
||||
Delmin (Del (setBlack r) Bool.false) k v
|
||||
|
||||
Node Red Leaf k v r ->
|
||||
Delmin (Del r Bool.false) k v
|
||||
|
||||
Node c l k v r ->
|
||||
when delMin l is
|
||||
Delmin (Del lx Bool.true) kx vx ->
|
||||
Delmin (rebalanceRight c lx k v r) kx vx
|
||||
|
||||
Delmin (Del lx Bool.false) kx vx ->
|
||||
Delmin (Del (Node c lx k v r) Bool.false) kx vx
|
||||
|
||||
Leaf ->
|
||||
Delmin (Del t Bool.false) 0 Bool.false
|
||||
|
||||
delete : Tree I64 Bool, I64 -> Tree I64 Bool
|
||||
delete = \t, k ->
|
||||
when del t k is
|
||||
Del tx _ ->
|
||||
setBlack tx
|
||||
|
||||
del : Tree I64 Bool, I64 -> Del I64 Bool
|
||||
del = \t, k ->
|
||||
when t is
|
||||
Leaf ->
|
||||
Del Leaf Bool.false
|
||||
|
||||
Node cx lx kx vx rx ->
|
||||
if (k < kx) then
|
||||
when del lx k is
|
||||
Del ly Bool.true ->
|
||||
rebalanceRight cx ly kx vx rx
|
||||
|
||||
Del ly Bool.false ->
|
||||
Del (Node cx ly kx vx rx) Bool.false
|
||||
else if (k > kx) then
|
||||
when del rx k is
|
||||
Del ry Bool.true ->
|
||||
rebalanceLeft cx lx kx vx ry
|
||||
|
||||
Del ry Bool.false ->
|
||||
Del (Node cx lx kx vx ry) Bool.false
|
||||
else
|
||||
when rx is
|
||||
Leaf ->
|
||||
if isBlack cx then makeBlack lx else Del lx Bool.false
|
||||
|
||||
Node _ _ _ _ _ ->
|
||||
when delMin rx is
|
||||
Delmin (Del ry Bool.true) ky vy ->
|
||||
rebalanceLeft cx lx ky vy ry
|
||||
|
||||
Delmin (Del ry Bool.false) ky vy ->
|
||||
Del (Node cx lx ky vy ry) Bool.false
|
|
@ -3,7 +3,6 @@ app [main] { pf: platform "platform/main.roc" }
|
|||
import pf.PlatformTasks
|
||||
import AStar
|
||||
|
||||
#main : Task {} *
|
||||
main =
|
||||
PlatformTasks.putLine! (showBool test1)
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
app [main] {
|
||||
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br",
|
||||
}
|
||||
|
||||
import pf.Stdout
|
||||
import pf.Arg
|
||||
|
||||
main =
|
||||
args = Arg.list! {}
|
||||
when List.first args is
|
||||
Ok argv0 -> Stdout.line argv0
|
||||
Err ListWasEmpty -> Stdout.line "Failed: argv was empty"
|
|
@ -1,18 +0,0 @@
|
|||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Stdin
|
||||
import pf.Stdout
|
||||
|
||||
main =
|
||||
Stdout.line! "\nLet's count down from 3 together - all you have to do is press <ENTER>."
|
||||
_ = Stdin.line!
|
||||
Task.loop 3 tick
|
||||
|
||||
tick = \n ->
|
||||
if n == 0 then
|
||||
Stdout.line! "🎉 SURPRISE! Happy Birthday! 🎂"
|
||||
Task.ok (Done {})
|
||||
else
|
||||
Stdout.line! (n |> Num.toStr |> \s -> "$(s)...")
|
||||
_ = Stdin.line!
|
||||
Task.ok (Step (n - 1))
|
|
@ -1,35 +0,0 @@
|
|||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Stdin
|
||||
import pf.Stdout
|
||||
|
||||
main =
|
||||
Stdout.line! "🗣 Shout into this cave and hear the echo! 👂👂👂"
|
||||
|
||||
Task.loop {} tick
|
||||
|
||||
tick : {} -> Task [Step {}, Done {}] _
|
||||
tick = \{} ->
|
||||
when Stdin.line |> Task.result! is
|
||||
Ok str -> Stdout.line (echo str) |> Task.map Step
|
||||
Err (StdinErr EndOfFile) -> Stdout.line (echo "Received end of input (EOF).") |> Task.map Done
|
||||
Err (StdinErr err) -> Stdout.line (echo "Unable to read input $(Inspect.toStr err)") |> Task.map Done
|
||||
|
||||
echo : Str -> Str
|
||||
echo = \shout ->
|
||||
silence = \length ->
|
||||
spaceInUtf8 = 32
|
||||
|
||||
List.repeat spaceInUtf8 length
|
||||
|
||||
shout
|
||||
|> Str.toUtf8
|
||||
|> List.mapWithIndex
|
||||
(\_, i ->
|
||||
length = (List.len (Str.toUtf8 shout) - i)
|
||||
phrase = (List.split (Str.toUtf8 shout) length).before
|
||||
|
||||
List.concat (silence (if i == 0 then 2 * length else length)) phrase)
|
||||
|> List.join
|
||||
|> Str.fromUtf8
|
||||
|> Result.withDefault ""
|
|
@ -1,30 +0,0 @@
|
|||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Stdout
|
||||
import pf.Stderr
|
||||
import pf.Env
|
||||
|
||||
main =
|
||||
task =
|
||||
Env.decode "EDITOR"
|
||||
|> Task.await (\editor -> Stdout.line "Your favorite editor is $(editor)!")
|
||||
|> Task.await (\{} -> Env.decode "SHLVL")
|
||||
|> Task.await
|
||||
(\lvl ->
|
||||
when lvl is
|
||||
1u8 -> Stdout.line "You're running this in a root shell!"
|
||||
n ->
|
||||
lvlStr = Num.toStr n
|
||||
|
||||
Stdout.line "Your current shell level is $(lvlStr)!")
|
||||
|> Task.await \{} -> Env.decode "LETTERS"
|
||||
|
||||
Task.attempt task \result ->
|
||||
when result is
|
||||
Ok letters ->
|
||||
joinedLetters = Str.joinWith letters " "
|
||||
|
||||
Stdout.line "Your favorite letters are: $(joinedLetters)"
|
||||
|
||||
Err _ ->
|
||||
Stderr.line "I couldn't find your favorite letters in the environment variables!"
|
|
@ -1,36 +0,0 @@
|
|||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Stdout
|
||||
import pf.File
|
||||
import pf.Path
|
||||
import pf.Env
|
||||
|
||||
main : Task {} [Exit I32 Str]_
|
||||
main =
|
||||
pathStr = "out.txt"
|
||||
|
||||
task =
|
||||
cwdPath = Env.cwd!
|
||||
cwdStr = Path.display cwdPath
|
||||
Stdout.line! "Current working directory: $(cwdStr)"
|
||||
|
||||
dirEntries = Path.listDir! cwdPath
|
||||
contentsStr = Str.joinWith (List.map dirEntries Path.display) "\n "
|
||||
Stdout.line! "Directory contents:\n $(contentsStr)\n"
|
||||
Stdout.line! "Writing a string to out.txt"
|
||||
File.writeUtf8! pathStr "a string!"
|
||||
contents = File.readUtf8! pathStr
|
||||
Stdout.line! "I read the file back. Its contents: \"$(contents)\""
|
||||
|
||||
when Task.result! task is
|
||||
Ok {} -> Stdout.line! "Successfully wrote a string to out.txt"
|
||||
Err err ->
|
||||
msg =
|
||||
when err is
|
||||
FileWriteErr _ PermissionDenied -> "PermissionDenied"
|
||||
FileWriteErr _ Unsupported -> "Unsupported"
|
||||
FileWriteErr _ (Unrecognized _ other) -> other
|
||||
FileReadErr _ _ -> "Error reading file"
|
||||
_ -> "Uh oh, there was an error!"
|
||||
|
||||
Task.err (Exit 1 msg)
|
|
@ -1,35 +0,0 @@
|
|||
# A Simple Markdown Example
|
||||
|
||||
This file contains `form.roc` embedded as a block in Markdown. It lets us test that `roc check` works with Markdown.
|
||||
|
||||
```roc
|
||||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Stdin
|
||||
import pf.Stdout
|
||||
|
||||
main =
|
||||
Stdout.line! "What's your first name?"
|
||||
firstName = Stdin.line!
|
||||
Stdout.line! "What's your last name?"
|
||||
lastName = Stdin.line!
|
||||
|
||||
Stdout.line "Hi, $(firstName) $(lastName)! 👋"
|
||||
```
|
||||
|
||||
Excitingly, we can have another block of Roc code as well! (In this case it is the same one...)
|
||||
|
||||
```roc
|
||||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Stdin
|
||||
import pf.Stdout
|
||||
|
||||
main =
|
||||
Stdout.line! "What's your first name?"
|
||||
firstName = Stdin.line!
|
||||
Stdout.line! "What's your last name?"
|
||||
lastName = Stdin.line!
|
||||
|
||||
Stdout.line "Hi, $(firstName) $(lastName)! 👋"
|
||||
```
|
|
@ -1,12 +0,0 @@
|
|||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Stdin
|
||||
import pf.Stdout
|
||||
|
||||
main =
|
||||
Stdout.line! "What's your first name?"
|
||||
firstName = Stdin.line!
|
||||
Stdout.line! "What's your last name?"
|
||||
lastName = Stdin.line!
|
||||
|
||||
Stdout.line "Hi, $(firstName) $(lastName)! 👋"
|
|
@ -1,23 +0,0 @@
|
|||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Http
|
||||
import pf.Stdout
|
||||
|
||||
main =
|
||||
request = {
|
||||
method: Get,
|
||||
headers: [],
|
||||
url: "http://www.example.com",
|
||||
mimeType: "",
|
||||
body: [],
|
||||
timeout: TimeoutMilliseconds 5000,
|
||||
}
|
||||
|
||||
resp = Http.send! request
|
||||
|
||||
output =
|
||||
when resp |> Http.handleStringResponse is
|
||||
Err err -> crash (Http.errorToString err)
|
||||
Ok body -> body
|
||||
|
||||
Stdout.line output
|
|
@ -1,12 +0,0 @@
|
|||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Stdout
|
||||
import "test-file.txt" as testFile
|
||||
|
||||
main =
|
||||
# Due to the functions we apply on testFile, it will be inferred as a List U8.
|
||||
testFile
|
||||
|> List.map Num.toU64
|
||||
|> List.sum
|
||||
|> Num.toStr
|
||||
|> Stdout.line!
|
|
@ -1,12 +0,0 @@
|
|||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Stdout
|
||||
import "test-file.txt" as testFile : _ # the _ is optional
|
||||
|
||||
main =
|
||||
# Due to the functions we apply on testFile, it will be inferred as a List U8.
|
||||
testFile
|
||||
|> List.map Num.toU64
|
||||
|> List.sum
|
||||
|> Num.toStr
|
||||
|> Stdout.line!
|
|
@ -1,7 +0,0 @@
|
|||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
|
||||
import pf.Stdout
|
||||
import "ingested-file.roc" as ownCode : Str
|
||||
|
||||
main =
|
||||
Stdout.line! "\nThis roc file can print its own source code. The source is:\n\n$(ownCode)"
|
|
@ -1,85 +0,0 @@
|
|||
app [main] {
|
||||
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br",
|
||||
}
|
||||
|
||||
import pf.Stdout
|
||||
|
||||
main =
|
||||
file = strParam { name: "file" }
|
||||
argParser =
|
||||
{ cliBuild <-
|
||||
file,
|
||||
count: numParam { name: "count" },
|
||||
doubled: numParam { name: "doubled" }
|
||||
|> cliMap \d -> d * 2,
|
||||
}
|
||||
|
||||
args = ["parse-args", "file.txt", "5", "7"]
|
||||
when argParser |> parseArgs args is
|
||||
Ok data -> Stdout.line "Success: $(Inspect.toStr data)"
|
||||
Err (FailedToParse message) -> Stdout.line "Failed: $(message)"
|
||||
|
||||
ArgParseErr : [NoMoreArgs, InvalidParam ParamConfig]
|
||||
|
||||
ParamConfig : {
|
||||
name : Str,
|
||||
type : [Num, Str],
|
||||
}
|
||||
|
||||
ArgParser out : {
|
||||
params : List ParamConfig,
|
||||
parser : List Str -> Result (out, List Str) ArgParseErr,
|
||||
}
|
||||
|
||||
strParam : { name : Str } -> ArgParser Str
|
||||
strParam = \{ name } ->
|
||||
parser = \args ->
|
||||
when args is
|
||||
[] -> Err NoMoreArgs
|
||||
[first, .. as rest] -> Ok (first, rest)
|
||||
|
||||
{ params: [{ name, type: Str }], parser }
|
||||
|
||||
numParam : { name : Str } -> ArgParser U64
|
||||
numParam = \{ name } ->
|
||||
param = { name, type: Num }
|
||||
parser = \args ->
|
||||
when args is
|
||||
[] -> Err NoMoreArgs
|
||||
[first, .. as rest] ->
|
||||
when Str.toU64 first is
|
||||
Ok num -> Ok (num, rest)
|
||||
Err InvalidNumStr -> Err (InvalidParam param)
|
||||
|
||||
{ params: [param], parser }
|
||||
|
||||
cliMap : ArgParser a, (a -> b) -> ArgParser b
|
||||
cliMap = \{ params, parser }, mapper ->
|
||||
mappedParser = \args ->
|
||||
(data, afterData) = parser? args
|
||||
|
||||
Ok (mapper data, afterData)
|
||||
|
||||
{
|
||||
params,
|
||||
parser: mappedParser,
|
||||
}
|
||||
|
||||
cliBuild : ArgParser a, ArgParser b, (a, b -> c) -> ArgParser c
|
||||
cliBuild = \firstWeaver, secondWeaver, combine ->
|
||||
allParams = List.concat firstWeaver.params secondWeaver.params
|
||||
combinedParser = \args ->
|
||||
(firstValue, afterFirst) = firstWeaver.parser? args
|
||||
(secondValue, afterSecond) = secondWeaver.parser? afterFirst
|
||||
|
||||
Ok (combine firstValue secondValue, afterSecond)
|
||||
|
||||
{ params: allParams, parser: combinedParser }
|
||||
|
||||
parseArgs : ArgParser a, List Str -> Result a [FailedToParse Str]
|
||||
parseArgs = \{ params: _, parser }, args ->
|
||||
when parser (List.dropFirst args 1) is
|
||||
Ok (data, []) -> Ok data
|
||||
Ok (_data, extraArgs) -> Err (FailedToParse "Got $(List.len extraArgs |> Inspect.toStr) extra args")
|
||||
Err NoMoreArgs -> Err (FailedToParse "I needed more args")
|
||||
Err (InvalidParam param) -> Err (FailedToParse "Parameter '$(param.name)' needed a $(Inspect.toStr param.type)")
|
|
@ -1,51 +0,0 @@
|
|||
app [main] {
|
||||
cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br",
|
||||
parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/0.5.2/9VrPjwfQQ1QeSL3CfmWr2Pr9DESdDIXy97pwpuq84Ck.tar.br",
|
||||
}
|
||||
|
||||
import cli.Stdout
|
||||
import cli.Stderr
|
||||
import parser.Core exposing [Parser, buildPrimitiveParser, many]
|
||||
import parser.String exposing [parseStr]
|
||||
|
||||
main =
|
||||
lettersInput = "AAAiBByAABBwBtCCCiAyArBBx"
|
||||
ifLetterA = \l -> l == A
|
||||
when parseStr (many letterParser) lettersInput is
|
||||
Ok letters ->
|
||||
letters
|
||||
|> List.keepIf ifLetterA
|
||||
|> List.map \_ -> 1
|
||||
|> List.sum
|
||||
|> Num.toStr
|
||||
|> \countLetterA -> Stdout.line "I counted $(countLetterA) letter A's!"
|
||||
|
||||
Err _ -> Stderr.line "Ooops, something went wrong parsing letters"
|
||||
|
||||
Letter : [A, B, C, Other]
|
||||
|
||||
letterParser : Parser (List U8) Letter
|
||||
letterParser =
|
||||
buildPrimitiveParser \input ->
|
||||
valResult =
|
||||
when input is
|
||||
[] -> Err (ParsingFailure "Nothing to parse")
|
||||
['A', ..] -> Ok A
|
||||
['B', ..] -> Ok B
|
||||
['C', ..] -> Ok C
|
||||
_ -> Ok Other
|
||||
|
||||
valResult
|
||||
|> Result.map \val -> { val, input: List.dropFirst input 1 }
|
||||
|
||||
expect
|
||||
input = "B"
|
||||
parser = letterParser
|
||||
result = parseStr parser input
|
||||
result == Ok B
|
||||
|
||||
expect
|
||||
input = "BCXA"
|
||||
parser = many letterParser
|
||||
result = parseStr parser input
|
||||
result == Ok [B, C, Other, A]
|
|
@ -1,63 +0,0 @@
|
|||
app [main] {
|
||||
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br",
|
||||
parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/0.5.2/9VrPjwfQQ1QeSL3CfmWr2Pr9DESdDIXy97pwpuq84Ck.tar.br",
|
||||
}
|
||||
|
||||
import pf.Stdout
|
||||
import pf.Stderr
|
||||
import parser.Core exposing [map, keep]
|
||||
import parser.String exposing [strFromUtf8]
|
||||
import parser.CSV
|
||||
|
||||
input : Str
|
||||
input = "Airplane!,1980,\"Robert Hays,Julie Hagerty\"\r\nCaddyshack,1980,\"Chevy Chase,Rodney Dangerfield,Ted Knight,Michael O'Keefe,Bill Murray\""
|
||||
|
||||
main =
|
||||
when CSV.parseStr movieInfoParser input is
|
||||
Ok movies ->
|
||||
moviesString =
|
||||
movies
|
||||
|> List.map movieInfoExplanation
|
||||
|> Str.joinWith ("\n")
|
||||
nMovies = List.len movies |> Num.toStr
|
||||
|
||||
Stdout.line "$(nMovies) movies were found:\n\n$(moviesString)\n\nParse success!\n"
|
||||
|
||||
Err problem ->
|
||||
when problem is
|
||||
ParsingFailure failure ->
|
||||
Stderr.line "Parsing failure: $(failure)\n"
|
||||
|
||||
ParsingIncomplete leftover ->
|
||||
leftoverStr = leftover |> List.map strFromUtf8 |> List.map (\val -> "\"$(val)\"") |> Str.joinWith ", "
|
||||
|
||||
Stderr.line "Parsing incomplete. Following leftover fields while parsing a record: $(leftoverStr)\n"
|
||||
|
||||
SyntaxError error ->
|
||||
Stderr.line "Parsing failure. Syntax error in the CSV: $(error)"
|
||||
|
||||
MovieInfo := { title : Str, releaseYear : U64, actors : List Str }
|
||||
|
||||
movieInfoParser =
|
||||
CSV.record (\title -> \releaseYear -> \actors -> @MovieInfo { title, releaseYear, actors })
|
||||
|> keep (CSV.field CSV.string)
|
||||
|> keep (CSV.field CSV.u64)
|
||||
|> keep (CSV.field actorsParser)
|
||||
|
||||
actorsParser =
|
||||
CSV.string
|
||||
|> map \val -> Str.split val ","
|
||||
|
||||
movieInfoExplanation = \@MovieInfo { title, releaseYear, actors } ->
|
||||
enumeratedActors = enumerate actors
|
||||
releaseYearStr = Num.toStr releaseYear
|
||||
|
||||
"The movie '$(title)' was released in $(releaseYearStr) and stars $(enumeratedActors)"
|
||||
|
||||
enumerate : List Str -> Str
|
||||
enumerate = \elements ->
|
||||
{ before: inits, others: last } = List.split elements (List.len elements - 1)
|
||||
|
||||
last
|
||||
|> List.prepend (inits |> Str.joinWith ", ")
|
||||
|> Str.joinWith " and "
|
|
@ -1 +0,0 @@
|
|||
Used by ingested-file-bytes.roc and ingested-file-bytes-no-ann.roc
|
File diff suppressed because it is too large
Load diff
1491
crates/cli/tests/cli_tests.rs
Normal file
1491
crates/cli/tests/cli_tests.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,9 +0,0 @@
|
|||
interface Transitive
|
||||
exposes [
|
||||
add,
|
||||
]
|
||||
imports []
|
||||
|
||||
add = \num1, num2 -> (num1 + num2)
|
||||
|
||||
expect add 1 2 == 3
|
|
@ -1,5 +0,0 @@
|
|||
package "transitive-tests"
|
||||
exposes [
|
||||
Direct,
|
||||
]
|
||||
packages {}
|
|
@ -1,4 +0,0 @@
|
|||
interface Dep1 exposes [str1] imports [Dep2]
|
||||
|
||||
str1 : Str
|
||||
str1 = Dep2.str2
|
|
@ -1,4 +0,0 @@
|
|||
interface Dep2 exposes [str2] imports []
|
||||
|
||||
str2 : Str
|
||||
str2 = "I am Dep2.str2"
|
|
@ -1,7 +0,0 @@
|
|||
app "multi-dep-str"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports [Dep1]
|
||||
provides [main] to pf
|
||||
|
||||
main : Str
|
||||
main = Dep1.str1
|
|
@ -1,119 +0,0 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const str = @import("glue").str;
|
||||
const RocStr = str.RocStr;
|
||||
const testing = std.testing;
|
||||
const expectEqual = testing.expectEqual;
|
||||
const expect = testing.expect;
|
||||
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
extern fn roc__mainForHost_1_exposed_generic(*RocStr) void;
|
||||
|
||||
const Align = 2 * @alignOf(usize);
|
||||
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
|
||||
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
|
||||
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
|
||||
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
|
||||
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
|
||||
|
||||
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
|
||||
_ = alignment;
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
|
||||
_ = old_size;
|
||||
_ = alignment;
|
||||
return realloc(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr))), new_size);
|
||||
}
|
||||
|
||||
export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||
_ = alignment;
|
||||
free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr))));
|
||||
}
|
||||
|
||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void {
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
switch (tag_id) {
|
||||
0 => {
|
||||
stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable;
|
||||
},
|
||||
1 => {
|
||||
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
export fn roc_dbg(loc: *RocStr, msg: *RocStr, src: *RocStr) callconv(.C) void {
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
stderr.print("[{s}] {s} = {s}\n", .{ loc.asSlice(), src.asSlice(), msg.asSlice() }) catch unreachable;
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_getppid_windows_stub() callconv(.C) c_int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .windows) {
|
||||
@export(roc_getppid_windows_stub, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
const Unit = extern struct {};
|
||||
|
||||
pub export fn main() i32 {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
|
||||
var timer = std.time.Timer.start() catch unreachable;
|
||||
|
||||
// actually call roc to populate the callresult
|
||||
var callresult = RocStr.empty();
|
||||
roc__mainForHost_1_exposed_generic(&callresult);
|
||||
|
||||
const nanos = timer.read();
|
||||
const seconds = (@as(f64, @floatFromInt(nanos)) / 1_000_000_000.0);
|
||||
|
||||
// stdout the result
|
||||
stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable;
|
||||
|
||||
callresult.decref();
|
||||
|
||||
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn to_seconds(tms: std.os.timespec) f64 {
|
||||
return @as(f64, @floatFromInt(tms.tv_sec)) + (@as(f64, @floatFromInt(tms.tv_nsec)) / 1_000_000_000.0);
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
platform "multi-module"
|
||||
requires {}{ main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
|
@ -1,7 +0,0 @@
|
|||
app "multi-dep-thunk"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports [Dep1]
|
||||
provides [main] to pf
|
||||
|
||||
main : Str
|
||||
main = Dep1.value1 {}
|
|
@ -1,119 +0,0 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const str = @import("glue").str;
|
||||
const RocStr = str.RocStr;
|
||||
const testing = std.testing;
|
||||
const expectEqual = testing.expectEqual;
|
||||
const expect = testing.expect;
|
||||
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
extern fn roc__mainForHost_1_exposed_generic(*RocStr) void;
|
||||
|
||||
const Align = 2 * @alignOf(usize);
|
||||
extern fn malloc(size: usize) callconv(.C) ?*anyopaque;
|
||||
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*anyopaque;
|
||||
extern fn free(c_ptr: [*]align(@alignOf(u128)) u8) callconv(.C) void;
|
||||
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
|
||||
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
|
||||
|
||||
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
|
||||
_ = alignment;
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
|
||||
_ = old_size;
|
||||
_ = alignment;
|
||||
return realloc(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr))), new_size);
|
||||
}
|
||||
|
||||
export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||
_ = alignment;
|
||||
free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr))));
|
||||
}
|
||||
|
||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void {
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
switch (tag_id) {
|
||||
0 => {
|
||||
stderr.print("Roc standard library crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable;
|
||||
},
|
||||
1 => {
|
||||
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
export fn roc_dbg(loc: *RocStr, msg: *RocStr, src: *RocStr) callconv(.C) void {
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
stderr.print("[{s}] {s} = {s}\n", .{ loc.asSlice(), src.asSlice(), msg.asSlice() }) catch unreachable;
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_getppid_windows_stub() callconv(.C) c_int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .windows) {
|
||||
@export(roc_getppid_windows_stub, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
const Unit = extern struct {};
|
||||
|
||||
pub export fn main() i32 {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
|
||||
var timer = std.time.Timer.start() catch unreachable;
|
||||
|
||||
// actually call roc to populate the callresult
|
||||
var callresult = RocStr.empty();
|
||||
roc__mainForHost_1_exposed_generic(&callresult);
|
||||
|
||||
const nanos = timer.read();
|
||||
const seconds = (@as(f64, @floatFromInt(nanos)) / 1_000_000_000.0);
|
||||
|
||||
// stdout the result
|
||||
stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable;
|
||||
|
||||
callresult.decref();
|
||||
|
||||
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn to_seconds(tms: std.os.timespec) f64 {
|
||||
return @as(f64, @floatFromInt(tms.tv_sec)) + (@as(f64, @floatFromInt(tms.tv_nsec)) / 1_000_000_000.0);
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
platform "multi-dep-thunk"
|
||||
requires {}{ main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
6
crates/cli/tests/fixtures/packages/app.roc
vendored
6
crates/cli/tests/fixtures/packages/app.roc
vendored
|
@ -1,6 +0,0 @@
|
|||
app "packages-test"
|
||||
packages { pf: "platform/main.roc", json: "json/main.roc", csv: "csv/main.roc" }
|
||||
imports [json.JsonParser, csv.Csv]
|
||||
provides [main] to pf
|
||||
|
||||
main = "Hello, World! $(JsonParser.example) $(Csv.example)"
|
|
@ -1,6 +0,0 @@
|
|||
interface Csv
|
||||
exposes [example]
|
||||
imports []
|
||||
|
||||
example : Str
|
||||
example = "This text came from a CSV package!"
|
|
@ -1,6 +0,0 @@
|
|||
interface JsonParser
|
||||
exposes [example]
|
||||
imports []
|
||||
|
||||
example : Str
|
||||
example = "This text came from a package!"
|
|
@ -1,9 +0,0 @@
|
|||
platform "multi-module"
|
||||
requires {}{ main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
|
@ -1,10 +0,0 @@
|
|||
app [main] {
|
||||
pf: platform "../packages/platform/main.roc",
|
||||
one: "one/main.roc",
|
||||
two: "two/main.roc",
|
||||
}
|
||||
|
||||
import one.One
|
||||
import two.Two
|
||||
|
||||
main = "$(One.example) | $(Two.example)"
|
|
@ -1,8 +0,0 @@
|
|||
app [main] {
|
||||
pf: platform "../packages/platform/main.roc",
|
||||
one: "one/main.roc",
|
||||
}
|
||||
|
||||
import one.One
|
||||
|
||||
main = One.example
|
|
@ -1,8 +0,0 @@
|
|||
app [main] {
|
||||
pf: platform "../packages/platform/main.roc",
|
||||
zero: "zero/main.roc",
|
||||
}
|
||||
|
||||
import zero.Zero
|
||||
|
||||
main = Zero.example
|
|
@ -1,3 +0,0 @@
|
|||
package [Zero] {
|
||||
one: "../one/main.roc"
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
interface ExposedNotDefined
|
||||
exposes [bar]
|
||||
imports []
|
|
@ -1,7 +0,0 @@
|
|||
interface UnusedImport
|
||||
exposes [plainText, emText]
|
||||
imports [Symbol.{ Ident }]
|
||||
|
||||
plainText = \str -> PlainText str
|
||||
|
||||
emText = \str -> EmText str
|
|
@ -1,7 +0,0 @@
|
|||
interface UnusedImportButWithALongFileNameForTesting
|
||||
exposes [plainText, emText]
|
||||
imports [Symbol.{ Ident }]
|
||||
|
||||
plainText = \str -> PlainText str
|
||||
|
||||
emText = \str -> EmText str
|
17
crates/cli/tests/markdown/form.md
Normal file
17
crates/cli/tests/markdown/form.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
# A Simple Markdown Example
|
||||
|
||||
This file contains `form.roc` embedded as a block in Markdown. It lets us test that `roc check` works with Markdown.
|
||||
|
||||
```roc
|
||||
module [foo]
|
||||
|
||||
foo = "Foo"
|
||||
```
|
||||
|
||||
Excitingly, we can have another block of Roc code as well! (In this case it is the same one...)
|
||||
|
||||
```roc
|
||||
module [bar]
|
||||
|
||||
bar = "Bar"
|
||||
```
|
|
@ -1,8 +0,0 @@
|
|||
module {
|
||||
sendHttpReq,
|
||||
getEnvVar
|
||||
} -> [hi]
|
||||
|
||||
hi : Str
|
||||
hi =
|
||||
"hi"
|
|
@ -1,8 +0,0 @@
|
|||
app [main] {
|
||||
pf: platform "../fixtures/multi-dep-str/platform/main.roc",
|
||||
}
|
||||
|
||||
import BadAnn { appId: "one" }
|
||||
|
||||
main =
|
||||
""
|
|
@ -1,6 +0,0 @@
|
|||
app [main] {
|
||||
pf: platform "./platform/main.roc"
|
||||
}
|
||||
|
||||
main =
|
||||
"from app"
|
|
@ -1,129 +0,0 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const str = @import("glue").str;
|
||||
const RocStr = str.RocStr;
|
||||
const testing = std.testing;
|
||||
const expectEqual = testing.expectEqual;
|
||||
const expect = testing.expect;
|
||||
|
||||
const Align = 2 * @alignOf(usize);
|
||||
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
|
||||
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
|
||||
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
|
||||
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
|
||||
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
|
||||
|
||||
const DEBUG: bool = false;
|
||||
|
||||
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
|
||||
if (DEBUG) {
|
||||
var ptr = malloc(size);
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
stdout.print("alloc: {d} (alignment {d}, size {d})\n", .{ ptr, alignment, size }) catch unreachable;
|
||||
return ptr;
|
||||
} else {
|
||||
return malloc(size);
|
||||
}
|
||||
}
|
||||
|
||||
export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
|
||||
if (DEBUG) {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
|
||||
}
|
||||
|
||||
return realloc(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr))), new_size);
|
||||
}
|
||||
|
||||
export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||
if (DEBUG) {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
|
||||
}
|
||||
|
||||
free(@as([*]align(Align) u8, @alignCast(@ptrCast(c_ptr))));
|
||||
}
|
||||
|
||||
export fn roc_panic(msg: *RocStr, tag_id: u32) callconv(.C) void {
|
||||
_ = tag_id;
|
||||
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg.asSlice()}) catch unreachable;
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
export fn roc_dbg(loc: *RocStr, msg: *RocStr, src: *RocStr) callconv(.C) void {
|
||||
// This platform uses stdout for testing purposes instead of the normal stderr.
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
stdout.print("[{s}] {s} = {s}\n", .{ loc.asSlice(), src.asSlice(), msg.asSlice() }) catch unreachable;
|
||||
}
|
||||
|
||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_getppid_windows_stub() callconv(.C) c_int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .windows) {
|
||||
@export(roc_getppid_windows_stub, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
extern fn roc__mainForHost_1_exposed_generic(*RocStr) void;
|
||||
|
||||
const Unit = extern struct {};
|
||||
|
||||
pub fn main() u8 {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
|
||||
var timer = std.time.Timer.start() catch unreachable;
|
||||
|
||||
// actually call roc to populate the callresult
|
||||
var callresult = RocStr.empty();
|
||||
roc__mainForHost_1_exposed_generic(&callresult);
|
||||
|
||||
const nanos = timer.read();
|
||||
const seconds = (@as(f64, @floatFromInt(nanos)) / 1_000_000_000.0);
|
||||
|
||||
// stdout the result
|
||||
stdout.print("{s}", .{callresult.asSlice()}) catch unreachable;
|
||||
|
||||
callresult.decref();
|
||||
|
||||
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_check_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
|
||||
── MISSING DEFINITION in tests/test-projects/known_bad/ExposedNotDefined.roc ───
|
||||
|
||||
bar is listed as exposed, but it isn't defined in this module.
|
||||
|
||||
You can fix this by adding a definition for bar, or by removing it
|
||||
from exposes.
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
1 error and 0 warning found in <ignored for test> ms
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_check_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
|
||||
── TYPE MISMATCH in tests/test-projects/known_bad/TypeError.roc ────────────────
|
||||
|
||||
Something is off with the body of the main definition:
|
||||
|
||||
3│ main : Str -> Task {} []
|
||||
4│ main = \_ ->
|
||||
5│ "this is a string, not a Task {} [] function like the platform expects."
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The body is a string of type:
|
||||
|
||||
Str
|
||||
|
||||
But the type annotation on main says it should be:
|
||||
|
||||
Task {} []
|
||||
|
||||
Tip: Add type annotations to functions or values to help you figure
|
||||
this out.
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
1 error and 0 warning found in <ignored for test> ms
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_check_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
|
||||
── UNUSED IMPORT in ...nown_bad/UnusedImportButWithALongFileNameForTesting.roc ─
|
||||
|
||||
Symbol is imported but not used.
|
||||
|
||||
3│ import Symbol exposing [Ident]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Since Symbol isn't used, you don't need to import it.
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
0 error and 1 warning found in <ignored for test> ms
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_test_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
── UNRECOGNIZED PACKAGE in tests/test-projects/module_imports_pkg/Module.roc ───
|
||||
|
||||
This module is trying to import from `pkg`:
|
||||
|
||||
3│ import pkg.Foo
|
||||
^^^^^^^
|
||||
|
||||
A lowercase name indicates a package shorthand, but I don't know which
|
||||
packages are available.
|
||||
|
||||
When checking a module directly, I look for a `main.roc` app or
|
||||
package to resolve shorthands from.
|
||||
|
||||
You can create it, or specify an existing one with the --main flag.
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_test_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
── UNRECOGNIZED PACKAGE in ...rojects/module_imports_pkg/ImportsUnknownPkg.roc ─
|
||||
|
||||
This module is trying to import from `cli`:
|
||||
|
||||
3│ import cli.Foo
|
||||
^^^^^^^
|
||||
|
||||
A lowercase name indicates a package shorthand, but I don't recognize
|
||||
this one. Did you mean one of these?
|
||||
|
||||
pkg
|
||||
|
||||
Note: I'm using the following module to resolve package shorthands:
|
||||
|
||||
tests/test-projects/module_imports_pkg/app.roc
|
||||
|
||||
You can specify a different one with the --main flag.
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: out.normalize_stdout_and_stderr()
|
||||
---
|
||||
(@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\"})]})
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_dev_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
── EXPECT FAILED in tests/test-projects/expects/expects.roc ────────────────────
|
||||
|
||||
This expectation failed:
|
||||
|
||||
25│ expect words == []
|
||||
^^^^^^^^^^^
|
||||
|
||||
When it failed, these variables had these values:
|
||||
|
||||
words : List Str
|
||||
words = ["this", "will", "for", "sure", "be", "a", "large", "string", "so", "when", "we", "split", "it", "it", "will", "use", "seamless", "slices", "which", "affect", "printing"]
|
||||
|
||||
Program finished!
|
||||
|
||||
[<ignored for tests>:28] x = 42
|
||||
[<ignored for tests>:30] "Fjoer en ferdjer frieten oan dyn geve lea" = "Fjoer en ferdjer frieten oan dyn geve lea"
|
||||
[<ignored for tests>:32] "this is line 24" = "this is line 24"
|
||||
[<ignored for tests>:18] x = "abc"
|
||||
[<ignored for tests>:18] x = 10
|
||||
[<ignored for tests>:18] x = (A (B C))
|
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_test_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
── EXPECT FAILED in tests/test-projects/expects/expects.roc ────────────────────
|
||||
|
||||
This expectation failed:
|
||||
|
||||
6│ expect a == 2
|
||||
^^^^^^
|
||||
|
||||
When it failed, these variables had these values:
|
||||
|
||||
a : Num *
|
||||
a = 1
|
||||
|
||||
── EXPECT FAILED in tests/test-projects/expects/expects.roc ────────────────────
|
||||
|
||||
This expectation failed:
|
||||
|
||||
7│ expect a == 3
|
||||
^^^^^^
|
||||
|
||||
When it failed, these variables had these values:
|
||||
|
||||
a : Num *
|
||||
a = 1
|
||||
|
||||
── EXPECT FAILED in tests/test-projects/expects/expects.roc ────────────────────
|
||||
|
||||
This expectation failed:
|
||||
|
||||
11│> expect
|
||||
12│> a = makeA
|
||||
13│> b = 2i64
|
||||
14│>
|
||||
15│> a == b
|
||||
|
||||
When it failed, these variables had these values:
|
||||
|
||||
a : Int Signed64
|
||||
a = 1
|
||||
|
||||
b : I64
|
||||
b = 2
|
||||
|
||||
|
||||
1 failed and 0 passed in <ignored for test> ms.
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_dev_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
App1.baseUrl: https://api.example.com/one
|
||||
App2.baseUrl: http://api.example.com/two
|
||||
App3.baseUrl: https://api.example.com/three
|
||||
App1.getUser 1: https://api.example.com/one/users/1
|
||||
App2.getUser 2: http://api.example.com/two/users/2
|
||||
App3.getUser 3: https://api.example.com/three/users/3
|
||||
App1.getPost 1: https://api.example.com/one/posts/1
|
||||
App2.getPost 2: http://api.example.com/two/posts/2
|
||||
App3.getPost 3: https://api.example.com/three/posts/3
|
||||
App1.getPosts [1, 2]: ["https://api.example.com/one/posts/1", "https://api.example.com/one/posts/2"]
|
||||
App2.getPosts [3, 4]: ["http://api.example.com/two/posts/3", "http://api.example.com/two/posts/4"]
|
||||
App2.getPosts [5, 6]: ["http://api.example.com/two/posts/5", "http://api.example.com/two/posts/6"]
|
||||
App1.getPostComments 1: https://api.example.com/one/posts/1/comments
|
||||
App2.getPostComments 2: http://api.example.com/two/posts/2/comments
|
||||
App2.getPostComments 3: http://api.example.com/two/posts/3/comments
|
||||
App1.getCompanies [1, 2]: ["https://api.example.com/one/companies/1", "https://api.example.com/one/companies/2"]
|
||||
App2.getCompanies [3, 4]: ["http://api.example.com/two/companies/3", "http://api.example.com/two/companies/4"]
|
||||
App2.getCompanies [5, 6]: ["http://api.example.com/two/companies/5", "http://api.example.com/two/companies/6"]
|
||||
App1.getPostAliased 1: https://api.example.com/one/posts/1
|
||||
App2.getPostAliased 2: http://api.example.com/two/posts/2
|
||||
App3.getPostAliased 3: https://api.example.com/three/posts/3
|
||||
App1.baseUrlAliased: https://api.example.com/one
|
||||
App2.baseUrlAliased: http://api.example.com/two
|
||||
App3.baseUrlAliased: https://api.example.com/three
|
||||
App1.getUserSafe 1: https://api.example.com/one/users/1
|
||||
Prod.getUserSafe 2: http://api.example.com/prod_1/users/2?safe=true
|
||||
usersApp1: ["https://api.example.com/one/users/1", "https://api.example.com/one/users/2", "https://api.example.com/one/users/3"]
|
||||
getUserApp3Nested 3: https://api.example.com/three/users/3
|
||||
usersApp3Passed: ["https://api.example.com/three/users/1", "https://api.example.com/three/users/2", "https://api.example.com/three/users/3"]
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
assertion_line: 429
|
||||
expression: cli_dev_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
|
||||
── TOO MANY ARGS in tests/test-projects/module_params/arity_mismatch.roc ───────
|
||||
|
||||
The getUser function expects 1 argument, but it got 2 instead:
|
||||
|
||||
12│ $(Api.getUser 1 2)
|
||||
^^^^^^^^^^^
|
||||
|
||||
Are there any missing commas? Or missing parentheses?
|
||||
|
||||
|
||||
── TOO MANY ARGS in tests/test-projects/module_params/arity_mismatch.roc ───────
|
||||
|
||||
This value is not a function, but it was given 1 argument:
|
||||
|
||||
13│ $(Api.baseUrl 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:
|
||||
|
||||
16│ $(Api.getPostComment 1)
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Roc does not allow functions to be partially applied. Use a closure to
|
||||
make partial application explicit.
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
3 error and 0 warning found in <ignored for test> ms
|
||||
.
|
||||
|
||||
You can run <ignored for tests>
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
assertion_line: 445
|
||||
expression: cli_dev_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
|
||||
── TYPE MISMATCH in tests/test-projects/module_params/BadAnn.roc ───────────────
|
||||
|
||||
Something is off with the body of the fnAnnotatedAsValue definition:
|
||||
|
||||
3│ fnAnnotatedAsValue : Str
|
||||
4│> fnAnnotatedAsValue = \postId, commentId ->
|
||||
5│> "/posts/$(postId)/comments/$(Num.toStr commentId)"
|
||||
|
||||
The body is an anonymous function of type:
|
||||
|
||||
Str, Num * -> Str
|
||||
|
||||
But the type annotation on fnAnnotatedAsValue 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:
|
||||
|
||||
7│ missingArg : Str -> Str
|
||||
8│> missingArg = \postId, _ ->
|
||||
9│> "/posts/$(postId)/comments"
|
||||
|
||||
The body is an anonymous function of type:
|
||||
|
||||
(Str, ? -> Str)
|
||||
|
||||
But the type annotation on missingArg says it should be:
|
||||
|
||||
(Str -> Str)
|
||||
|
||||
Tip: It looks like it takes too many arguments. I'm seeing 1 extra.
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
2 error and 1 warning found in <ignored for test> ms
|
||||
.
|
||||
|
||||
You can run <ignored for tests>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
assertion_line: 476
|
||||
expression: cli_dev_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
|
||||
── TYPE MISMATCH in tests/test-projects/module_params/unexpected_fn.roc ────────
|
||||
|
||||
This argument to this string interpolation has an unexpected type:
|
||||
|
||||
11│ $(Api.getPost)
|
||||
^^^^^^^^^^^
|
||||
|
||||
The argument is an anonymous function of type:
|
||||
|
||||
U32 -> Str
|
||||
|
||||
But this string interpolation needs its argument to be:
|
||||
|
||||
Str
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
1 error and 0 warning found in <ignored for test> ms
|
||||
.
|
||||
|
||||
You can run <ignored for tests>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_test_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
Compiled in <ignored for test> ms.
|
||||
|
||||
Direct.roc:
|
||||
0 failed and 2 passed in <ignored for test> ms.
|
||||
|
||||
Transitive.roc:
|
||||
0 failed and 1 passed in <ignored for test> ms.
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
source: crates/cli/tests/cli_tests.rs
|
||||
expression: cli_check_out.normalize_stdout_and_stderr()
|
||||
---
|
||||
|
||||
── UNUSED IMPORT in tests/test-projects/known_bad/UnusedImport.roc ─────────────
|
||||
|
||||
Symbol is imported but not used.
|
||||
|
||||
3│ import Symbol exposing [Ident]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Since Symbol isn't used, you don't need to import it.
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
0 error and 1 warning found in <ignored for test> ms
|
|
@ -110,18 +110,10 @@ comptime {
|
|||
pub export fn main() u8 {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
|
||||
var timer = std.time.Timer.start() catch unreachable;
|
||||
|
||||
const result = roc__mainForHost_1_exposed(10);
|
||||
|
||||
const nanos = timer.read();
|
||||
const seconds = (@as(f64, @floatFromInt(nanos)) / 1_000_000_000.0);
|
||||
|
||||
stdout.print("{d}\n", .{result}) catch unreachable;
|
||||
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -127,8 +127,6 @@ pub export fn main() u8 {
|
|||
|
||||
var roc_list = RocList{ .elements = numbers, .length = NUM_NUMS, .capacity = NUM_NUMS };
|
||||
|
||||
var timer = std.time.Timer.start() catch unreachable;
|
||||
|
||||
// actually call roc to populate the callresult
|
||||
const callresult: RocList = roc__mainForHost_1_exposed(roc_list);
|
||||
|
||||
|
@ -136,9 +134,6 @@ pub export fn main() u8 {
|
|||
const length = @min(20, callresult.length);
|
||||
var result = callresult.elements[0..length];
|
||||
|
||||
const nanos = timer.read();
|
||||
const seconds = (@as(f64, @floatFromInt(nanos)) / 1_000_000_000.0);
|
||||
|
||||
for (result, 0..) |x, i| {
|
||||
if (i == 0) {
|
||||
stdout.print("[{}, ", .{x}) catch unreachable;
|
||||
|
@ -149,12 +144,5 @@ pub export fn main() u8 {
|
|||
}
|
||||
}
|
||||
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn to_seconds(tms: std.os.timespec) f64 {
|
||||
return @as(f64, @floatFromInt(tms.tv_sec)) + (@as(f64, @floatFromInt(tms.tv_nsec)) / 1_000_000_000.0);
|
||||
}
|
|
@ -1,7 +1,4 @@
|
|||
app "quicksort"
|
||||
packages { pf: "quicksort-platform/main.roc" }
|
||||
imports []
|
||||
provides [quicksort] to pf
|
||||
app [quicksort] { pf: platform "quicksort-platform/main.roc" }
|
||||
|
||||
quicksort = \originalList ->
|
||||
n = List.len originalList
|
35
crates/cli/tests/test-projects/effectful/echo.roc
Normal file
35
crates/cli/tests/test-projects/effectful/echo.roc
Normal file
|
@ -0,0 +1,35 @@
|
|||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
||||
main! : {} => {}
|
||||
main! = \{} -> tick! {}
|
||||
|
||||
tick! = \{} ->
|
||||
line = Effect.getLine! {}
|
||||
|
||||
if !(Str.isEmpty line) then
|
||||
Effect.putLine! (echo line)
|
||||
else
|
||||
Effect.putLine! "Received no input."
|
||||
|
||||
echo : Str -> Str
|
||||
echo = \shout ->
|
||||
silence = \length -> List.repeat ' ' length
|
||||
|
||||
shout
|
||||
|> Str.toUtf8
|
||||
|> List.mapWithIndex \_, i ->
|
||||
length = (List.len (Str.toUtf8 shout) - i)
|
||||
phrase = (List.splitAt (Str.toUtf8 shout) length).before
|
||||
|
||||
List.concat (silence (if i == 0 then 2 * length else length)) phrase
|
||||
|> List.join
|
||||
|> Str.fromUtf8
|
||||
|> Result.withDefault ""
|
||||
|
||||
expect
|
||||
message = "hello!"
|
||||
echoedMessage = echo message
|
||||
|
||||
echoedMessage == " hello! hello hell hel he h"
|
23
crates/cli/tests/test-projects/effectful/for_each_try.roc
Normal file
23
crates/cli/tests/test-projects/effectful/for_each_try.roc
Normal file
|
@ -0,0 +1,23 @@
|
|||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
good = [0, 2, 4] |> List.forEachTry! validate!
|
||||
expect good == Ok {}
|
||||
|
||||
bad = [6, 8, 9, 10] |> List.forEachTry! validate!
|
||||
expect bad == Err 9
|
||||
|
||||
{}
|
||||
|
||||
validate! : U32 => Result {} U32
|
||||
validate! = \x ->
|
||||
if Num.isEven x then
|
||||
Effect.putLine! "✅ $(Num.toStr x)"
|
||||
Ok {}
|
||||
|
||||
else
|
||||
Effect.putLine! "$(Num.toStr x) is not even! ABORT!"
|
||||
Err x
|
|
@ -1,4 +1,4 @@
|
|||
app [main!] { pf: platform "../../../../examples/cli/effects-platform/main.roc" }
|
||||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
app [main!] { pf: platform "../../../../examples/cli/effects-platform/main.roc" }
|
||||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
app [main!] { pf: platform "../../../../examples/cli/effects-platform/main.roc" }
|
||||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
#
|
||||
# Shows how Roc values can be logged
|
||||
#
|
||||
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
|
||||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Stdout
|
||||
import pf.Effect
|
||||
import Community
|
||||
|
||||
main =
|
||||
main! = \{} ->
|
||||
Community.empty
|
||||
|> Community.addPerson {
|
||||
firstName: "John",
|
||||
|
@ -32,4 +32,4 @@ main =
|
|||
|> Community.addFriend 0 2
|
||||
|> Community.addFriend 1 2
|
||||
|> Inspect.toStr
|
||||
|> Stdout.line!
|
||||
|> Effect.putLine!
|
|
@ -1,4 +1,4 @@
|
|||
app [main!] { pf: platform "../../../../examples/cli/effects-platform/main.roc" }
|
||||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
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