Merge branch 'main' into specialize-exprs

This commit is contained in:
Agus Zubiaga 2024-11-23 01:48:51 -03:00
commit 2e96aca0fd
No known key found for this signature in database
797 changed files with 17394 additions and 12632 deletions

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

@ -2,6 +2,7 @@
name = "roc_cli"
description = "The Roc binary that brings together all functionality in the Roc toolset."
default-run = "roc"
build = "build.rs"
authors.workspace = true
edition.workspace = true
@ -30,7 +31,13 @@ target-wasm32 = ["roc_build/target-wasm32"]
target-x86 = ["roc_build/target-x86", "roc_repl_cli/target-x86"]
target-x86_64 = ["roc_build/target-x86_64", "roc_repl_cli/target-x86_64"]
target-all = ["target-aarch64", "target-arm", "target-x86", "target-x86_64", "target-wasm32"]
target-all = [
"target-aarch64",
"target-arm",
"target-x86",
"target-x86_64",
"target-wasm32",
]
sanitizers = ["roc_build/sanitizers"]
@ -83,15 +90,17 @@ 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
[[bench]]
name = "time_bench"

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

71
crates/cli/build.rs Normal file
View file

@ -0,0 +1,71 @@
use chrono::prelude::*;
use std::fs;
use std::process::Command;
use std::str;
fn main() {
// Rebuild if this build.rs file changes
println!("cargo:rerun-if-changed=build.rs");
// The version file is located at the root of the repository
let version_file_path = "../../version.txt";
// Rebuild if version file changes
println!("cargo:rerun-if-changed={}", version_file_path);
// Read the version file
let version_file_contents = fs::read_to_string(version_file_path).unwrap();
// If the version is "built-from-source", replace it with the git commit information
let version = match version_file_contents.trim() {
"built-from-source" => {
let git_head_file_path = "../../.git/HEAD";
// Rebuild if a new Git commit is made
println!("cargo:rerun-if-changed={}", git_head_file_path);
// Check if the .git/HEAD file exists
let git_head_exists = fs::metadata(git_head_file_path).is_ok();
if git_head_exists {
// Get the hash of the current commit
let git_describe_output = Command::new("git")
.arg("describe")
.arg("--always")
.arg("--dirty= with additional changes") // Add a suffix if the working directory is dirty
.output()
.expect("Failed to execute git describe command");
println!("git_describe_output: {:?}", git_describe_output);
let git_commit_hash = str::from_utf8(&git_describe_output.stdout)
.expect("Failed to parse git describe output")
.trim();
// Get the datetime of the last commit
let git_show_output = Command::new("git")
.arg("show")
.arg("--no-patch")
.arg("--format=%ct") // Outputting a UNIX timestamp is the only way to always use UTC
.output()
.expect("Failed to execute git show command");
println!("git_show_output: {:?}", git_show_output);
let git_commit_timestamp = {
let timestamp = str::from_utf8(&git_show_output.stdout)
.expect("Failed to parse git show output as a string")
.trim()
.parse::<i64>()
.expect("Failed to parse timestamp as an integer");
DateTime::from_timestamp(timestamp, 0)
.expect("Failed to parse timestamp")
.format("%Y-%m-%d %H:%M:%S")
};
format!(
"built from commit {git_commit_hash}, committed at {git_commit_timestamp} UTC"
)
} else {
// If the .git/HEAD file does not exist, e.g. in a Nix build, use a generic message
"built from source".to_string()
}
}
_ => version_file_contents.trim().to_string(),
};
// Emit the version to a build-time environment variable
println!("cargo:rustc-env=ROC_VERSION={}", version);
}

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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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";
@ -90,7 +90,7 @@ pub const FLAG_PP_HOST: &str = "host";
pub const FLAG_PP_PLATFORM: &str = "platform";
pub const FLAG_PP_DYLIB: &str = "lib";
const VERSION: &str = include_str!("../../../version.txt");
pub const VERSION: &str = env!("ROC_VERSION");
const DEFAULT_GENERATED_DOCS_DIR: &str = "generated-docs";
pub fn build_app() -> Command {
@ -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);
@ -182,7 +188,7 @@ pub fn build_app() -> Command {
PossibleValuesParser::new(Target::iter().map(Into::<&'static str>::into));
Command::new("roc")
.version(concatcp!(VERSION, "\n"))
.version(VERSION)
.about("Run the given .roc file, if there are no compilation errors.\nYou can use one of the SUBCOMMANDS below to do something else!")
.args_conflicts_with_subcommands(true)
.subcommand(Command::new(CMD_BUILD)
@ -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,18 +517,21 @@ 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();
// Spawn the root task
if !path.exists() {
let current_dir = env::current_dir().unwrap();
let expected_file_path = current_dir.join(path);
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();
let expected_file_path = current_dir.join(path);
let current_dir_string = current_dir.display();
let expected_file_path_string = expected_file_path.display();
let current_dir_string = current_dir.display();
let expected_file_path_string = expected_file_path.display();
// TODO these should use roc_reporting to display nicer error messages.
match matches.value_source(ROC_FILE) {
// TODO these should use roc_reporting to display nicer error messages.
match matches.value_source(ROC_FILE) {
Some(ValueSource::DefaultValue) => {
eprintln!(
"\nThe current directory ({current_dir_string}) does not contain a {DEFAULT_ROC_FILENAME} file to use as a default.\n\nYou can run `roc help` for more information on how to provide a .roc file.\n"
@ -541,116 +539,141 @@ 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);
}
let arena = &arena;
let function_kind = FunctionKind::from_env();
let opt_main_path = matches.get_one::<PathBuf>(FLAG_MAIN);
// Step 1: compile the app and generate the .o file
let load_config = LoadConfig {
target,
function_kind,
// TODO: expose this from CLI?
render: roc_reporting::report::RenderTarget::ColorTerminal,
palette: roc_reporting::report::DEFAULT_PALETTE,
threading,
exec_mode: ExecutionMode::Test,
};
let load_result = roc_load::load_and_monomorphize(
arena,
path.to_path_buf(),
opt_main_path.cloned(),
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
load_config,
);
let mut loaded = match load_result {
Ok(loaded) => loaded,
Err(LoadMonomorphizedError::LoadingProblem(problem)) => {
return handle_loading_problem(problem);
}
Err(LoadMonomorphizedError::ErrorModule(module)) => {
return handle_error_module(module, start_time.elapsed(), path.as_os_str(), false);
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 problems = report_problems_monomorphized(&mut loaded);
let mut expectations = std::mem::take(&mut loaded.expectations);
let mut all_files_total_failed_count = 0;
let mut all_files_total_passed_count = 0;
let interns = loaded.interns.clone();
let sources = loaded.sources.clone();
for path in paths.iter() {
let arena = &arena;
let function_kind = FunctionKind::from_env();
let (dyn_lib, expects_by_module, layout_interner) =
roc_repl_expect::run::expect_mono_module_to_dylib(
arena,
let opt_main_path = matches.get_one::<PathBuf>(FLAG_MAIN);
// Step 1: compile the app and generate the .o file
let load_config = LoadConfig {
target,
loaded,
opt_level,
LlvmBackendMode::CliTest,
)
.unwrap();
// Print warnings before running tests.
{
debug_assert_eq!(
problems.errors, 0,
"if there were errors, we would have already exited."
function_kind,
// TODO: expose this from CLI?
render: roc_reporting::report::RenderTarget::ColorTerminal,
palette: roc_reporting::report::DEFAULT_PALETTE,
threading,
exec_mode: ExecutionMode::Test,
};
let load_result = roc_load::load_and_monomorphize(
arena,
path.to_path_buf(),
opt_main_path.cloned(),
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
load_config,
);
if problems.warnings > 0 {
problems.print_error_warning_count(start_time.elapsed());
println!(".\n\nRunning tests…\n\n\x1B[36m{}\x1B[39m", "".repeat(80));
let mut loaded = match load_result {
Ok(loaded) => loaded,
Err(LoadMonomorphizedError::LoadingProblem(problem)) => {
return handle_loading_problem(problem);
}
Err(LoadMonomorphizedError::ErrorModule(module)) => {
return handle_error_module(module, start_time.elapsed(), path.as_os_str(), false);
}
};
let problems = report_problems_monomorphized(&mut loaded);
let mut expectations = std::mem::take(&mut loaded.expectations);
let interns = loaded.interns.clone();
let sources = loaded.sources.clone();
let (dyn_lib, expects_by_module, layout_interner) =
roc_repl_expect::run::expect_mono_module_to_dylib(
arena,
target,
loaded,
opt_level,
LlvmBackendMode::CliTest,
)
.unwrap();
// Print warnings before running tests.
{
debug_assert_eq!(
problems.errors, 0,
"if there were errors, we would have already exited."
);
if problems.warnings > 0 {
problems.print_error_warning_count(start_time.elapsed());
println!(".\n\nRunning tests…\n\n\x1B[36m{}\x1B[39m", "".repeat(80));
}
}
// Run the tests.
let arena = &bumpalo::Bump::new();
let interns = arena.alloc(interns);
let mut writer = std::io::stdout();
let mut total_failed_count = 0;
let mut total_passed_count = 0;
let mut results_by_module = Vec::new();
let global_layout_interner = layout_interner.into_global();
let compilation_duration = start_time.elapsed();
for (module_id, expects) in expects_by_module.into_iter() {
let test_start_time = Instant::now();
let (failed_count, passed_count) = roc_repl_expect::run::run_toplevel_expects(
&mut writer,
roc_reporting::report::RenderTarget::ColorTerminal,
arena,
interns,
&global_layout_interner,
&dyn_lib,
&mut expectations,
expects,
)
.unwrap();
let tests_duration = test_start_time.elapsed();
results_by_module.push(ModuleTestResults {
module_id,
failed_count,
passed_count,
tests_duration,
});
total_failed_count += failed_count;
total_passed_count += passed_count;
}
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}");
}
}
// Run the tests.
let arena = &bumpalo::Bump::new();
let interns = arena.alloc(interns);
let mut writer = std::io::stdout();
let mut total_failed_count = 0;
let mut total_passed_count = 0;
let mut results_by_module = Vec::new();
let global_layout_interner = layout_interner.into_global();
let compilation_duration = start_time.elapsed();
for (module_id, expects) in expects_by_module.into_iter() {
let test_start_time = Instant::now();
let (failed_count, passed_count) = roc_repl_expect::run::run_toplevel_expects(
&mut writer,
roc_reporting::report::RenderTarget::ColorTerminal,
arena,
interns,
&global_layout_interner,
&dyn_lib,
&mut expectations,
expects,
)
.unwrap();
let tests_duration = test_start_time.elapsed();
results_by_module.push(ModuleTestResults {
module_id,
failed_count,
passed_count,
tests_duration,
});
total_failed_count += failed_count;
total_passed_count += passed_count;
}
let total_duration = start_time.elapsed();
if total_failed_count == 0 && total_passed_count == 0 {
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);
}
} else {
let test_summary_str =
test_summary(total_failed_count, total_passed_count, total_duration);
println!("{test_summary_str}");
}
Ok((all_files_total_failed_count > 0) as i32)
}
}
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,
@ -986,7 +1016,15 @@ pub fn build(
// ManuallyDrop will leak the bytes because we don't drop manually
let bytes = &ManuallyDrop::new(std::fs::read(&binary_path).unwrap());
roc_run(&arena, opt_level, target, args, bytes, expect_metadata)
roc_run(
&arena,
path,
opt_level,
target,
args,
bytes,
expect_metadata,
)
}
BuildAndRunIfNoErrors => {
if problems.fatally_errored {
@ -1021,7 +1059,15 @@ pub fn build(
// ManuallyDrop will leak the bytes because we don't drop manually
let bytes = &ManuallyDrop::new(std::fs::read(&binary_path).unwrap());
roc_run(&arena, opt_level, target, args, bytes, expect_metadata)
roc_run(
&arena,
path,
opt_level,
target,
args,
bytes,
expect_metadata,
)
}
}
}
@ -1034,6 +1080,7 @@ pub fn build(
fn roc_run<'a, I: IntoIterator<Item = &'a OsStr>>(
arena: &Bump,
script_path: &Path,
opt_level: OptLevel,
target: Target,
args: I,
@ -1073,7 +1120,14 @@ fn roc_run<'a, I: IntoIterator<Item = &'a OsStr>>(
Ok(0)
}
_ => roc_run_native(arena, opt_level, args, binary_bytes, expect_metadata),
_ => roc_run_native(
arena,
script_path,
opt_level,
args,
binary_bytes,
expect_metadata,
),
}
}
@ -1090,7 +1144,7 @@ fn os_str_as_utf8_bytes(os_str: &OsStr) -> &[u8] {
fn make_argv_envp<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
arena: &'a Bump,
executable: &ExecutableFile,
script_path: &Path,
args: I,
) -> (
bumpalo::collections::Vec<'a, CString>,
@ -1098,8 +1152,7 @@ fn make_argv_envp<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
) {
use bumpalo::collections::CollectIn;
let path = executable.as_path();
let path_cstring = CString::new(os_str_as_utf8_bytes(path.as_os_str())).unwrap();
let path_cstring = CString::new(os_str_as_utf8_bytes(script_path.as_os_str())).unwrap();
// argv is an array of pointers to strings passed to the new program
// as its command-line arguments. By convention, the first of these
@ -1137,6 +1190,7 @@ fn make_argv_envp<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
#[cfg(target_family = "unix")]
fn roc_run_native<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
arena: &Bump,
script_path: &Path,
opt_level: OptLevel,
args: I,
binary_bytes: &[u8],
@ -1145,7 +1199,7 @@ fn roc_run_native<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
use bumpalo::collections::CollectIn;
let executable = roc_run_executable_file_path(binary_bytes)?;
let (argv_cstrings, envp_cstrings) = make_argv_envp(arena, &executable, args);
let (argv_cstrings, envp_cstrings) = make_argv_envp(arena, script_path, args);
let argv: bumpalo::collections::Vec<*const c_char> = argv_cstrings
.iter()
@ -1400,6 +1454,7 @@ fn roc_run_executable_file_path(binary_bytes: &[u8]) -> std::io::Result<Executab
#[cfg(not(target_family = "unix"))]
fn roc_run_native<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
arena: &Bump, // This should be passed an owned value, not a reference, so we can usefully mem::forget it!
script_path: &Path,
opt_level: OptLevel,
args: I,
binary_bytes: &[u8],
@ -1411,7 +1466,7 @@ fn roc_run_native<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
let executable = roc_run_executable_file_path(binary_bytes)?;
// TODO forward the arguments
let (argv_cstrings, envp_cstrings) = make_argv_envp(&arena, &executable, args);
let (argv_cstrings, envp_cstrings) = make_argv_envp(&arena, script_path, args);
let argv: bumpalo::collections::Vec<*const c_char> = argv_cstrings
.iter()

View file

@ -4,27 +4,25 @@ 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,
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};
use std::io::BufRead;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use target_lexicon::Triple;
#[macro_use]
extern crate const_format;
use tempfile::Builder;
#[global_allocator]
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
@ -52,7 +50,7 @@ fn main() -> io::Result<()> {
BuildConfig::BuildAndRunIfNoErrors,
Triple::host().into(),
None,
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
LinkType::Executable,
)
} else {
@ -67,7 +65,7 @@ fn main() -> io::Result<()> {
BuildConfig::BuildAndRun,
Triple::host().into(),
None,
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
LinkType::Executable,
)
} else {
@ -93,7 +91,7 @@ fn main() -> io::Result<()> {
BuildConfig::BuildAndRunIfNoErrors,
Triple::host().into(),
None,
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
LinkType::Executable,
)
} else {
@ -121,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_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) };
@ -170,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,
@ -202,7 +189,7 @@ fn main() -> io::Result<()> {
BuildConfig::BuildOnly,
target,
out_path,
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
link_type,
)?)
}
@ -220,26 +207,89 @@ fn main() -> io::Result<()> {
let opt_main_path = matches.get_one::<PathBuf>(FLAG_MAIN);
match check_file(
&arena,
roc_file_path.to_owned(),
opt_main_path.cloned(),
emit_timings,
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
threading,
) {
Ok((problems, total_time)) => {
problems.print_error_warning_count(total_time);
Ok(problems.exit_code())
}
match roc_file_path.extension().and_then(OsStr::to_str) {
Some("md") => {
// Extract the blocks of roc code
let file = fs::File::open(roc_file_path.as_path())?;
let markdown_file_reader = io::BufReader::new(file);
let mut roc_blocks: Vec<String> = Vec::new();
let mut in_roc_block: bool = false;
let mut current_block = String::new();
Err(LoadingProblem::FormattedReport(report)) => {
print!("{report}");
for line in markdown_file_reader.lines() {
let line = line.unwrap();
if line == "```roc" {
in_roc_block = true;
} else if (line == "```") & in_roc_block {
in_roc_block = false;
roc_blocks.push(current_block);
current_block = String::new();
} else if in_roc_block {
current_block.push_str(&line);
current_block.push('\n');
}
}
Ok(1)
// now check each block, we exit early if any single block does not check
let mut exit_code = 0;
for block in roc_blocks.iter() {
let mut file = Builder::new().suffix(".roc").tempfile()?;
write!(file, "{}", block)?;
match check_file(
&arena,
file.path().to_owned(),
opt_main_path.cloned(),
emit_timings,
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
threading,
) {
Ok((problems, total_time)) => {
problems.print_error_warning_count(total_time);
exit_code = problems.exit_code();
}
Err(LoadingProblem::FormattedReport(report)) => {
print!("{report}");
exit_code = 1;
}
Err(other) => {
panic!("build_file failed with error:\n{other:?}");
}
}
if exit_code != 0 {
break;
}
}
Ok(exit_code)
}
Err(other) => {
panic!("build_file failed with error:\n{other:?}");
_ => {
match check_file(
&arena,
roc_file_path.to_owned(),
opt_main_path.cloned(),
emit_timings,
RocCacheDir::Persistent(cache::roc_cache_packages_dir().as_path()),
threading,
) {
Ok((problems, total_time)) => {
problems.print_error_warning_count(total_time);
Ok(problems.exit_code())
}
Err(LoadingProblem::FormattedReport(report)) => {
print!("{report}");
Ok(1)
}
Err(other) => {
panic!("build_file failed with error:\n{other:?}");
}
}
}
}
}
@ -364,11 +414,7 @@ fn main() -> io::Result<()> {
Ok(format_exit_code)
}
Some((CMD_VERSION, _)) => {
print!(
"{}",
concatcp!("roc ", include_str!("../../../version.txt"))
);
println!("roc {}", VERSION);
Ok(0)
}
_ => unreachable!(),

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,18 +0,0 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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,12 +0,0 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.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,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,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,7 +0,0 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br" }
import pf.Stdout
import Menu { echo: Stdout.line }
main =
Menu.menu "Agus"

View file

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

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

@ -1,7 +1,4 @@
app "fibonacci"
packages { pf: "fibonacci-platform/main.roc" }
imports []
provides [main] to pf
app [main] { pf: platform "fibonacci-platform/main.roc" }
main = \n -> fib n 0 1

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,82 @@
module [
Community,
empty,
addPerson,
addFriend,
Person,
walkFriendNames,
]
## Datatype representing a community for demonstration purposes in inspect-gui.roc and inspect-logging.roc
Community := {
people : List Person,
friends : List (Set U64),
}
implements [Inspect]
Person := {
firstName : Str,
lastName : Str,
age : U8,
hasBeard : Bool,
favoriteColor : Color,
}
implements [Inspect]
Color : [
Red,
Green,
Blue,
RGB (U8, U8, U8),
]
empty = @Community { people: [], friends: [] }
addPerson = \@Community { people, friends }, person ->
@Community {
people: List.append people (@Person person),
friends: List.append friends (Set.empty {}),
}
addFriend = \@Community { people, friends }, from, to ->
when (List.get friends from, List.get friends to) is
(Ok fromSet, Ok toSet) ->
@Community {
people,
friends: friends
|> List.set from (Set.insert fromSet to)
|> List.set to (Set.insert toSet from),
}
_ ->
@Community { people, friends }
walkFriendNames : Community, state, (state, Str, Set Str -> state) -> state
walkFriendNames = \@Community { people, friends }, s0, nextFn ->
(out, _) =
List.walk friends (s0, 0) \(s1, id), friendSet ->
(@Person person) =
when List.get people id is
Ok v -> v
Err _ -> crash "Unknown Person"
personName =
person.firstName
|> Str.concat " "
|> Str.concat person.lastName
friendNames =
Set.walk friendSet (Set.empty {}) \friendsSet, friendId ->
(@Person friend) =
when List.get people friendId is
Ok v -> v
Err _ -> crash "Unknown Person"
friendName =
friend.firstName
|> Str.concat " "
|> Str.concat friend.lastName
Set.insert friendsSet friendName
(nextFn s1 personName friendNames, id + 1)
out

View file

@ -1,4 +1,4 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br" }
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br" }
import pf.Stdout

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

@ -0,0 +1,27 @@
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
import pf.Effect
main! : {} => {}
main! = \{} ->
first = ask! "What's your first name?"
last = ask! "What's your last name?"
Effect.putLine! "\nHi, $(first) $(last)!\n"
when Str.toU8 (ask! "How old are you?") is
Err InvalidNumStr ->
Effect.putLine! "Enter a valid number"
Ok age if age >= 18 ->
Effect.putLine! "\nNice! You can vote!"
Ok age ->
Effect.putLine! "\nYou'll be able to vote in $(Num.toStr (18 - age)) years"
Effect.putLine! "\nBye! 👋"
ask! : Str => Str
ask! = \question ->
Effect.putLine! question
Effect.getLine! {}

View file

@ -0,0 +1,7 @@
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
import pf.Effect
main! : {} => {}
main! = \{} ->
Effect.putLine! "I'm an effect 👻"

View file

@ -0,0 +1,8 @@
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
import pf.Effect
main! : {} => {}
main! = \{} ->
_ = Effect.getLine! {}
Effect.putLine! "I asked for input and I ignored it. Deal with it! 😎"

View file

@ -0,0 +1,35 @@
#
# Shows how Roc values can be logged
#
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
import pf.Effect
import Community
main! = \{} ->
Community.empty
|> Community.addPerson {
firstName: "John",
lastName: "Smith",
age: 27,
hasBeard: Bool.true,
favoriteColor: Blue,
}
|> Community.addPerson {
firstName: "Debby",
lastName: "Johnson",
age: 47,
hasBeard: Bool.false,
favoriteColor: Green,
}
|> Community.addPerson {
firstName: "Jane",
lastName: "Doe",
age: 33,
hasBeard: Bool.false,
favoriteColor: RGB (255, 255, 0),
}
|> Community.addFriend 0 2
|> Community.addFriend 1 2
|> Inspect.toStr
|> Effect.putLine!

View file

@ -0,0 +1,16 @@
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
import pf.Effect
main! : {} => {}
main! = \{} ->
friends = ["Lu", "Marce", "Joaquin", "Chloé", "Mati", "Pedro"]
printAll! friends
printAll! : List Str => {}
printAll! = \friends ->
when friends is
[] -> {}
[first, .. as remaining] ->
Effect.putLine! first
printAll! remaining

View file

@ -0,0 +1,24 @@
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
import pf.Effect
main! : {} => {}
main! = \{} ->
_ =
authenticate! {}
|> Result.onErr! \BadPass ->
Effect.putLine! "LOG: Failed login attempt"
Ok "Bad password"
{}
authenticate! : {} => Result Str [BadPass]
authenticate! = \{} ->
Effect.putLine! "Enter your password:"
password = Effect.getLine! {}
if password == "password" then
Ok "You are in"
else
Err BadPass

View file

@ -0,0 +1,19 @@
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
import pf.Effect
main! : {} => {}
main! = \{} ->
["Welcome!", "What's your name?"]
|> List.forEach! Effect.putLine!
line = Effect.getLine! {}
if line == "secret" then
Effect.putLine! "You found the secret"
Effect.putLine! "Congratulations!"
else
{}
Effect.putLine! "You entered: $(line)"
Effect.putLine! "It is known"

View file

@ -0,0 +1,22 @@
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
import pf.Effect
Fx : {
getLine!: {} => Str,
}
main! : {} => {}
main! = \{} ->
notEffectful : Fx
notEffectful = {
getLine!: \{} -> "hardcoded"
}
effectful : Fx
effectful = {
getLine!: Effect.getLine!
}
Effect.putLine! "notEffectful: $(notEffectful.getLine! {})"
Effect.putLine! "effectful: $(effectful.getLine! {})"

View file

@ -0,0 +1,12 @@
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
import pf.Effect
main! : {} => {}
main! = \{} ->
logged! "hello" (\{} -> Effect.putLine! "Hello, World!")
logged! = \name, fx! ->
Effect.putLine! "Before $(name)"
fx! {}
Effect.putLine! "After $(name)"

View file

@ -1,7 +1,4 @@
app "expects-test"
packages { pf: "zig-platform/main.roc" }
imports []
provides [main] to pf
app [main] { pf: platform "../test-platform-simple-zig/main.roc" }
makeA =
a = 1
@ -24,7 +21,7 @@ polyDbg = \x ->
main =
str = "this will for sure be a large string so when we split it it will use seamless slices which affect printing"
words = Str.split str " "
words = Str.splitOn str " "
expect words == []
x = 42

View file

@ -1,10 +1,8 @@
interface Direct
exposes [
addAndStringify,
]
imports [
Transitive,
]
module [
addAndStringify,
]
import Transitive
addAndStringify = \num1, num2 ->
Num.toStr (Transitive.add num1 num2)

View file

@ -0,0 +1,7 @@
module [
add,
]
add = \num1, num2 -> (num1 + num2)
expect add 1 2 == 3

View file

@ -0,0 +1,3 @@
package [
Direct,
] {}

View file

@ -0,0 +1,108 @@
module [Context, Data, with, getChar, Option, pushStack, popStack, toStr, inWhileScope]
import pf.File
import Variable exposing [Variable]
Option a : [Some a, None]
# The underlying context of the current location within the file
Data : [Lambda (List U8), Number I32, Var Variable]
# While loops are special and have their own Scope specific state.
WhileState : { cond : List U8, body : List U8, state : [InCond, InBody] }
Scope : { data : Option File.Handle, index : U64, buf : List U8, whileInfo : Option WhileState }
State : [Executing, InComment, InLambda U64 (List U8), InString (List U8), InNumber I32, InSpecialChar, LoadChar]
Context : { scopes : List Scope, stack : List Data, vars : List Data, state : State }
pushStack : Context, Data -> Context
pushStack = \ctx, data ->
{ ctx & stack: List.append ctx.stack data }
# I think an open tag union should just work here.
# Instead at a call sites, I need to match on the error and then return the same error.
# Otherwise it hits unreachable code in ir.rs
popStack : Context -> Result [T Context Data] [EmptyStack]
popStack = \ctx ->
when List.last ctx.stack is
Ok val ->
poppedCtx = { ctx & stack: List.dropAt ctx.stack (List.len ctx.stack - 1) }
Ok (T poppedCtx val)
Err ListWasEmpty ->
Err EmptyStack
toStrData : Data -> Str
toStrData = \data ->
when data is
Lambda _ -> "[]"
Number n -> Num.toStr (Num.intCast n)
Var v -> Variable.toStr v
toStrState : State -> Str
toStrState = \state ->
when state is
Executing -> "Executing"
InComment -> "InComment"
InString _ -> "InString"
InNumber _ -> "InNumber"
InLambda _ _ -> "InLambda"
InSpecialChar -> "InSpecialChar"
LoadChar -> "LoadChar"
toStr : Context -> Str
toStr = \{ scopes, stack, state, vars } ->
depth = Num.toStr (List.len scopes)
stateStr = toStrState state
stackStr = Str.joinWith (List.map stack toStrData) " "
varsStr = Str.joinWith (List.map vars toStrData) " "
"\n============\nDepth: $(depth)\nState: $(stateStr)\nStack: [$(stackStr)]\nVars: [$(varsStr)]\n============\n"
with : Str, (Context -> Task {} a) -> Task {} a
with = \path, callback ->
File.withOpen path \handle ->
# I cant define scope here and put it in the list in callback. It breaks alias anaysis.
# Instead I have to inline this.
# root_scope = { data: Some handle, index: 0, buf: [], whileInfo: None }
callback { scopes: [{ data: Some handle, index: 0, buf: [], whileInfo: None }], state: Executing, stack: [], vars: List.repeat (Number 0) Variable.totalCount }
# I am pretty sure there is a syntax to destructure and keep a reference to the whole, but Im not sure what it is.
getChar : Context -> Task [T U8 Context] [EndOfData, NoScope]
getChar = \ctx ->
when List.last ctx.scopes is
Ok scope ->
(T val newScope) = getCharScope! scope
Task.ok (T val { ctx & scopes: List.set ctx.scopes (List.len ctx.scopes - 1) newScope })
Err ListWasEmpty ->
Task.err NoScope
getCharScope : Scope -> Task [T U8 Scope] [EndOfData, NoScope]
getCharScope = \scope ->
when List.get scope.buf scope.index is
Ok val ->
Task.ok (T val { scope & index: scope.index + 1 })
Err OutOfBounds ->
when scope.data is
Some h ->
bytes = File.chunk! h
when List.first bytes is
Ok val ->
# This starts at 1 because the first character is already being returned.
Task.ok (T val { scope & buf: bytes, index: 1 })
Err ListWasEmpty ->
Task.err EndOfData
None ->
Task.err EndOfData
inWhileScope : Context -> Bool
inWhileScope = \ctx ->
when List.last ctx.scopes is
Ok scope ->
scope.whileInfo != None
Err ListWasEmpty ->
Bool.false

View file

@ -0,0 +1,6 @@
# False Interpreter
This is an interpreter for the [false programming language](https://strlen.com/false-language/).
It is currently functional but runs in a way that devours stack space.
There are many examples of applications in the examples sub folder.
Many of them will currently cause stack overflows if stack size is not increased with something like `ulimit -s unlimited`.

View file

@ -0,0 +1,34 @@
module [Variable, fromUtf8, toIndex, totalCount, toStr]
# Variables in False can only be single letters. Thus, the valid variables are "a" to "z".
# This opaque type deals with ensure we always have valid variables.
Variable := U8
totalCount : U64
totalCount =
0x7A # "z"
- 0x61 # "a"
+ 1
toStr : Variable -> Str
toStr = \@Variable char ->
when Str.fromUtf8 [char] is
Ok str -> str
_ -> "_"
fromUtf8 : U8 -> Result Variable [InvalidVariableUtf8]
fromUtf8 = \char ->
if
char
>= 0x61 # "a"
&& char
<= 0x7A # "z"
then
Ok (@Variable char)
else
Err InvalidVariableUtf8
toIndex : Variable -> U64
toIndex = \@Variable char ->
Num.intCast (char - 0x61) # "a"
# List.first (Str.toUtf8 "a")

View file

@ -0,0 +1,5 @@
{ False version of 99 Bottles by Marcus Comstedt (marcus@lysator.liu.se) }
[$0=["no more bottles"]?$1=["One bottle"]?$1>[$." bottles"]?%" of beer"]b:
100[$0>][$b;!" on the wall, "$b;!".
"1-"Take one down, pass it around, "$b;!" on the wall.
"]#%

View file

@ -0,0 +1,224 @@
{
This should do the exact same thing as the linux cksum utility.
It does a crc32 of the input data.
One core difference, this reads off of stdin while cksum reads from a file.
With the interpreter, it currently runs about 350x slower though and requires extended stack size.
}
{
Load 256 constants from https://github.com/wertarbyte/coreutils/blob/f70c7b785b93dd436788d34827b209453157a6f2/src/cksum.c#L117
To support the original false interpreter, numbers must be less than 32000.
To deal with loading, just split all the numbers in two chunks.
First chunk is lower 16 bits, second chunk is higher 16 bits shift to the right.
Its values are then shifted back and merged together.
}
16564 45559 65536*| 23811 46390 65536*| 31706 47221 65536*| 26221 48308 65536*|
13928 41715 65536*| 11231 42546 65536*| 3334 43889 65536*| 4273 44976 65536*|
44300 38911 65536*| 45243 37694 65536*| 38498 40573 65536*| 35797 39612 65536*|
56272 34043 65536*| 50791 32826 65536*| 57534 36217 65536*| 64777 35256 65536*|
39876 64998 65536*| 34419 63783 65536*| 41130 62564 65536*| 48413 61605 65536*|
60696 61154 65536*| 61615 59939 65536*| 54902 59232 65536*| 52161 58273 65536*|
30332 56302 65536*| 27595 57135 65536*| 19730 53868 65536*| 20645 54957 65536*|
160 51434 65536*| 7447 52267 65536*| 15310 49512 65536*| 9849 50601 65536*|
63060 10708 65536*| 60387 11541 65536*| 52538 8278 65536*| 53389 9367 65536*|
32904 15056 65536*| 40255 15889 65536*| 48102 13138 65536*| 42577 14227 65536*|
7148 4060 65536*| 1627 2845 65536*| 8322 1630 65536*| 15669 671 65536*|
27952 7384 65536*| 28807 6169 65536*| 22110 5466 65536*| 19433 4507 65536*|
11556 26053 65536*| 12435 24836 65536*| 5706 27719 65536*| 3069 26758 65536*|
23544 30401 65536*| 17999 29184 65536*| 24726 32579 65536*| 32033 31618 65536*|
49308 17357 65536*| 56619 18188 65536*| 64498 19023 65536*| 58949 20110 65536*|
46656 20681 65536*| 44023 21512 65536*| 36142 22859 65536*| 37017 23946 65536*|
12483 34161 65536*| 11636 33200 65536*| 2989 36083 65536*| 5658 34866 65536*|
17951 38517 65536*| 23464 37556 65536*| 32113 40951 65536*| 24774 39734 65536*|
56699 41849 65536*| 49356 42936 65536*| 58901 43771 65536*| 64418 44602 65536*|
43943 45181 65536*| 46608 46268 65536*| 37065 47615 65536*| 36222 48446 65536*|
60339 51552 65536*| 62980 52641 65536*| 53469 49378 65536*| 52586 50211 65536*|
40303 55908 65536*| 32984 56997 65536*| 42497 54246 65536*| 48054 55079 65536*|
1547 61288 65536*| 7100 60329 65536*| 15717 59114 65536*| 8402 57899 65536*|
28887 64620 65536*| 28000 63661 65536*| 19385 62958 65536*| 22030 61743 65536*|
34339 7506 65536*| 39828 6547 65536*| 48461 5328 65536*| 41210 4113 65536*|
61695 3670 65536*| 60744 2711 65536*| 52113 2004 65536*| 54822 789 65536*|
27547 15194 65536*| 30252 16283 65536*| 20725 13016 65536*| 19778 13849 65536*|
7495 10334 65536*| 240 11423 65536*| 9769 8668 65536*| 15262 9501 65536*|
23891 20803 65536*| 16612 21890 65536*| 26173 22721 65536*| 31626 23552 65536*|
11151 16967 65536*| 13880 18054 65536*| 4321 19397 65536*| 3414 20228 65536*|
45291 30539 65536*| 44380 29578 65536*| 35717 32457 65536*| 38450 31240 65536*|
50743 25679 65536*| 56192 24718 65536*| 64857 28109 65536*| 57582 26892 65536*|
41050 55547 65536*| 48621 56378 65536*| 39732 53625 65536*| 34435 54712 65536*|
54918 52223 65536*| 52017 53054 65536*| 60904 49789 65536*| 61535 50876 65536*|
19938 65267 65536*| 20565 64050 65536*| 30348 63345 65536*| 27451 62384 65536*|
15166 60919 65536*| 9865 59702 65536*| 80 58485 65536*| 7655 57524 65536*|
31530 38122 65536*| 26269 36907 65536*| 16452 40296 65536*| 24051 39337 65536*|
3574 34798 65536*| 4161 33583 65536*| 13976 36460 65536*| 11055 35501 65536*|
38546 45794 65536*| 35621 46627 65536*| 44540 47968 65536*| 45131 49057 65536*|
57422 41446 65536*| 65017 42279 65536*| 56096 43108 65536*| 50839 44197 65536*|
5818 16600 65536*| 2829 17433 65536*| 11732 18778 65536*| 12387 19867 65536*|
24678 21468 65536*| 32209 22301 65536*| 23304 23134 65536*| 18111 24223 65536*|
64258 26320 65536*| 59061 25105 65536*| 49260 28498 65536*| 56795 27539 65536*|
36318 30164 65536*| 36969 28949 65536*| 46768 31830 65536*| 43783 30871 65536*|
52682 3273 65536*| 53373 2056 65536*| 63140 1355 65536*| 60179 394 65536*|
47894 8141 65536*| 42657 6924 65536*| 32888 5711 65536*| 40399 4750 65536*|
8306 10945 65536*| 15813 11776 65536*| 6940 9027 65536*| 1707 10114 65536*|
22190 14789 65536*| 19225 15620 65536*| 28096 12359 65536*| 28791 13446 65536*|
53293 60541 65536*| 52634 59580 65536*| 60227 58879 65536*| 63220 57662 65536*|
42737 65401 65536*| 47942 64440 65536*| 40351 63227 65536*| 32808 62010 65536*|
15765 51829 65536*| 8226 52916 65536*| 1787 50167 65536*| 6988 50998 65536*|
19273 55665 65536*| 22270 56752 65536*| 28711 53491 65536*| 28048 54322 65536*|
2909 41068 65536*| 5866 42157 65536*| 12339 43502 65536*| 11652 44335 65536*|
32129 45928 65536*| 24630 47017 65536*| 18159 47850 65536*| 23384 48683 65536*|
59109 34404 65536*| 64338 33445 65536*| 56715 36838 65536*| 49212 35623 65536*|
36921 38240 65536*| 36238 37281 65536*| 43863 40162 65536*| 46816 38947 65536*|
26317 29790 65536*| 31610 28831 65536*| 23971 32220 65536*| 16404 31005 65536*|
4113 26458 65536*| 3494 25499 65536*| 11135 28376 65536*| 14024 27161 65536*|
35701 21078 65536*| 38594 22167 65536*| 45083 23508 65536*| 44460 24341 65536*|
64937 16722 65536*| 57374 17811 65536*| 50887 18640 65536*| 56176 19473 65536*|
48573 14415 65536*| 40970 15502 65536*| 34515 12749 65536*| 39780 13580 65536*|
52065 11083 65536*| 54998 12170 65536*| 61455 8905 65536*| 60856 9736 65536*|
20485 7751 65536*| 19890 6790 65536*| 27499 6085 65536*| 30428 4868 65536*|
9945 3395 65536*| 15214 2434 65536*| 7607 1217 65536*| 0
{load crc32 base 0}
0
{load the xor function into x for use later}
[
{duplicate both inputs}
{nand inputs}
&~
{bring original inputs to top of stack with rotation}
@@
{or inputs}
|
{and the nand and or result to get xor}
&
]x:
{load right shift function to r for later use}
[
{will right shift the second from top value by the top value}
{while top value > 0}
[$0>][
{minus one from the top value}
1-
{swap values}
\
{divide the bottom value by 2}
2/
{zero top bit to avoid sign extension}
65535 32767 65536*|&
{swap back}
\
]#
{drop the top value}
%
]r:
{i will be used to count the length. Set it to zero to start}
0i:
{load the first character}
^
{while data != - 1: # -1 is eof}
[$1_=~][
{increment i}
i;1+i:
{duplicate crc32 which is on the stack under the current character}
{Shift crc32 right by 24}
24r;!
{xor the data and crc32}
x;!
{and with 255 to ensure it is in range}
255&
{
The index goes into the constant array, but currently the crc32 is loaded infront of the constant array.
Add 1 to the index to skip this and then load the value from the stack.
}
1+ø
{swap the crc32 on top of the stack}
\
{left shift it by 8 (multiply by 0x100)}
256*
{xor with the loaded constant}
x;!
{load the next character}
^
]#
{drop the -1 left on top of the stack}
%
{to match ck sum, add length to crc32}
{load i}
i;
{Note, this will break if i is negative from overflow}
{while i != 0}
[$0=~][
{duplicate and get last byte of i by and with 0xFF}
$255&
{duplicate crc32 which is on the stack under i and the current byte}
{Shift crc32 right by 24}
24r;!
{xor the data and crc32}
x;!
{and with 255 to ensure it is in range}
255&
{
The index goes into the constant array, but currently the i and the crc32 is loaded infront of the constant array.
Add 1 to the index to skip this and then load the value from the stack.
}
2+ø
{rotate the crc32 on top of the stack}
@
{left shift it by 8 (multiply by 0x100)}
256*
{xor with the loaded constant}
x;!
{swap i back on top of the stack and right shift it by 8}
\8r;!
]#
{drop i}
%
{ binary negate the crc32 }
~
{print the crc32}
.
{print a space}
" "
{print the length}
i;.

View file

@ -0,0 +1,2 @@
{ This will stack overflow if the input is too large }
[^$1_=~][,]#

View file

@ -0,0 +1,7 @@
{ unix cksum, CRC32. -- Jonathan Neuschäfer <j.neuschaefer@gmx.net> }
[[$0>][\2*\1-]#%]l:[0\128[$0>][$2O&0>[$@\64/x;!@@$g;*@x;!@@]?2/]#%%]h:
[[$0>][\2/\1-]#%]r:[1O$8 28l;!1-&$@=~\24r;!\[128|]?x;!h;!\8l;!x;!]s:79764919g:
[q1_0[\1+\^$1_>]s;#%@%\$@[1O0>][1O255&s;!\8r;!\]#~n;!32,%.10,]m:[$2O&@@|~|~]x:
[$0\>\1O[$u;!]?\~[$.]?%]n:[h;y:[3+O]h:255[$0>][$y;!\1-]#m;!256[$0>][\%1-]#%]o:
[1000$$**0@[$$0\>\4O\>~|][2O-\1+\]#\.\[10/$0>][\$2O/$.2O*-\]#%%]u: {width: 78}
{ usage: run m for "main" or o for "optimized" (builds a lookup table) } o;!

View file

@ -0,0 +1,11 @@
{ This is a comment}
{ White space doesn't matter}
{ Strings in False just automatically print...So, "Hello, World!", I guess }
"Hello, World!
"
{ Note the new line created by the white space that matters in strings }

View file

@ -0,0 +1 @@
abc

View file

@ -0,0 +1,10 @@
{
Dijkstra's odd words Problem
You'll need to enter a sentence in the Input box, ending with a period. Odd words are reversed.
}
[[$' =][%^]#]b:
[$$'.=\' =|~]w:
[$'.=~[' ,]?]s:
[w;![^o;!\,]?]o:
^b;![$'.=~][w;[,^]#b;!s;!o;!b;!s;!]#,

View file

@ -0,0 +1,2 @@
{This prints all of the primes from 1 to 99}
99 9[1-$][\$@$@$@$@\/*=[1-$$[%\1-$@]?0=[\$.' ,\]?]?]#

Some files were not shown because too many files have changed in this diff Show more