Merge branch 'main' into constrain-early-return-functions

This commit is contained in:
Sam Mohr 2024-11-18 15:04:34 -08:00
commit 7ca305b5dc
No known key found for this signature in database
GPG key ID: EA41D161A3C1BC99
371 changed files with 6427 additions and 8505 deletions

1
.gitattributes vendored
View file

@ -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

View file

@ -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!"

View file

@ -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
View 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

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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: |

View file

@ -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
View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -54,6 +54,6 @@ fi
./jump-start.sh
# build the basic cli platform
roc build.roc --prebuilt-platform
roc build.roc
cd ..

View file

@ -47,6 +47,6 @@ cd ..
cd basic-webserver
roc build.roc --prebuilt-platform
roc build.roc
cd ..

View file

@ -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

View file

@ -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/`

View file

@ -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

View file

@ -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};

View file

@ -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?"

View file

@ -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,

View file

@ -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,

View file

@ -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 (\_ -> {})

View file

@ -0,0 +1,3 @@
app [main] { pf: platform "main.roc" }
main = Task.ok {}

View file

@ -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;

View file

@ -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

View file

@ -3,7 +3,6 @@ app [main] { pf: platform "platform/main.roc" }
import pf.PlatformTasks
import AStar
#main : Task {} *
main =
PlatformTasks.putLine! (showBool test1)

View file

@ -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"

View file

@ -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))

View file

@ -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 ""

View file

@ -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!"

View file

@ -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)

View file

@ -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)! 👋"
```

View file

@ -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)! 👋"

View file

@ -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

View file

@ -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!

View file

@ -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!

View file

@ -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)"

View file

@ -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)")

View file

@ -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]

View file

@ -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 "

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -1,9 +0,0 @@
interface Transitive
exposes [
add,
]
imports []
add = \num1, num2 -> (num1 + num2)
expect add 1 2 == 3

View file

@ -1,5 +0,0 @@
package "transitive-tests"
exposes [
Direct,
]
packages {}

View file

@ -1,4 +0,0 @@
interface Dep1 exposes [str1] imports [Dep2]
str1 : Str
str1 = Dep2.str2

View file

@ -1,4 +0,0 @@
interface Dep2 exposes [str2] imports []
str2 : Str
str2 = "I am Dep2.str2"

View file

@ -1,7 +0,0 @@
app "multi-dep-str"
packages { pf: "platform/main.roc" }
imports [Dep1]
provides [main] to pf
main : Str
main = Dep1.str1

View file

@ -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);
}

View file

@ -1,9 +0,0 @@
platform "multi-module"
requires {}{ main : Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str
mainForHost = main

View file

@ -1,7 +0,0 @@
app "multi-dep-thunk"
packages { pf: "platform/main.roc" }
imports [Dep1]
provides [main] to pf
main : Str
main = Dep1.value1 {}

View file

@ -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);
}

View file

@ -1,9 +0,0 @@
platform "multi-dep-thunk"
requires {}{ main : Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str
mainForHost = main

View file

@ -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)"

View file

@ -1,6 +0,0 @@
interface Csv
exposes [example]
imports []
example : Str
example = "This text came from a CSV package!"

View file

@ -1,6 +0,0 @@
interface JsonParser
exposes [example]
imports []
example : Str
example = "This text came from a package!"

View file

@ -1,9 +0,0 @@
platform "multi-module"
requires {}{ main : Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str
mainForHost = main

View file

@ -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)"

View file

@ -1,8 +0,0 @@
app [main] {
pf: platform "../packages/platform/main.roc",
one: "one/main.roc",
}
import one.One
main = One.example

View file

@ -1,8 +0,0 @@
app [main] {
pf: platform "../packages/platform/main.roc",
zero: "zero/main.roc",
}
import zero.Zero
main = Zero.example

View file

@ -1,3 +0,0 @@
package [Zero] {
one: "../one/main.roc"
}

View file

@ -1,3 +0,0 @@
interface ExposedNotDefined
exposes [bar]
imports []

View file

@ -1,7 +0,0 @@
interface UnusedImport
exposes [plainText, emText]
imports [Symbol.{ Ident }]
plainText = \str -> PlainText str
emText = \str -> EmText str

View file

@ -1,7 +0,0 @@
interface UnusedImportButWithALongFileNameForTesting
exposes [plainText, emText]
imports [Symbol.{ Ident }]
plainText = \str -> PlainText str
emText = \str -> EmText str

View 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"
```

View file

@ -1,8 +0,0 @@
module {
sendHttpReq,
getEnvVar
} -> [hi]
hi : Str
hi =
"hi"

View file

@ -1,8 +0,0 @@
app [main] {
pf: platform "../fixtures/multi-dep-str/platform/main.roc",
}
import BadAnn { appId: "one" }
main =
""

View file

@ -1,6 +0,0 @@
app [main] {
pf: platform "./platform/main.roc"
}
main =
"from app"

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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\"})]})

View file

@ -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))

View file

@ -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.

View file

@ -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"]

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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.

View file

@ -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

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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

View 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"

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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!

View file

@ -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