Merge remote-tracking branch 'origin/main' into csv_decoding-server_example

This commit is contained in:
Folkert 2022-09-28 16:38:40 +02:00
commit 2e5f207283
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
14 changed files with 271 additions and 59 deletions

16
Cargo.lock generated
View file

@ -1871,9 +1871,9 @@ checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca"
[[package]] [[package]]
name = "insta" name = "insta"
version = "1.19.0" version = "1.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37dc501f12ec0c339b385787fa89ffda3d5d2caa62e558da731134c24d6e0c4" checksum = "58a931b01c76064c5be919faa2ef0dc570e9a889dcd1e5fef08a8ca6eb4d6c0b"
dependencies = [ dependencies = [
"console", "console",
"linked-hash-map", "linked-hash-map",
@ -2776,9 +2776,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]] [[package]]
name = "peg" name = "peg"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af728fe826811af3b38c37e93de6d104485953ea373d656eebae53d6987fcd2c" checksum = "a07f2cafdc3babeebc087e499118343442b742cc7c31b4d054682cc598508554"
dependencies = [ dependencies = [
"peg-macros", "peg-macros",
"peg-runtime", "peg-runtime",
@ -2786,9 +2786,9 @@ dependencies = [
[[package]] [[package]]
name = "peg-macros" name = "peg-macros"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4536be147b770b824895cbad934fccce8e49f14b4c4946eaa46a6e4a12fcdc16" checksum = "4a90084dc05cf0428428e3d12399f39faad19b0909f64fb9170c9fdd6d9cd49b"
dependencies = [ dependencies = [
"peg-runtime", "peg-runtime",
"proc-macro2", "proc-macro2",
@ -2797,9 +2797,9 @@ dependencies = [
[[package]] [[package]]
name = "peg-runtime" name = "peg-runtime"
version = "0.8.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9b0efd3ba03c3a409d44d60425f279ec442bcf0b9e63ff4e410da31c8b0f69f" checksum = "9fa00462b37ead6d11a82c9d568b26682d78e0477dc02d1966c013af80969739"
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"

View file

@ -87,6 +87,7 @@ mod cli_run {
executable_filename: &'a str, executable_filename: &'a str,
stdin: &'a [&'a str], stdin: &'a [&'a str],
arguments: &'a [Arg<'a>], arguments: &'a [Arg<'a>],
env: &'a [(&'a str, &'a str)],
expected_ending: &'a str, expected_ending: &'a str,
use_valgrind: bool, use_valgrind: bool,
} }
@ -136,12 +137,14 @@ mod cli_run {
compile_out compile_out
} }
#[allow(clippy::too_many_arguments)]
fn check_output_with_stdin( fn check_output_with_stdin(
file: &Path, file: &Path,
stdin: &[&str], stdin: &[&str],
executable_filename: &str, executable_filename: &str,
flags: &[&str], flags: &[&str],
app_args: &[String], app_args: &[String],
extra_env: &[(&str, &str)],
expected_ending: &str, expected_ending: &str,
use_valgrind: bool, use_valgrind: bool,
) { ) {
@ -214,16 +217,31 @@ mod cli_run {
file.with_file_name(executable_filename).to_str().unwrap(), file.with_file_name(executable_filename).to_str().unwrap(),
stdin.iter().copied(), stdin.iter().copied(),
app_args, app_args,
extra_env.iter().copied(),
) )
} }
} }
CliMode::Roc => run_roc_on(file, flags.clone(), stdin, app_args), CliMode::Roc => {
CliMode::RocRun => run_roc_on( if !extra_env.is_empty() {
file, // TODO: environment is not currently forwarded by Roc to the target
iter::once(CMD_RUN).chain(flags.clone()), // binary, so this would fail!
stdin, continue;
app_args, }
), run_roc_on(file, flags.clone(), stdin, app_args)
}
CliMode::RocRun => {
if !extra_env.is_empty() {
// TODO: environment is not currently forwarded by Roc to the target
// binary, so this would fail!
continue;
}
run_roc_on(
file,
iter::once(CMD_RUN).chain(flags.clone()),
stdin,
app_args,
)
}
}; };
if !&out.stdout.ends_with(expected_ending) { if !&out.stdout.ends_with(expected_ending) {
@ -367,6 +385,7 @@ mod cli_run {
example.executable_filename, example.executable_filename,
&custom_flags, &custom_flags,
&app_args, &app_args,
example.env,
example.expected_ending, example.expected_ending,
example.use_valgrind, example.use_valgrind,
); );
@ -381,6 +400,7 @@ mod cli_run {
example.executable_filename, example.executable_filename,
&custom_flags, &custom_flags,
&app_args, &app_args,
example.env,
example.expected_ending, example.expected_ending,
example.use_valgrind, example.use_valgrind,
); );
@ -394,6 +414,7 @@ mod cli_run {
example.executable_filename, example.executable_filename,
&[LINKER_FLAG, "legacy"], &[LINKER_FLAG, "legacy"],
&app_args, &app_args,
example.env,
example.expected_ending, example.expected_ending,
example.use_valgrind, example.use_valgrind,
); );
@ -431,6 +452,7 @@ mod cli_run {
executable_filename: "helloWorld", executable_filename: "helloWorld",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending:"Hello, World!\n", expected_ending:"Hello, World!\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -439,6 +461,7 @@ mod cli_run {
executable_filename: "rocLovesPlatforms", executable_filename: "rocLovesPlatforms",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending:"Which platform am I running on now?\n", expected_ending:"Which platform am I running on now?\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -458,6 +481,7 @@ mod cli_run {
executable_filename: "rocLovesRust", executable_filename: "rocLovesRust",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending:"Roc <3 Rust!\n", expected_ending:"Roc <3 Rust!\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -466,6 +490,7 @@ mod cli_run {
executable_filename: "rocLovesSwift", executable_filename: "rocLovesSwift",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending:"Roc <3 Swift!\n", expected_ending:"Roc <3 Swift!\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -474,6 +499,7 @@ mod cli_run {
executable_filename: "rocLovesWebAssembly", executable_filename: "rocLovesWebAssembly",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending:"Roc <3 Web Assembly!\n", expected_ending:"Roc <3 Web Assembly!\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -482,6 +508,7 @@ mod cli_run {
executable_filename: "rocLovesZig", executable_filename: "rocLovesZig",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending:"Roc <3 Zig!\n", expected_ending:"Roc <3 Zig!\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -490,6 +517,7 @@ mod cli_run {
executable_filename: "libhello", executable_filename: "libhello",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending:"", expected_ending:"",
use_valgrind: true, use_valgrind: true,
}, },
@ -498,6 +526,7 @@ mod cli_run {
executable_filename: "fibonacci", executable_filename: "fibonacci",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending:"55\n", expected_ending:"55\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -506,6 +535,7 @@ mod cli_run {
executable_filename: "hello-gui", executable_filename: "hello-gui",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "", expected_ending: "",
use_valgrind: false, use_valgrind: false,
}, },
@ -514,6 +544,7 @@ mod cli_run {
executable_filename: "breakout", executable_filename: "breakout",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "", expected_ending: "",
use_valgrind: false, use_valgrind: false,
}, },
@ -522,6 +553,7 @@ mod cli_run {
executable_filename: "quicksort", executable_filename: "quicksort",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n", expected_ending: "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -538,14 +570,28 @@ mod cli_run {
executable_filename: "args", executable_filename: "args",
stdin: &[], stdin: &[],
arguments: &[Arg::PlainText("log"), Arg::PlainText("-b"), Arg::PlainText("3"), Arg::PlainText("--num"), Arg::PlainText("81")], arguments: &[Arg::PlainText("log"), Arg::PlainText("-b"), Arg::PlainText("3"), Arg::PlainText("--num"), Arg::PlainText("81")],
env: &[],
expected_ending: "4\n", expected_ending: "4\n",
use_valgrind: false, use_valgrind: false,
}, },
env:"interactive" => Example {
filename: "env.roc",
executable_filename: "env",
stdin: &[],
arguments: &[],
env: &[("EDITOR", "roc-editor"), ("SHLVL", "3"), ("LETTERS", "a,c,e,j")],
expected_ending: (
"Your favorite editor is roc-editor!\n\
Your current shell level is 3!\n\
Your favorite letters are: a c e j\n"),
use_valgrind: false,
},
effects:"interactive" => Example { effects:"interactive" => Example {
filename: "effects.roc", filename: "effects.roc",
executable_filename: "effects", executable_filename: "effects",
stdin: &["hi there!"], stdin: &["hi there!"],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "hi there!\nIt is known\n", expected_ending: "hi there!\nIt is known\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -562,6 +608,7 @@ mod cli_run {
executable_filename: "form", executable_filename: "form",
stdin: &["Giovanni\n", "Giorgio\n"], stdin: &["Giovanni\n", "Giorgio\n"],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "Hi, Giovanni Giorgio! 👋\n", expected_ending: "Hi, Giovanni Giorgio! 👋\n",
use_valgrind: false, use_valgrind: false,
}, },
@ -570,6 +617,7 @@ mod cli_run {
executable_filename: "tui", executable_filename: "tui",
stdin: &["foo\n"], // NOTE: adding more lines leads to memory leaks stdin: &["foo\n"], // NOTE: adding more lines leads to memory leaks
arguments: &[], arguments: &[],
env: &[],
expected_ending: "Hello Worldfoo!\n", expected_ending: "Hello Worldfoo!\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -595,6 +643,7 @@ mod cli_run {
executable_filename: "false", executable_filename: "false",
stdin: &[], stdin: &[],
arguments: &[Arg::ExamplePath("examples/hello.false")], arguments: &[Arg::ExamplePath("examples/hello.false")],
env: &[],
expected_ending:"Hello, World!\n", expected_ending:"Hello, World!\n",
use_valgrind: false, use_valgrind: false,
} }
@ -604,6 +653,7 @@ mod cli_run {
executable_filename: "swiftui", executable_filename: "swiftui",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "", expected_ending: "",
use_valgrind: false, use_valgrind: false,
}, },
@ -613,6 +663,7 @@ mod cli_run {
executable_filename: "static-site", executable_filename: "static-site",
stdin: &[], stdin: &[],
arguments: &[Arg::ExamplePath("input"), Arg::ExamplePath("output")], arguments: &[Arg::ExamplePath("input"), Arg::ExamplePath("output")],
env: &[],
expected_ending: "Processed 3 files with 3 successes and 0 errors\n", expected_ending: "Processed 3 files with 3 successes and 0 errors\n",
use_valgrind: false, use_valgrind: false,
} }
@ -623,6 +674,7 @@ mod cli_run {
executable_filename: "parse-movies-csv", executable_filename: "parse-movies-csv",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "Parse success!\n", expected_ending: "Parse success!\n",
use_valgrind: false, use_valgrind: false,
} }
@ -671,6 +723,7 @@ mod cli_run {
benchmark.executable_filename, benchmark.executable_filename,
&[], &[],
&app_args, &app_args,
benchmark.env,
benchmark.expected_ending, benchmark.expected_ending,
benchmark.use_valgrind, benchmark.use_valgrind,
); );
@ -689,6 +742,7 @@ mod cli_run {
benchmark.executable_filename, benchmark.executable_filename,
&[PREBUILT_PLATFORM], &[PREBUILT_PLATFORM],
&app_args, &app_args,
benchmark.env,
benchmark.expected_ending, benchmark.expected_ending,
benchmark.use_valgrind, benchmark.use_valgrind,
); );
@ -700,6 +754,7 @@ mod cli_run {
benchmark.executable_filename, benchmark.executable_filename,
&[PREBUILT_PLATFORM, OPTIMIZE_FLAG], &[PREBUILT_PLATFORM, OPTIMIZE_FLAG],
&app_args, &app_args,
benchmark.env,
benchmark.expected_ending, benchmark.expected_ending,
benchmark.use_valgrind, benchmark.use_valgrind,
); );
@ -813,6 +868,7 @@ mod cli_run {
executable_filename: "nqueens", executable_filename: "nqueens",
stdin: &["6"], stdin: &["6"],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "4\n", expected_ending: "4\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -821,6 +877,7 @@ mod cli_run {
executable_filename: "cfold", executable_filename: "cfold",
stdin: &["3"], stdin: &["3"],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "11 & 11\n", expected_ending: "11 & 11\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -829,6 +886,7 @@ mod cli_run {
executable_filename: "deriv", executable_filename: "deriv",
stdin: &["2"], stdin: &["2"],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "1 count: 6\n2 count: 22\n", expected_ending: "1 count: 6\n2 count: 22\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -837,6 +895,7 @@ mod cli_run {
executable_filename: "rbtree-ck", executable_filename: "rbtree-ck",
stdin: &["100"], stdin: &["100"],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "10\n", expected_ending: "10\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -845,6 +904,7 @@ mod cli_run {
executable_filename: "rbtree-insert", executable_filename: "rbtree-insert",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "Node Black 0 {} Empty Empty\n", expected_ending: "Node Black 0 {} Empty Empty\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -853,6 +913,7 @@ mod cli_run {
// executable_filename: "rbtree-del", // executable_filename: "rbtree-del",
// stdin: &["420"], // stdin: &["420"],
// arguments: &[], // arguments: &[],
// env: &[],
// expected_ending: "30\n", // expected_ending: "30\n",
// use_valgrind: true, // use_valgrind: true,
// }, // },
@ -861,6 +922,7 @@ mod cli_run {
executable_filename: "test-astar", executable_filename: "test-astar",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "True\n", expected_ending: "True\n",
use_valgrind: false, use_valgrind: false,
}, },
@ -869,6 +931,7 @@ mod cli_run {
executable_filename: "test-base64", executable_filename: "test-base64",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "encoded: SGVsbG8gV29ybGQ=\ndecoded: Hello World\n", expected_ending: "encoded: SGVsbG8gV29ybGQ=\ndecoded: Hello World\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -877,6 +940,7 @@ mod cli_run {
executable_filename: "closure", executable_filename: "closure",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "", expected_ending: "",
use_valgrind: false, use_valgrind: false,
}, },
@ -885,6 +949,7 @@ mod cli_run {
executable_filename: "issue2279", executable_filename: "issue2279",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "Hello, world!\n", expected_ending: "Hello, world!\n",
use_valgrind: true, use_valgrind: true,
}, },
@ -893,6 +958,7 @@ mod cli_run {
executable_filename: "quicksortapp", executable_filename: "quicksortapp",
stdin: &[], stdin: &[],
arguments: &[], arguments: &[],
env: &[],
expected_ending: "todo put the correct quicksort answer here", expected_ending: "todo put the correct quicksort answer here",
use_valgrind: true, use_valgrind: true,
}, },
@ -973,6 +1039,7 @@ mod cli_run {
"multi-dep-str", "multi-dep-str",
&[], &[],
&[], &[],
&[],
"I am Dep2.str2\n", "I am Dep2.str2\n",
true, true,
); );
@ -987,6 +1054,7 @@ mod cli_run {
"multi-dep-str", "multi-dep-str",
&[OPTIMIZE_FLAG], &[OPTIMIZE_FLAG],
&[], &[],
&[],
"I am Dep2.str2\n", "I am Dep2.str2\n",
true, true,
); );
@ -1001,6 +1069,7 @@ mod cli_run {
"multi-dep-thunk", "multi-dep-thunk",
&[], &[],
&[], &[],
&[],
"I am Dep2.value2\n", "I am Dep2.value2\n",
true, true,
); );
@ -1015,6 +1084,7 @@ mod cli_run {
"multi-dep-thunk", "multi-dep-thunk",
&[OPTIMIZE_FLAG], &[OPTIMIZE_FLAG],
&[], &[],
&[],
"I am Dep2.value2\n", "I am Dep2.value2\n",
true, true,
); );

View file

@ -48,12 +48,12 @@ fn check_cmd_output(
let out = if cmd_str.contains("cfold") { let out = if cmd_str.contains("cfold") {
let child = thread::Builder::new() let child = thread::Builder::new()
.stack_size(CFOLD_STACK_SIZE) .stack_size(CFOLD_STACK_SIZE)
.spawn(move || run_cmd(&cmd_str, [stdin_str], &[])) .spawn(move || run_cmd(&cmd_str, [stdin_str], &[], []))
.unwrap(); .unwrap();
child.join().unwrap() child.join().unwrap()
} else { } else {
run_cmd(&cmd_str, [stdin_str], &[]) run_cmd(&cmd_str, [stdin_str], &[], [])
}; };
if !&out.stdout.ends_with(expected_ending) { if !&out.stdout.ends_with(expected_ending) {
@ -96,13 +96,14 @@ fn bench_cmd<T: Measurement>(
if let Some(bench_group) = bench_group_opt { if let Some(bench_group) = bench_group_opt {
bench_group.bench_function(&format!("Benchmarking {:?}", executable_filename), |b| { bench_group.bench_function(&format!("Benchmarking {:?}", executable_filename), |b| {
b.iter(|| run_cmd(black_box(&cmd_str), black_box([stdin_str]), &[])) b.iter(|| run_cmd(black_box(&cmd_str), black_box([stdin_str]), &[], []))
}); });
} else { } else {
run_cmd( run_cmd(
black_box(file.with_file_name(executable_filename).to_str().unwrap()), black_box(file.with_file_name(executable_filename).to_str().unwrap()),
black_box([stdin_str]), black_box([stdin_str]),
&[], &[],
[],
); );
} }
} }

View file

@ -161,10 +161,11 @@ where
} }
} }
pub fn run_cmd<'a, I: IntoIterator<Item = &'a str>>( pub fn run_cmd<'a, I: IntoIterator<Item = &'a str>, E: IntoIterator<Item = (&'a str, &'a str)>>(
cmd_name: &str, cmd_name: &str,
stdin_vals: I, stdin_vals: I,
args: &[String], args: &[String],
env: E,
) -> Out { ) -> Out {
let mut cmd = Command::new(cmd_name); let mut cmd = Command::new(cmd_name);
@ -172,6 +173,10 @@ pub fn run_cmd<'a, I: IntoIterator<Item = &'a str>>(
cmd.arg(arg); cmd.arg(arg);
} }
for (env, val) in env.into_iter() {
cmd.env(env, val);
}
let mut child = cmd let mut child = cmd
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())

View file

@ -3732,14 +3732,21 @@ fn send_header<'a>(
// Also build a list of imported_values_to_expose (like `bar` above.) // Also build a list of imported_values_to_expose (like `bar` above.)
for (qualified_module_name, exposed_idents, region) in imported.into_iter() { for (qualified_module_name, exposed_idents, region) in imported.into_iter() {
let cloned_module_name = qualified_module_name.module.clone(); let cloned_module_name = qualified_module_name.module.clone();
let pq_module_name = match qualified_module_name.opt_package { let pq_module_name = if qualified_module_name.is_builtin() {
None => match opt_shorthand { // If this is a builtin, it must be unqualified, and we should *never* prefix it
Some(shorthand) => { // with the package shorthand! The user intended to import the module as-is here.
PQModuleName::Qualified(shorthand, qualified_module_name.module) debug_assert!(qualified_module_name.opt_package.is_none());
} PQModuleName::Unqualified(qualified_module_name.module)
None => PQModuleName::Unqualified(qualified_module_name.module), } else {
}, match qualified_module_name.opt_package {
Some(package) => PQModuleName::Qualified(package, cloned_module_name), None => match opt_shorthand {
Some(shorthand) => {
PQModuleName::Qualified(shorthand, qualified_module_name.module)
}
None => PQModuleName::Unqualified(qualified_module_name.module),
},
Some(package) => PQModuleName::Qualified(package, cloned_module_name),
}
}; };
let module_id = module_ids.get_or_insert(&pq_module_name); let module_id = module_ids.get_or_insert(&pq_module_name);

View file

@ -37,4 +37,4 @@ tempfile = "3.2.0"
bumpalo = { version = "3.11.0", features = ["collections"] } bumpalo = { version = "3.11.0", features = ["collections"] }
regex = "1.5.5" regex = "1.5.5"
lazy_static = "1.4.0" lazy_static = "1.4.0"
insta = "1.19.0" insta = "1.20.0"

View file

@ -29,4 +29,4 @@ lazy_static = "1.4.0"
indoc = "1.0.7" indoc = "1.0.7"
ven_pretty = { path = "../../vendor/pretty" } ven_pretty = { path = "../../vendor/pretty" }
pretty_assertions = "1.3.0" pretty_assertions = "1.3.0"
insta = "1.19.0" insta = "1.20.0"

View file

@ -22,7 +22,7 @@ roc_highlight = { path = "../highlight"}
roc_reporting = { path = "../reporting"} roc_reporting = { path = "../reporting"}
bumpalo = { version = "3.11.0", features = ["collections"] } bumpalo = { version = "3.11.0", features = ["collections"] }
snafu = { version = "0.7.1", features = ["backtraces"] } snafu = { version = "0.7.1", features = ["backtraces"] }
peg = "0.8.0" peg = "0.8.1"
[dev-dependencies] [dev-dependencies]
pretty_assertions = "1.3.0" pretty_assertions = "1.3.0"

View file

@ -7,5 +7,5 @@ edition = "2021"
description = "For syntax highlighting, starts with a string and returns our markup nodes." description = "For syntax highlighting, starts with a string and returns our markup nodes."
[dependencies] [dependencies]
peg = "0.8.0" peg = "0.8.1"
roc_code_markup = { path = "../code_markup"} roc_code_markup = { path = "../code_markup"}

View file

@ -34,4 +34,4 @@ roc_test_utils = { path = "../test_utils" }
roc_solve = { path = "../compiler/solve" } roc_solve = { path = "../compiler/solve" }
pretty_assertions = "1.3.0" pretty_assertions = "1.3.0"
indoc = "1.0.7" indoc = "1.0.7"
insta = "1.19.0" insta = "1.20.0"

View file

@ -6,3 +6,4 @@ form
tui tui
http-get http-get
file-io file-io
env

View file

@ -1,6 +1,5 @@
interface Env interface Env
exposes [cwd, dict, var] exposes [cwd, dict, var, decode] imports [Task.{ Task }, Path.{ Path }, InternalPath, Effect, InternalTask, EnvDecoding]
imports [Task.{ Task }, Path.{ Path }, InternalPath, Effect, InternalTask]
## Reads the [current working directory](https://en.wikipedia.org/wiki/Working_directory) ## Reads the [current working directory](https://en.wikipedia.org/wiki/Working_directory)
## from the environment. File operations on relative [Path]s are relative to this directory. ## from the environment. File operations on relative [Path]s are relative to this directory.
@ -33,31 +32,40 @@ var = \name ->
|> Effect.map (\result -> Result.mapErr result \{} -> VarNotFound) |> Effect.map (\result -> Result.mapErr result \{} -> VarNotFound)
|> InternalTask.fromEffect |> InternalTask.fromEffect
# ## Reads the given environment variable and attempts to decode it. ## Reads the given environment variable and attempts to decode it.
# ## ##
# ## The type being decoded into will be determined by type inference. For example, ## The type being decoded into will be determined by type inference. For example,
# ## if this ends up being used like a `Task U16 …` then the environment variable ## if this ends up being used like a `Task U16 …` then the environment variable
# ## will be decoded as a string representation of a `U16`. ## will be decoded as a string representation of a `U16`.
# ## ##
# ## getU16Var : Str -> Task U16 [VarNotFound, DecodeErr DecodeError]* [Env]* ## getU16Var : Str -> Task U16 [VarNotFound, DecodeErr DecodeError]* [Env]*
# ## getU16Var = \var -> Env.decode var ## getU16Var = \var -> Env.decode var
# ## # If the environment contains a variable NUM_THINGS=123, then calling ## # If the environment contains a variable NUM_THINGS=123, then calling
# ## # (getU16Var "NUM_THINGS") would return a task which succeeds with the U16 number 123. ## # (getU16Var "NUM_THINGS") would return a task which succeeds with the U16 number 123.
# ## # ## #
# ## # However, if the NUM_THINGS environment variable was set to 1234567, then ## # However, if the NUM_THINGS environment variable was set to 1234567, then
# ## # (getU16Var "NUM_THINGS") would fail because that number is too big to fit in a U16. ## # (getU16Var "NUM_THINGS") would fail because that number is too big to fit in a U16.
# ## ##
# ## Supported types: ## Supported types:
# ## - strings ## - strings
# ## - numbers, as long as they contain only numeric digits, up to one `.`, and an optional `-` at the front for negative numbers ## - numbers, as long as they contain only numeric digits, up to one `.`, and an optional `-` at the front for negative numbers
# ## - comma-separated lists (of either strings or numbers), as long as there are no spaces after the commas ## - comma-separated lists (of either strings or numbers), as long as there are no spaces after the commas
# ## ##
# ## Trying to decode into any other types will always fail with a `DecodeErr`. ## Trying to decode into any other types will always fail with a `DecodeErr`.
# decode : Str -> Task val [VarNotFound, DecodeErr DecodeError]* [Env]* decode : Str -> Task val [VarNotFound, DecodeErr DecodeError]* [Env]* | val has Decoding
# | val has Decode decode = \name ->
# decode = \var -> Effect.envVar name
# Effect.envVar var |> Effect.map
# |> InternalTask.fromEffect (
\result ->
result
|> Result.mapErr (\{} -> VarNotFound)
|> Result.try
(\varStr ->
Decode.fromBytes (Str.toUtf8 varStr) (EnvDecoding.format {})
|> Result.mapErr (\_ -> DecodeErr TooShort)))
|> InternalTask.fromEffect
## Reads all the process's environment variables into a [Dict]. ## Reads all the process's environment variables into a [Dict].
## ##
## If any key or value contains invalid Unicode, the [Unicode replacement character](https://unicode.org/glossary/#replacement_character) ## If any key or value contains invalid Unicode, the [Unicode replacement character](https://unicode.org/glossary/#replacement_character)

View file

@ -0,0 +1,95 @@
interface EnvDecoding exposes [EnvFormat, format] imports []
EnvFormat := {} has [
DecoderFormatting {
u8: envU8,
u16: envU16,
u32: envU32,
u64: envU64,
u128: envU128,
i8: envI8,
i16: envI16,
i32: envI32,
i64: envI64,
i128: envI128,
f32: envF32,
f64: envF64,
dec: envDec,
bool: envBool,
string: envString,
list: envList,
record: envRecord,
},
]
format : {} -> EnvFormat
format = \{} -> @EnvFormat {}
decodeBytesToNum = \bytes, transformer ->
when Str.fromUtf8 bytes is
Ok s ->
when transformer s is
Ok n -> { result: Ok n, rest: [] }
Err _ -> { result: Err TooShort, rest: bytes }
Err _ -> { result: Err TooShort, rest: bytes }
envU8 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toU8
envU16 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toU16
envU32 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toU32
envU64 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toU64
envU128 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toU128
envI8 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toI8
envI16 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toI16
envI32 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toI32
envI64 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toI64
envI128 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toI128
envF32 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toF32
envF64 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toF64
envDec = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toDec
envBool = Decode.custom \bytes, @EnvFormat {} ->
when Str.fromUtf8 bytes is
Ok "true" -> { result: Ok Bool.true, rest: [] }
Ok "false" -> { result: Ok Bool.false, rest: [] }
_ -> { result: Err TooShort, rest: bytes }
envString = Decode.custom \bytes, @EnvFormat {} ->
when Str.fromUtf8 bytes is
Ok s -> { result: Ok s, rest: [] }
Err _ -> { result: Err TooShort, rest: bytes }
envList = \decodeElem -> Decode.custom \bytes, @EnvFormat {} ->
# Per our supported methods of decoding, this is either a list of strings or
# a list of numbers; in either case, the list of bytes must be Utf-8
# decodable. So just parse it as a list of strings and pass each chunk to
# the element decoder. By construction, our element decoders expect to parse
# a whole list of bytes anyway.
decodeElems = \allBytes, accum ->
{ toParse, remainder } =
when List.splitFirst allBytes (Num.toU8 ',') is
Ok { before, after } ->
{ toParse: before, remainder: Some after }
Err NotFound ->
{ toParse: allBytes, remainder: None }
when Decode.decodeWith toParse decodeElem (@EnvFormat {}) is
{ result, rest } ->
when result is
Ok val ->
when remainder is
Some restBytes -> decodeElems restBytes (List.append accum val)
None -> Done (List.append accum val)
Err e -> Errored e rest
when decodeElems bytes [] is
Errored e rest -> { result: Err e, rest }
Done vals ->
{ result: Ok vals, rest: [] }
# TODO: we must currently annotate the arrows here so that the lambda sets are
# exercised, and the solver can find an ambient lambda set for the
# specialization.
envRecord : _, (_, _ -> [Keep (Decoder _ _), Skip]), (_ -> _) -> Decoder _ _
envRecord = \_initialState, _stepField, _finalizer -> Decode.custom \bytes, @EnvFormat {} ->
{ result: Err TooShort, rest: bytes }

View file

@ -0,0 +1,25 @@
app "env"
packages { pf: "cli-platform/main.roc" }
imports [pf.Stdout, pf.Env, pf.Task, pf.Program.{ Program }]
provides [main] to pf
main : Program
main =
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.await
(\letters ->
joinedLetters = Str.joinWith letters " "
Stdout.line "Your favorite letters are: \(joinedLetters)")
|> Program.quick