diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f4b51f50..9a41e845 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,5 +1,5 @@
on:
- pull_request:
+# pull_request:
workflow_dispatch:
# this cancels workflows currently in progress if you start a new one
diff --git a/Cargo.lock b/Cargo.lock
index 67f24e28..074866b7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -64,9 +64,9 @@ checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
[[package]]
name = "cc"
-version = "1.2.6"
+version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
+checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
dependencies = [
"shlex",
]
@@ -376,9 +376,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
-version = "0.2.15"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
@@ -512,7 +512,7 @@ dependencies = [
[[package]]
name = "roc_std"
version = "0.0.1"
-source = "git+https://github.com/roc-lang/roc.git#0ce43ffd1e2f1387370006e1c300fe8ec74343c7"
+source = "git+https://github.com/roc-lang/roc.git#fbf448cac882ed9f81cb68242e0091a75f4f202d"
dependencies = [
"arrayvec",
"static_assertions",
@@ -521,7 +521,7 @@ dependencies = [
[[package]]
name = "roc_std_heap"
version = "0.0.1"
-source = "git+https://github.com/roc-lang/roc.git#0ce43ffd1e2f1387370006e1c300fe8ec74343c7"
+source = "git+https://github.com/roc-lang/roc.git#fbf448cac882ed9f81cb68242e0091a75f4f202d"
dependencies = [
"memmap2",
"roc_std",
@@ -623,9 +623,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.13.0"
+version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5"
+checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
dependencies = [
"core-foundation-sys",
"libc",
diff --git a/build.roc b/build.roc
index 51841c00..d55ca685 100644
--- a/build.roc
+++ b/build.roc
@@ -13,50 +13,47 @@ import cli.Env
## Check basic-cli-build-steps.png for a diagram that shows what the code does.
##
main! : _ => Result {} _
-main! = \_ ->
+main! = \_args ->
- roc_cmd = Env.var! "ROC" |> Result.withDefault "roc"
+ roc_cmd = Env.var!("ROC") |> Result.with_default("roc")
debug_mode =
- when Env.var! "DEBUG" is
- Ok str if !(Str.isEmpty str) -> Debug
+ when Env.var!("DEBUG") is
+ Ok(str) if !(Str.is_empty(str)) -> Debug
_ -> Release
- try roc_version! roc_cmd
+ roc_version!(roc_cmd)?
- os_and_arch = try get_os_and_arch! {}
+ os_and_arch = get_os_and_arch!({})?
- stub_lib_path = "platform/libapp.$(stub_file_extension os_and_arch)"
+ stub_lib_path = "platform/libapp.$(stub_file_extension(os_and_arch))"
- try build_stub_app_lib! roc_cmd stub_lib_path
+ build_stub_app_lib!(roc_cmd, stub_lib_path)?
- try cargo_build_host! debug_mode
+ cargo_build_host!(debug_mode)?
- rust_target_folder = try get_rust_target_folder! debug_mode
+ rust_target_folder = get_rust_target_folder!(debug_mode)?
- try copy_host_lib! os_and_arch rust_target_folder
+ copy_host_lib!(os_and_arch, rust_target_folder)?
- try preprocess_host! roc_cmd stub_lib_path rust_target_folder
+ preprocess_host!(roc_cmd, stub_lib_path, rust_target_folder)?
- try info! "Successfully built platform files!"
+ info!("Successfully built platform files!")?
- Ok {}
+ Ok({})
roc_version! : Str => Result {} _
roc_version! = \roc_cmd ->
- try info! "Checking provided roc; executing `$(roc_cmd) version`:"
+ info!("Checking provided roc; executing `$(roc_cmd) version`:")?
- roc_cmd
- |> Cmd.exec! ["version"]
- |> Result.mapErr RocVersionCheckFailed
+ Cmd.exec!(roc_cmd, ["version"])
+ |> Result.map_err(RocVersionCheckFailed)
get_os_and_arch! : {} => Result OSAndArch _
get_os_and_arch! = \{} ->
- try info! "Getting the native operating system and architecture ..."
+ info!("Getting the native operating system and architecture ...")?
- { os, arch } = Env.platform! {}
-
- convert_os_and_arch!! { os, arch }
+ convert_os_and_arch!(Env.platform!({}))
OSAndArch : [
MacosArm64,
@@ -70,19 +67,18 @@ OSAndArch : [
convert_os_and_arch! : _ => Result OSAndArch _
convert_os_and_arch! = \{ os, arch } ->
when (os, arch) is
- (MACOS, AARCH64) -> Ok MacosArm64
- (MACOS, X64) -> Ok MacosX64
- (LINUX, AARCH64) -> Ok LinuxArm64
- (LINUX, X64) -> Ok LinuxX64
- _ -> Err (UnsupportedNative os arch)
+ (MACOS, AARCH64) -> Ok(MacosArm64)
+ (MACOS, X64) -> Ok(MacosX64)
+ (LINUX, AARCH64) -> Ok(LinuxArm64)
+ (LINUX, X64) -> Ok(LinuxX64)
+ _ -> Err(UnsupportedNative(os, arch))
build_stub_app_lib! : Str, Str => Result {} _
build_stub_app_lib! = \roc_cmd, stub_lib_path ->
- try info! "Building stubbed app shared library ..."
+ info!("Building stubbed app shared library ...")?
- roc_cmd
- |> Cmd.exec! ["build", "--lib", "platform/libapp.roc", "--output", stub_lib_path, "--optimize"]
- |> Result.mapErr ErrBuildingAppStub
+ Cmd.exec!(roc_cmd, ["build", "--lib", "platform/libapp.roc", "--output", stub_lib_path, "--optimize"])
+ |> Result.map_err(ErrBuildingAppStub)
stub_file_extension : OSAndArch -> Str
stub_file_extension = \os_and_arch ->
@@ -106,53 +102,58 @@ get_rust_target_folder! = \debug_mode ->
debug_or_release = if debug_mode == Debug then "debug" else "release"
- when Env.var! "CARGO_BUILD_TARGET" is
- Ok target_env_var ->
- if Str.isEmpty target_env_var then
- Ok "target/$(debug_or_release)/"
+ when Env.var!("CARGO_BUILD_TARGET") is
+ Ok(target_env_var) ->
+ if Str.is_empty(target_env_var) then
+ Ok("target/$(debug_or_release)/")
else
- Ok "target/$(target_env_var)/$(debug_or_release)/"
+ Ok("target/$(target_env_var)/$(debug_or_release)/")
- Err e ->
- try info! "Failed to get env var CARGO_BUILD_TARGET with error $(Inspect.toStr e). Assuming default CARGO_BUILD_TARGET (native)..."
+ Err(e) ->
+ info!("Failed to get env var CARGO_BUILD_TARGET with error $(Inspect.to_str(e)). Assuming default CARGO_BUILD_TARGET (native)...")?
- Ok "target/$(debug_or_release)/"
+ Ok("target/$(debug_or_release)/")
cargo_build_host! : [Debug, Release] => Result {} _
cargo_build_host! = \debug_mode ->
- cargo_build_args =
+
+ cargo_build_args! = \{} ->
when debug_mode is
- Debug -> Result.map (info! "Building rust host in debug mode...") \_ -> ["build"]
- Release -> Result.map (info! "Building rust host ...") \_ -> ["build", "--release"]
+ Debug ->
+ info!("Building rust host in debug mode...")?
+ Ok(["build"])
+
+ Release ->
+ info!("Building rust host ...")?
+ Ok(["build", "--release"])
+
+ args = cargo_build_args!({})?
- "cargo"
- |> Cmd.exec! (try cargo_build_args)
- |> Result.mapErr ErrBuildingHostBinaries
+ Cmd.exec!("cargo", args)
+ |> Result.map_err(ErrBuildingHostBinaries)
copy_host_lib! : OSAndArch, Str => Result {} _
copy_host_lib! = \os_and_arch, rust_target_folder ->
host_build_path = "$(rust_target_folder)libhost.a"
- host_dest_path = "platform/$(prebuilt_static_lib_file os_and_arch)"
+ host_dest_path = "platform/$(prebuilt_static_lib_file(os_and_arch))"
- try info! "Moving the prebuilt binary from $(host_build_path) to $(host_dest_path) ..."
+ info!("Moving the prebuilt binary from $(host_build_path) to $(host_dest_path) ...")?
- "cp"
- |> Cmd.exec! [host_build_path, host_dest_path]
- |> Result.mapErr ErrMovingPrebuiltLegacyBinary
+ Cmd.exec!("cp", [host_build_path, host_dest_path])
+ |> Result.map_err(ErrMovingPrebuiltLegacyBinary)
preprocess_host! : Str, Str, Str => Result {} _
preprocess_host! = \roc_cmd, stub_lib_path, rust_target_folder ->
- try info! "Preprocessing surgical host ..."
+ info!("Preprocessing surgical host ...")?
surgical_build_path = "$(rust_target_folder)host"
- roc_cmd
- |> Cmd.exec! ["preprocess-host", surgical_build_path, "platform/main.roc", stub_lib_path]
- |> Result.mapErr ErrPreprocessingSurgicalBinary
+ Cmd.exec!(roc_cmd, ["preprocess-host", surgical_build_path, "platform/main.roc", stub_lib_path])
+ |> Result.map_err(ErrPreprocessingSurgicalBinary)
info! : Str => Result {} _
info! = \msg ->
- Stdout.line! "\u(001b)[34mINFO:\u(001b)[0m $(msg)"
+ Stdout.line!("\u(001b)[34mINFO:\u(001b)[0m $(msg)")
diff --git a/ci/expect_scripts/http-get-json.exp b/ci/expect_scripts/http-get-json.exp
deleted file mode 100644
index d2af026a..00000000
--- a/ci/expect_scripts/http-get-json.exp
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/expect
-
-# uncomment line below for debugging
-# exp_internal 1
-
-set timeout 7
-
-source ./ci/expect_scripts/shared-code.exp
-
-# Start server to test with in the background and capture its process ID
-set server_pid [exec ./ci/rust_http_server/target/release/rust_http_server &]
-sleep 3
-
-spawn $env(EXAMPLES_DIR)http-get-json
-
-expect "The json I received was: { foo: \"Hello Json!\" }\r\n" {
- exec kill $server_pid
-
- expect eof {
- check_exit_and_segfault
- }
-}
-
-exec kill $server_pid
-
-puts stderr "\nError: output was different from expected value."
-exit 1
diff --git a/ci/rust_http_server/src/main.rs b/ci/rust_http_server/src/main.rs
index 46a5c5ee..207d34c7 100644
--- a/ci/rust_http_server/src/main.rs
+++ b/ci/rust_http_server/src/main.rs
@@ -3,7 +3,6 @@ use hyper::service::{make_service_fn, service_fn};
use std::convert::Infallible;
async fn handle_request(_req: Request
) -> Result, Infallible> {
- // Encode.toBytes {foo: "Hello Json!"} Json.utf8
let json_bytes: Vec = vec![123, 34, 102, 111, 111, 34, 58, 34, 72, 101, 108, 108, 111, 32, 74, 115, 111, 110, 33, 34, 125];
let response = Response::builder()
diff --git a/examples/args.roc b/examples/args.roc
index be3e884b..d10a56fd 100644
--- a/examples/args.roc
+++ b/examples/args.roc
@@ -10,12 +10,12 @@ import pf.Arg exposing [Arg]
main! : List Arg => Result {} _
main! = \raw_args ->
- args = List.map raw_args Arg.display
+ args = List.map(raw_args, Arg.display)
# get the second argument, the first is the executable's path
- when List.get args 1 |> Result.mapErr (\_ -> ZeroArgsGiven) is
- Err ZeroArgsGiven ->
- Err (Exit 1 "Error ZeroArgsGiven:\n\tI expected one argument, but I got none.\n\tRun the app like this: `roc main.roc -- input.txt`")
+ when List.get(args, 1) |> Result.map_err(\_ -> ZeroArgsGiven) is
+ Err(ZeroArgsGiven) ->
+ Err(Exit(1, "Error ZeroArgsGiven:\n\tI expected one argument, but I got none.\n\tRun the app like this: `roc main.roc -- input.txt`"))
- Ok first_arg ->
- Stdout.line! "received argument: $(first_arg)"
+ Ok(first_arg) ->
+ Stdout.line!("received argument: $(first_arg)")
diff --git a/examples/command.roc b/examples/command.roc
index 145ebfa1..0c6af341 100644
--- a/examples/command.roc
+++ b/examples/command.roc
@@ -6,32 +6,32 @@ import pf.Stdout
import pf.Cmd
main! = \_args ->
- try status_example! {}
+ status_example!({})?
- try output_example! {}
+ output_example!({})?
- try exec_example! {}
+ exec_example!({})?
- Ok {}
+ Ok({})
exec_example! : {} => Result {} _
-exec_example! = \{} -> Cmd.exec! "echo" ["EXEC"]
+exec_example! = \{} -> Cmd.exec!("echo", ["EXEC"])
# Run "env" with verbose option, clear all environment variables, and pass in
# "FOO" and "BAZ".
status_example! : {} => Result {} _
status_example! = \{} ->
result =
- Cmd.new "env"
- |> Cmd.arg "-v"
+ Cmd.new("env")
+ |> Cmd.arg("-v")
|> Cmd.clear_envs
- |> Cmd.envs [("FOO", "BAR"), ("BAZ", "DUCK")]
+ |> Cmd.envs([("FOO", "BAR"), ("BAZ", "DUCK")])
|> Cmd.status!
when result is
- Ok exit_code if exit_code == 0 -> Ok {}
- Ok exit_code -> Stdout.line! "Child exited with non-zero code: $(Num.toStr exit_code)"
- Err err -> Stdout.line! "Error executing command: $(Inspect.toStr err)"
+ Ok(exit_code) if exit_code == 0 -> Ok({})
+ Ok(exit_code) -> Stdout.line!("Child exited with non-zero code: $(Num.to_str(exit_code))")
+ Err(err) -> Stdout.line!("Error executing command: $(Inspect.to_str(err))")
# Run "env" with verbose option, clear all environment variables, and pass in
# only as an environment variable "FOO"
@@ -39,12 +39,12 @@ output_example! : {} => Result {} _
output_example! = \{} ->
output =
- Cmd.new "env"
+ Cmd.new("env")
|> Cmd.clear_envs
- |> Cmd.env "FOO" "BAR"
- |> Cmd.args ["-v"]
+ |> Cmd.env("FOO", "BAR")
+ |> Cmd.args(["-v"])
|> Cmd.output!
- msg = Str.fromUtf8 output.stdout |> Result.withDefault "Failed to decode stdout"
+ msg = Str.from_utf8(output.stdout) |> Result.with_default("Failed to decode stdout")
- Stdout.write! msg
+ Stdout.write!(msg)
diff --git a/examples/countdown.roc b/examples/countdown.roc
index 5f16cf9d..1bf45ca4 100644
--- a/examples/countdown.roc
+++ b/examples/countdown.roc
@@ -6,15 +6,15 @@ import pf.Stdin
import pf.Stdout
main! = \_args ->
- try Stdout.line! "\nLet's count down from 3 together - all you have to do is press ."
- _ = Stdin.line! {}
- tick! 3
+ Stdout.line!("\nLet's count down from 3 together - all you have to do is press .")?
+ _ = Stdin.line!({})
+ tick!(3)
tick! = \n ->
if n == 0 then
- try Stdout.line! "🎉 SURPRISE! Happy Birthday! 🎂"
- Ok {}
+ Stdout.line!("🎉 SURPRISE! Happy Birthday! 🎂")?
+ Ok({})
else
- try Stdout.line! (n |> Num.toStr |> \s -> "$(s)...")
- _ = Stdin.line! {}
- tick! (n - 1)
+ Stdout.line!((n |> Num.to_str |> \s -> "$(s)..."))?
+ _ = Stdin.line!({})
+ tick!((n - 1))
diff --git a/examples/dir.roc b/examples/dir.roc
index 34ddcc69..693e73f7 100644
--- a/examples/dir.roc
+++ b/examples/dir.roc
@@ -9,32 +9,34 @@ import pf.Path
main! = \_args ->
# Create a directory
- try Dir.create! "dirExampleE"
+ Dir.create!("dirExampleE")?
# Create a directory and its parents
- try Dir.create_all! "dirExampleA/b/c/child"
+ Dir.create_all!("dirExampleA/b/c/child")?
# Create a child directory
- try Dir.create! "dirExampleA/child"
+ Dir.create!("dirExampleA/child")?
# List the contents of a directory
paths_as_str =
- Dir.list! "dirExampleA"
- |> Result.map \paths -> List.map paths Path.display
+ Dir.list!("dirExampleA")
+ |> Result.map(\paths -> List.map(paths, Path.display))
|> try
# Check the contents of the directory
- expect (Set.fromList paths_as_str) == (Set.fromList ["dirExampleA/b", "dirExampleA/child"])
+ expect (Set.from_list(paths_as_str)) == (Set.from_list(["dirExampleA/b", "dirExampleA/child"]))
# Try to create a directory without a parent (should fail, ignore error)
- when Dir.create! "dirExampleD/child" is
- Ok {} -> {}
- Err _ -> {}
+ when Dir.create!("dirExampleD/child") is
+ Ok({}) -> {}
+ Err(_) -> {}
# Delete an empty directory
- try Dir.delete_empty! "dirExampleE"
+ Dir.delete_empty!("dirExampleE")?
# Delete all directories recursively
- try Dir.delete_all! "dirExampleA"
+ Dir.delete_all!("dirExampleA")?
- Stdout.line! "Success!"
+ Stdout.line!("Success!")?
+
+ Ok({})
diff --git a/examples/echo.roc b/examples/echo.roc
index 5ffd53e8..81ea9eb9 100644
--- a/examples/echo.roc
+++ b/examples/echo.roc
@@ -6,41 +6,42 @@ import pf.Stdin
import pf.Stdout
main! = \_args ->
- try Stdout.line! "Shout into this cave and hear the echo!"
-
- tick! {}
+ Stdout.line!("Shout into this cave and hear the echo!")?
+ tick!({})
tick! : {} => Result {} [StdoutErr _]
tick! = \{} ->
- when Stdin.line! {} is
- Ok str ->
- try Stdout.line! (echo str)
- tick! {}
+ when Stdin.line!({}) is
+ Ok(str) ->
+ Stdout.line!(echo(str))?
+ tick!({})
- Err EndOfFile ->
- try Stdout.line! (echo "Received end of input (EOF).")
- Ok {}
+ Err(EndOfFile) ->
+ Stdout.line!(echo("Received end of input (EOF)."))?
+ Ok({})
- Err (StdinErr err) ->
- try Stdout.line! (echo "Unable to read input $(Inspect.toStr err)")
- Ok {}
+ Err(StdinErr(err)) ->
+ Stdout.line!(echo("Unable to read input $(Inspect.to_str(err))"))?
+ Ok({})
echo : Str -> Str
echo = \shout ->
- silence = \length -> List.repeat ' ' length
+ 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
+ |> Str.to_utf8
+ |> List.map_with_index(
+ \_, i ->
+ length = (List.len(Str.to_utf8(shout)) - i)
+ phrase = (List.split_at(Str.to_utf8(shout), length)).before
+
+ List.concat(silence((if i == 0 then 2 * length else length)), phrase),
+ )
|> List.join
- |> Str.fromUtf8
- |> Result.withDefault ""
+ |> Str.from_utf8
+ |> Result.with_default("")
expect
message = "hello!"
- echoed = echo message
+ echoed = echo(message)
echoed == " hello! hello hell hel he h"
diff --git a/examples/env-var.roc b/examples/env-var.roc
index 0c083790..6dfb2a0f 100644
--- a/examples/env-var.roc
+++ b/examples/env-var.roc
@@ -9,16 +9,16 @@ import pf.Env
main! = \_args ->
- editor = try Env.decode! "EDITOR"
+ editor = Env.decode!("EDITOR")?
- try Stdout.line! "Your favorite editor is $(editor)!"
+ Stdout.line!("Your favorite editor is $(editor)!")?
# Env.decode! does not return the same type everywhere.
# The type is determined based on type inference.
- # Here `Str.joinWith` forces the type that Env.decode! returns to be `List Str`
+ # Here `Str.join_with` forces the type that Env.decode! returns to be `List Str`
joined_letters =
- Env.decode! "LETTERS"
- |> Result.map \letters -> Str.joinWith letters " "
+ Env.decode!("LETTERS")
+ |> Result.map(\letters -> Str.join_with(letters, " "))
|> try
- Stdout.line! "Your favorite letters are: $(joined_letters)"
+ Stdout.line!("Your favorite letters are: $(joined_letters)")
diff --git a/examples/file-mixed.roc b/examples/file-mixed.roc
index 6579cc3f..43197599 100644
--- a/examples/file-mixed.roc
+++ b/examples/file-mixed.roc
@@ -13,36 +13,38 @@ out_txt_path = "out.txt"
task! = \{} ->
- cwd_str = Path.display (try Env.cwd! {})
+ cwd_str = Path.display(Env.cwd!({})?)
- try Stdout.line! "cwd: $(cwd_str)"
+ Stdout.line!("cwd: $(cwd_str)")?
- dir_entries = try Dir.list! cwd_str
+ dir_entries = try(Dir.list!, cwd_str)
- dir_entries_tr = Str.joinWith (List.map dir_entries Path.display) "\n "
+ dir_entries_tr = Str.join_with(List.map(dir_entries, Path.display), "\n ")
- try Stdout.line! "Directory contents:\n $(dir_entries_tr)\n"
+ Stdout.line!("Directory contents:\n $(dir_entries_tr)\n")?
- try Stdout.line! "Writing a string to out.txt"
+ Stdout.line!("Writing a string to out.txt")?
- try File.write_utf8! "a string!" out_txt_path
+ File.write_utf8!("a string!", out_txt_path)?
- contents = try File.read_utf8! out_txt_path
+ contents = File.read_utf8!(out_txt_path)?
- Stdout.line! "I read the file back. Its contents: \"$(contents)\""
+ Stdout.line!("I read the file back. Its contents: \"$(contents)\"")?
+
+ Ok({})
main! = \_args ->
- when task! {} is
- Ok {} -> Stdout.line! "Successfully wrote a string to out.txt"
- Err err ->
+ when 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"
+ FileWriteErr(_, PermissionDenied) -> "PermissionDenied"
+ FileWriteErr(_, Unsupported) -> "Unsupported"
+ FileWriteErr(_, Unrecognized(_, other)) -> other
+ FileReadErr(_, _) -> "Error reading file"
_ -> "Uh oh, there was an error!"
- try Stderr.line! msg
+ Stderr.line!(msg)?
- Err (Exit 1 "unable to write file: $(msg)") # non-zero exit code to indicate failure
+ Err(Exit(1, "unable to write file: $(msg)")) # non-zero exit code to indicate failure
diff --git a/examples/file-read-buffered.roc b/examples/file-read-buffered.roc
index 639b8957..4b288788 100644
--- a/examples/file-read-buffered.roc
+++ b/examples/file-read-buffered.roc
@@ -19,11 +19,11 @@ import pf.File
# See examples/file-read.roc if you want to read the full contents at once.
main! = \_args ->
- reader = try File.open_reader! "LICENSE"
+ reader = File.open_reader!("LICENSE")?
- read_summary = try process_line! reader { lines_read: 0, bytes_read: 0 }
+ read_summary = process_line!(reader, { lines_read: 0, bytes_read: 0 })?
- Stdout.line! "Done reading file: $(Inspect.toStr read_summary)"
+ Stdout.line!("Done reading file: $(Inspect.to_str(read_summary))")
ReadSummary : {
lines_read : U64,
@@ -33,15 +33,18 @@ ReadSummary : {
## Count the number of lines and the number of bytes read.
process_line! : File.Reader, ReadSummary => Result ReadSummary _
process_line! = \reader, { lines_read, bytes_read } ->
- when File.read_line! reader is
- Ok bytes if List.len bytes == 0 ->
- Ok { lines_read, bytes_read }
-
- Ok bytes ->
- process_line! reader {
- lines_read: lines_read + 1,
- bytes_read: bytes_read + (List.len bytes |> Num.intCast),
- }
-
- Err err ->
- Err (ErrorReadingLine (Inspect.toStr err))
+ when File.read_line!(reader) is
+ Ok(bytes) if List.len(bytes) == 0 ->
+ Ok({ lines_read, bytes_read })
+
+ Ok(bytes) ->
+ process_line!(
+ reader,
+ {
+ lines_read: lines_read + 1,
+ bytes_read: bytes_read + (List.len(bytes) |> Num.int_cast),
+ },
+ )
+
+ Err(err) ->
+ Err(ErrorReadingLine(Inspect.to_str(err)))
diff --git a/examples/file-read.roc b/examples/file-read.roc
index 534ebe26..b9f1640a 100644
--- a/examples/file-read.roc
+++ b/examples/file-read.roc
@@ -6,22 +6,22 @@ import pf.Stdout
import pf.File
main! = \_args ->
- when run! {} is
- Ok {} -> Ok {}
- Err err ->
+ when run!({}) is
+ Ok({}) -> Ok({})
+ Err(err) ->
msg =
when err is
- FileWriteErr _ PermissionDenied -> "PermissionDenied"
- FileWriteErr _ Unsupported -> "Unsupported"
- FileWriteErr _ (Unrecognized _ other) -> other
- FileReadErr _ _ -> "Error reading file"
+ FileWriteErr(_, PermissionDenied) -> "PermissionDenied"
+ FileWriteErr(_, Unsupported) -> "Unsupported"
+ FileWriteErr(_, Unrecognized(_, other)) -> other
+ FileReadErr(_, _) -> "Error reading file"
_ -> "Uh oh, there was an error!"
- Err (Exit 1 "unable to read file: $(msg)") # non-zero exit code to indicate failure
+ Err(Exit(1, "unable to read file: $(msg)")) # non-zero exit code to indicate failure
run! = \{} ->
file_name = "LICENSE"
- contents = try File.read_utf8! file_name
- lines = Str.splitOn contents "\n"
+ contents = File.read_utf8!(file_name)?
+ lines = Str.split_on(contents, "\n")
- Stdout.line! (Str.concat "First line of $(file_name): " (List.first lines |> Result.withDefault "err"))
+ Stdout.line!(Str.concat("First line of $(file_name): ", (List.first(lines) |> Result.with_default("err"))))
diff --git a/examples/form.roc b/examples/form.roc
index a6317785..fdcf7b40 100644
--- a/examples/form.roc
+++ b/examples/form.roc
@@ -7,12 +7,12 @@ import pf.Stdout
main! = \_args ->
- try Stdout.line! "What's your first name?"
+ Stdout.line!("What's your first name?")?
- first = try Stdin.line! {}
+ first = Stdin.line!({})?
- try Stdout.line! "What's your last name?"
+ Stdout.line!("What's your last name?")?
- last = try Stdin.line! {}
+ last = Stdin.line!({})?
- Stdout.line! "Hi, $(first) $(last)! đź‘‹"
+ Stdout.line!("Hi, $(first) $(last)! đź‘‹")
diff --git a/examples/hello-world.roc b/examples/hello-world.roc
index eedc9172..816b9992 100644
--- a/examples/hello-world.roc
+++ b/examples/hello-world.roc
@@ -5,4 +5,4 @@ app [main!] { pf: platform "../platform/main.roc" }
import pf.Stdout
main! = \_args ->
- Stdout.line! "Hello, World!"
+ Stdout.line!("Hello, World!")
diff --git a/examples/http-get-json.roc b/examples/http-get-json.roc
deleted file mode 100644
index 7b8fbcba..00000000
--- a/examples/http-get-json.roc
+++ /dev/null
@@ -1,19 +0,0 @@
-app [main!] {
- pf: platform "../platform/main.roc",
- json: "https://github.com/lukewilliamboswell/roc-json/releases/download/0.11.0/z45Wzc-J39TLNweQUoLw3IGZtkQiEN3lTBv3BXErRjQ.tar.br",
-}
-
-# To run this example: check the README.md in this folder
-
-import pf.Http
-import pf.Stdout
-import json.Json
-
-# HTTP GET request with easy decoding to json
-main! = \_args ->
-
- # Easy decoding/deserialization of { "foo": "something" } into a Roc var
- { foo } = try Http.get! "http://localhost:8000" Json.utf8
- # If you want to see an example of the server side, see basic-cli/ci/rust_http_server/src/main.rs
-
- Stdout.line! "The json I received was: { foo: \"$(foo)\" }"
diff --git a/examples/http-get.roc b/examples/http-get.roc
index 812e1fbd..52c56230 100644
--- a/examples/http-get.roc
+++ b/examples/http-get.roc
@@ -8,14 +8,16 @@ import pf.Stdout
main! = \_args ->
- response = Http.send! {
- method: Get,
- headers: [],
- uri: "http://www.example.com",
- body: [],
- timeout_ms: TimeoutMilliseconds 5000,
- }
+ response = Http.send!(
+ {
+ method: GET,
+ headers: [],
+ uri: "http://www.example.com",
+ body: [],
+ timeout_ms: TimeoutMilliseconds(5000),
+ },
+ )
- body = (Str.fromUtf8 response.body)?
+ body = (Str.from_utf8(response.body))?
- Stdout.line! "Response body:\n\t$(body)."
+ Stdout.line!("Response body:\n\t$(body).")
diff --git a/examples/path.roc b/examples/path.roc
index 3eea366b..879942db 100644
--- a/examples/path.roc
+++ b/examples/path.roc
@@ -7,11 +7,11 @@ import pf.Path
main! = \_args ->
- path = Path.from_str "path.roc"
+ path = Path.from_str("path.roc")
- a = try Path.is_file! path
- b = try Path.is_dir! path
- c = try Path.is_sym_link! path
- d = try Path.type! path
+ a = Path.is_file!(path)?
+ b = Path.is_dir!(path)?
+ c = Path.is_sym_link!(path)?
+ d = Path.type!(path)?
- Stdout.line! "isFile: $(Inspect.toStr a) isDir: $(Inspect.toStr b) isSymLink: $(Inspect.toStr c) type: $(Inspect.toStr d)"
+ Stdout.line!("isFile: $(Inspect.to_str(a)) isDir: $(Inspect.to_str(b)) isSymLink: $(Inspect.to_str(c)) type: $(Inspect.to_str(d))")
diff --git a/examples/piping.roc b/examples/piping.roc
index d982efb3..26853ae9 100644
--- a/examples/piping.roc
+++ b/examples/piping.roc
@@ -7,10 +7,10 @@ import pf.Stdin
# Try piping in some text like this: `echo -e "test\n123" | roc piping.roc`
main! = \_args ->
- lines = count! 0
- Stdout.line! "I read $(Num.toStr lines) lines from stdin."
+ lines = count!(0)
+ Stdout.line!("I read $(Num.to_str(lines)) lines from stdin.")
count! = \n ->
- when Stdin.line! {} is
- Ok _ -> count! (n + 1)
- Err _ -> n
+ when Stdin.line!({}) is
+ Ok(_) -> count!((n + 1))
+ Err(_) -> n
diff --git a/examples/record-builder.roc b/examples/record-builder.roc
index cadcac34..77bc4991 100644
--- a/examples/record-builder.roc
+++ b/examples/record-builder.roc
@@ -7,20 +7,19 @@ import pf.Stdout
# To run this example: check the README.md in this folder
main! = \_args ->
- { apples, oranges } = try
- { Result.map2 <-
- apples: get_fruit! Apples |> Result.map join_strs,
- oranges: get_fruit! Oranges |> Result.map join_strs,
- }
+ { apples, oranges } = { Result.map2 <-
+ apples: get_fruit!(Apples) |> Result.map(join_strs),
+ oranges: get_fruit!(Oranges) |> Result.map(join_strs),
+ }?
- Stdout.line! "Apples: $(apples)\nOranges: $(oranges)"
+ Stdout.line!("Apples: $(apples)\nOranges: $(oranges)")
-join_strs = \fruits -> Str.joinWith fruits ", "
+join_strs = \fruits -> Str.join_with(fruits, ", ")
## This doesn't actually perform any effects, but we can imagine that it does
## for the sake of this example, maybe it fetches data from a server or reads a file.
get_fruit! : [Apples, Oranges] => Result (List Str) *
get_fruit! = \request ->
when request is
- Apples -> Ok ["Granny Smith", "Pink Lady", "Golden Delicious"]
- Oranges -> Ok ["Navel", "Blood Orange", "Clementine"]
+ Apples -> Ok(["Granny Smith", "Pink Lady", "Golden Delicious"])
+ Oranges -> Ok(["Navel", "Blood Orange", "Clementine"])
diff --git a/examples/result.roc b/examples/result.roc
index 29e6fd68..e27da51c 100644
--- a/examples/result.roc
+++ b/examples/result.roc
@@ -5,16 +5,16 @@ import pf.Stdout
# To run this example: check the README.md in this folder
main! = \_args ->
- when check_file! "good" is
- Ok Good -> Stdout.line! "GOOD"
- Ok Bad -> Stdout.line! "BAD"
- Err IOError -> Stdout.line! "IOError"
+ when check_file!("good") is
+ Ok(Good) -> Stdout.line!("GOOD")
+ Ok(Bad) -> Stdout.line!("BAD")
+ Err(IOError) -> Stdout.line!("IOError")
check_file! : Str => Result [Good, Bad] [IOError]
check_file! = \str ->
if str == "good" then
- Ok Good
+ Ok(Good)
else if str == "bad" then
- Ok Bad
+ Ok(Bad)
else
- Err IOError
+ Err(IOError)
diff --git a/examples/sqlite.roc b/examples/sqlite.roc
index f014c9f4..d2d43033 100644
--- a/examples/sqlite.roc
+++ b/examples/sqlite.roc
@@ -7,29 +7,38 @@ import pf.Sqlite
# To run this example: check the README.md in this folder
main! = \_args ->
- db_path = try Env.var! "DB_PATH"
+ db_path = Env.var!("DB_PATH")?
- todo = try query_todos_by_status! db_path "todo"
+ todo = query_todos_by_status!(db_path, "todo")?
- try Stdout.line! "Todo Tasks:"
- try List.forEachTry! todo \{ id, task } ->
- Stdout.line! "\tid: $(id), task: $(task)"
+ Stdout.line!("Todo Tasks:")?
+ List.for_each_try!(
+ todo,
+ \{ id, task } ->
+ Stdout.line!("\tid: $(id), task: $(task)"),
+ )?
- completed = try query_todos_by_status! db_path "completed"
+ completed = query_todos_by_status!(db_path, "completed")?
- try Stdout.line! "\nCompleted Tasks:"
- try List.forEachTry! completed \{ id, task } ->
- Stdout.line! "\tid: $(id), task: $(task)"
+ Stdout.line!("\nCompleted Tasks:")?
- Ok {}
+ List.for_each_try!(
+ completed,
+ \{ id, task } ->
+ Stdout.line!("\tid: $(id), task: $(task)"),
+ )?
+
+ Ok({})
query_todos_by_status! = \db_path, status ->
- Sqlite.query_many! {
- path: db_path,
- query: "SELECT id, task FROM todos WHERE status = :status;",
- bindings: [{ name: ":status", value: String status }],
- rows: { Sqlite.decode_record <-
- id: Sqlite.i64 "id" |> Sqlite.map_value Num.toStr,
- task: Sqlite.str "task",
+ Sqlite.query_many!(
+ {
+ path: db_path,
+ query: "SELECT id, task FROM todos WHERE status = :status;",
+ bindings: [{ name: ":status", value: String(status) }],
+ rows: { Sqlite.decode_record <-
+ id: Sqlite.i64("id") |> Sqlite.map_value(Num.to_str),
+ task: Sqlite.str("task"),
+ },
},
- }
+ )
diff --git a/examples/stdin.roc b/examples/stdin.roc
index bb1cfe56..76bc2a95 100644
--- a/examples/stdin.roc
+++ b/examples/stdin.roc
@@ -7,29 +7,33 @@ import pf.Stdin
# To run this example: check the README.md in this folder
main! = \_args ->
- try Stdout.line! "Enter a series of number characters (0-9):"
+ Stdout.line!("Enter a series of number characters (0-9):")?
- number_bytes = try take_number_bytes! {}
+ number_bytes = take_number_bytes!({})?
- if List.isEmpty number_bytes then
- Stderr.line! "Expected a series of number characters (0-9)"
+ if List.is_empty(number_bytes) then
+ Stderr.line!("Expected a series of number characters (0-9)")
else
- when Str.fromUtf8 number_bytes is
- Ok n_str ->
- Stdout.line! "Got number $(n_str)"
+ when Str.from_utf8(number_bytes) is
+ Ok(n_str) ->
+ Stdout.line!("Got number $(n_str)")
- Err _ ->
- Stderr.line! "Error, bad utf8"
+ Err(_) ->
+ Stderr.line!("Error, bad utf8")
take_number_bytes! : {} => Result (List U8) _
take_number_bytes! = \{} ->
- bytes_read = try Stdin.bytes! {}
+ bytes_read = Stdin.bytes!({})?
number_bytes =
- List.walk bytes_read [] \bytes, b ->
- if b >= '0' && b <= '9' then
- List.append bytes b
- else
- bytes
-
- Ok number_bytes
+ List.walk(
+ bytes_read,
+ [],
+ \bytes, b ->
+ if b >= '0' && b <= '9' then
+ List.append(bytes, b)
+ else
+ bytes,
+ )
+
+ Ok(number_bytes)
diff --git a/examples/task-list.roc b/examples/task-list.roc
index 31af2b1c..22c341e5 100644
--- a/examples/task-list.roc
+++ b/examples/task-list.roc
@@ -6,12 +6,12 @@ import pf.Stdout
main! = \_args ->
# Prints out each of the authors
- print! ["Foo", "Bar", "Baz"]
+ print!(["Foo", "Bar", "Baz"])
print! : List Str => Result {} _
print! = \authors ->
when authors is
- [] -> Ok {}
+ [] -> Ok({})
[author, .. as rest] ->
- try Stdout.line! author
- print! rest
+ Stdout.line!(author)?
+ print!(rest)
diff --git a/examples/tcp-client.roc b/examples/tcp-client.roc
index 1e5830cd..27cb8de3 100644
--- a/examples/tcp-client.roc
+++ b/examples/tcp-client.roc
@@ -8,16 +8,16 @@ import pf.Stderr
# To run this example: check the README.md in this folder
main! = \_args ->
- when run! {} is
- Ok {} -> Ok {}
- Err err -> handle_err! err
+ when run!({}) is
+ Ok({}) -> Ok({})
+ Err(err) -> handle_err!(err)
handle_err! : []_ => Result {} _
handle_err! = \error ->
when error is
- TcpConnectErr err ->
- err_str = Tcp.connect_err_to_str err
- Stderr.line!
+ TcpConnectErr(err) ->
+ err_str = Tcp.connect_err_to_str(err)
+ Stderr.line!(
"""
Failed to connect: $(err_str)
@@ -26,46 +26,49 @@ handle_err! = \error ->
If you want an echo server you can run:
$ ncat -e \$(which cat) -l 8085
- """
+ """,
+ )
- TcpReadBadUtf8 _ ->
- Stderr.line! "Received invalid UTF-8 data"
+ TcpReadBadUtf8(_) ->
+ Stderr.line!("Received invalid UTF-8 data")
- TcpReadErr err ->
- err_str = Tcp.stream_err_to_str err
- Stderr.line! "Error while reading: $(err_str)"
+ TcpReadErr(err) ->
+ err_str = Tcp.stream_err_to_str(err)
+ Stderr.line!("Error while reading: $(err_str)")
- TcpWriteErr err ->
- err_str = Tcp.stream_err_to_str err
- Stderr.line! "Error while writing: $(err_str)"
+ TcpWriteErr(err) ->
+ err_str = Tcp.stream_err_to_str(err)
+ Stderr.line!("Error while writing: $(err_str)")
- other -> Stderr.line! "Got other error: $(Inspect.toStr other)"
+ other -> Stderr.line!("Got other error: $(Inspect.to_str(other))")
run! : {} => Result {} _
run! = \{} ->
- stream = try Tcp.connect! "127.0.0.1" 8085
+ stream = Tcp.connect!("127.0.0.1", 8085)?
- try Stdout.line! "Connected!"
+ Stdout.line!("Connected!")?
- loop! {} \_ ->
- Result.map (tick! stream) Step
+ loop!(
+ {},
+ \_ -> Result.map(tick!(stream), Step),
+ )
tick! : Tcp.Stream => Result {} _
tick! = \stream ->
- try Stdout.write! "> "
+ Stdout.write!("> ")?
- out_msg = try Stdin.line! {}
+ out_msg = Stdin.line!({})?
- try Tcp.write_utf8! stream "$(out_msg)\n"
+ Tcp.write_utf8!(stream, "$(out_msg)\n")?
- in_msg = try Tcp.read_line! stream
+ in_msg = Tcp.read_line!(stream)?
- Stdout.line! "< $(in_msg)"
+ Stdout.line!("< $(in_msg)")
loop! : state, (state => Result [Step state, Done done] err) => Result done err
loop! = \state, fn! ->
- when fn! state is
- Err err -> Err err
- Ok (Done done) -> Ok done
- Ok (Step next) -> loop! next fn!
+ when fn!(state) is
+ Err(err) -> Err(err)
+ Ok(Done(done)) -> Ok(done)
+ Ok(Step(next)) -> loop!(next, fn!)
diff --git a/examples/temp-dir.roc b/examples/temp-dir.roc
index 4ce96fa4..d7ab3fff 100644
--- a/examples/temp-dir.roc
+++ b/examples/temp-dir.roc
@@ -12,7 +12,7 @@ import pf.Path
## for example: `roc build examples/temp-dir.roc --linker=legacy`
main! = \_args ->
- temp_dir_str = Path.display (Env.temp_dir! {})
+ temp_dir_str = Path.display(Env.temp_dir!({}))
- Stdout.line! "The temp dir path is $(temp_dir_str)"
- |> Result.mapErr \err -> Exit 1 "Failed to print temp dir:\n\t$(Inspect.toStr err)"
+ Stdout.line!("The temp dir path is $(temp_dir_str)")
+ |> Result.map_err(\err -> Exit(1, "Failed to print temp dir:\n\t$(Inspect.to_str(err))"))
diff --git a/examples/time.roc b/examples/time.roc
index b12f39db..5577fea1 100644
--- a/examples/time.roc
+++ b/examples/time.roc
@@ -7,12 +7,12 @@ import pf.Sleep
# To run this example: check the README.md in this folder
main! = \_args ->
- start = Utc.now! {}
+ start = Utc.now!({})
- Sleep.millis! 1500
+ Sleep.millis!(1500)
- finish = Utc.now! {}
+ finish = Utc.now!({})
- duration = Num.toStr (Utc.delta_as_nanos start finish)
+ duration = Num.to_str(Utc.delta_as_nanos(start, finish))
- Stdout.line! "Completed in $(duration)ns"
+ Stdout.line!("Completed in $(duration)ns")
diff --git a/flake.lock b/flake.lock
index 077bd9fb..0990e2a4 100644
--- a/flake.lock
+++ b/flake.lock
@@ -102,11 +102,11 @@
"rust-overlay": "rust-overlay"
},
"locked": {
- "lastModified": 1734960752,
- "narHash": "sha256-QVcT/lUgDRoBccvaZqIAefNInrN6bSuqUJNs9cfjKLY=",
+ "lastModified": 1736378239,
+ "narHash": "sha256-J7/bHTiRAefX/czxRkTbik/iMaJDL5ZmTnMfXJE+/nY=",
"owner": "roc-lang",
"repo": "roc",
- "rev": "a58b1013e756749da5c35431efde834a70a29717",
+ "rev": "fbf448cac882ed9f81cb68242e0091a75f4f202d",
"type": "github"
},
"original": {
@@ -154,11 +154,11 @@
]
},
"locked": {
- "lastModified": 1734834660,
- "narHash": "sha256-bm8V+Cu8rWJA+vKQnc94mXTpSDgvedyoDKxTVi/uJfw=",
+ "lastModified": 1736303309,
+ "narHash": "sha256-IKrk7RL+Q/2NC6+Ql6dwwCNZI6T6JH2grTdJaVWHF0A=",
"owner": "oxalica",
"repo": "rust-overlay",
- "rev": "b070e6030118680977bc2388868c4b3963872134",
+ "rev": "a0b81d4fa349d9af1765b0f0b4a899c13776f706",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index c3195b8f..f9dd5e4e 100644
--- a/flake.nix
+++ b/flake.nix
@@ -2,6 +2,7 @@
description = "Basic cli devShell flake";
inputs = {
+
roc.url = "github:roc-lang/roc";
nixpkgs.follows = "roc/nixpkgs";
diff --git a/platform/Arg.roc b/platform/Arg.roc
index eacbabda..9ebbeb7e 100644
--- a/platform/Arg.roc
+++ b/platform/Arg.roc
@@ -15,22 +15,22 @@ module [
## encoding for you, but for quick-and-dirty code you can use [display] to
## convert these to [Str] in a lossy way.
Arg := [Unix (List U8), Windows (List U16)]
- implements [Eq, Inspect { toInspector: arg_inspector }]
+ implements [Eq, Inspect { to_inspector: arg_inspector }]
arg_inspector : Arg -> Inspector f where f implements InspectFormatter
-arg_inspector = \arg -> Inspect.str (display arg)
+arg_inspector = \arg -> Inspect.str(display(arg))
test_hello : Arg
-test_hello = Arg.from_os_raw (Unix [72, 101, 108, 108, 111])
+test_hello = Arg.from_os_raw(Unix([72, 101, 108, 108, 111]))
-expect Arg.display test_hello == "Hello"
-expect Inspect.toStr test_hello == "\"Hello\""
+expect Arg.display(test_hello) == "Hello"
+expect Inspect.to_str(test_hello) == "\"Hello\""
## Unwrap an [Arg] into a raw, OS-aware numeric list.
##
## This is a good way to pass [Arg]s to Roc packages.
to_os_raw : Arg -> [Unix (List U8), Windows (List U16)]
-to_os_raw = \@Arg inner -> inner
+to_os_raw = \@Arg(inner) -> inner
## Wrap a raw, OS-aware numeric list into an [Arg].
from_os_raw : [Unix (List U8), Windows (List U16)] -> Arg
@@ -40,16 +40,16 @@ from_os_raw = @Arg
##
## NB: this will currently crash if there is invalid utf8 bytes, in future this will be lossy and replace any invalid bytes with the [Unicode Replacement Character U+FFFD ďż˝](https://en.wikipedia.org/wiki/Specials_(Unicode_block))
display : Arg -> Str
-display = \@Arg inner ->
+display = \@Arg(inner) ->
when inner is
- Unix bytes ->
+ Unix(bytes) ->
# TODO replace with Str.from_utf8_lossy : List U8 -> Str
# see https://github.com/roc-lang/roc/issues/7390
- when Str.fromUtf8 bytes is
- Ok str -> str
- Err _ -> crash "tried to display Arg containing invalid utf-8"
+ when Str.from_utf8(bytes) is
+ Ok(str) -> str
+ Err(_) -> crash("tried to display Arg containing invalid utf-8")
- Windows _ ->
+ Windows(_) ->
# TODO replace with Str.from_utf16_lossy : List U16 -> Str
# see https://github.com/roc-lang/roc/issues/7390
- crash "display for utf-16 Arg not yet supported"
+ crash("display for utf-16 Arg not yet supported")
diff --git a/platform/Cmd.roc b/platform/Cmd.roc
index 109cd66d..c79e30cc 100644
--- a/platform/Cmd.roc
+++ b/platform/Cmd.roc
@@ -25,77 +25,79 @@ Output : InternalCmd.Output
## Create a new command to execute the given program in a child process.
new : Str -> Cmd
new = \program ->
- @Cmd {
- program,
- args: [],
- envs: [],
- clear_envs: Bool.false,
- }
+ @Cmd(
+ {
+ program,
+ args: [],
+ envs: [],
+ clear_envs: Bool.false,
+ },
+ )
## Add a single argument to the command.
## ! Shell features like variable subsitition (e.g. `$FOO`), glob patterns (e.g. `*.txt`), ... are not available.
##
## ```
## # Represent the command "ls -l"
-## Cmd.new "ls"
-## |> Cmd.arg "-l"
+## Cmd.new("ls")
+## |> Cmd.arg("-l")
## ```
##
arg : Cmd, Str -> Cmd
-arg = \@Cmd cmd, value ->
- @Cmd ({ cmd & args: List.append cmd.args value })
+arg = \@Cmd(cmd), value ->
+ @Cmd({ cmd & args: List.append(cmd.args, value) })
## Add multiple arguments to the command.
## ! Shell features like variable subsitition (e.g. `$FOO`), glob patterns (e.g. `*.txt`), ... are not available.
##
## ```
## # Represent the command "ls -l -a"
-## Cmd.new "ls"
-## |> Cmd.args ["-l", "-a"]
+## Cmd.new("ls")
+## |> Cmd.args(["-l", "-a"])
## ```
##
args : Cmd, List Str -> Cmd
-args = \@Cmd cmd, values ->
- @Cmd ({ cmd & args: List.concat cmd.args values })
+args = \@Cmd(cmd), values ->
+ @Cmd({ cmd & args: List.concat(cmd.args, values) })
## Add a single environment variable to the command.
##
## ```
## # Run "env" and add the environment variable "FOO" with value "BAR"
-## Cmd.new "env"
-## |> Cmd.env "FOO" "BAR"
+## Cmd.new("env")
+## |> Cmd.env("FOO", "BAR")
## ```
##
env : Cmd, Str, Str -> Cmd
-env = \@Cmd cmd, key, value ->
- @Cmd ({ cmd & envs: List.concat cmd.envs [key, value] })
+env = \@Cmd(cmd), key, value ->
+ @Cmd({ cmd & envs: List.concat(cmd.envs, [key, value]) })
## Add multiple environment variables to the command.
##
## ```
## # Run "env" and add the variables "FOO" and "BAZ"
-## Cmd.new "env"
-## |> Cmd.envs [("FOO", "BAR"), ("BAZ", "DUCK")]
+## Cmd.new("env")
+## |> Cmd.envs([("FOO", "BAR"), ("BAZ", "DUCK")])
## ```
##
envs : Cmd, List (Str, Str) -> Cmd
-envs = \@Cmd cmd, key_values ->
- values = key_values |> List.joinMap \(key, value) -> [key, value]
- @Cmd { cmd & envs: List.concat cmd.envs values }
+envs = \@Cmd(cmd), key_values ->
+ values = key_values |> List.join_map(\(key, value) -> [key, value])
+ @Cmd({ cmd & envs: List.concat(cmd.envs, values) })
## Clear all environment variables, and prevent inheriting from parent, only
## the environment variables provided to command are available to the child.
##
## ```
## # Represents "env" with only "FOO" environment variable set
-## Cmd.new "env"
+## Cmd.new("env")
## |> Cmd.clear_envs
-## |> Cmd.env "FOO" "BAR"
+## |> Cmd.env("FOO", "BAR")
## ```
##
clear_envs : Cmd -> Cmd
-clear_envs = \@Cmd cmd ->
- @Cmd { cmd & clear_envs: Bool.true }
+clear_envs = \@Cmd(cmd) ->
+ @Cmd({ cmd & clear_envs: Bool.true })
## Execute command and capture stdout and stderr
##
@@ -103,32 +105,32 @@ clear_envs = \@Cmd cmd ->
## > to read from the stdin stream will result in the stream immediately closing.
##
output! : Cmd => Output
-output! = \@Cmd cmd ->
- Host.command_output! cmd
+output! = \@Cmd(cmd) ->
+ Host.command_output!(cmd)
|> InternalCmd.from_host_output
## Execute command and inherit stdin, stdout and stderr from parent
##
status! : Cmd => Result I32 [CmdStatusErr InternalIOErr.IOErr]
-status! = \@Cmd cmd ->
- Host.command_status! cmd
- |> Result.mapErr InternalIOErr.handle_err
- |> Result.mapErr CmdStatusErr
+status! = \@Cmd(cmd) ->
+ Host.command_status!(cmd)
+ |> Result.map_err(InternalIOErr.handle_err)
+ |> Result.map_err(CmdStatusErr)
## Execute command and inherit stdin, stdout and stderr from parent
##
## ```
## # Call echo to print "hello world"
-## Cmd.exec! "echo" ["hello world"]
+## Cmd.exec!("echo", ["hello world"])
## ```
exec! : Str, List Str => Result {} [CmdStatusErr InternalIOErr.IOErr]
exec! = \program, arguments ->
exit_code =
- new program
- |> args arguments
+ new(program)
+ |> args(arguments)
|> status!?
if exit_code == 0i32 then
- Ok {}
+ Ok({})
else
- Err (CmdStatusErr (Other "Non-zero exit code $(Num.toStr exit_code)"))
+ Err(CmdStatusErr(Other("Non-zero exit code $(Num.to_str(exit_code))")))
diff --git a/platform/Dir.roc b/platform/Dir.roc
index 5fd9a9be..14e6411e 100644
--- a/platform/Dir.roc
+++ b/platform/Dir.roc
@@ -26,7 +26,7 @@ DirEntry : Path.DirEntry
## > [Path.list_dir!] does the same thing, except it takes a [Path] instead of a [Str].
list! : Str => Result (List Path) [DirErr IOErr]
list! = \path ->
- Path.list_dir! (Path.from_str path)
+ Path.list_dir!(Path.from_str(path))
## Deletes a directory if it's empty
##
@@ -39,7 +39,7 @@ list! = \path ->
## > [Path.delete_empty!] does the same thing, except it takes a [Path] instead of a [Str].
delete_empty! : Str => Result {} [DirErr IOErr]
delete_empty! = \path ->
- Path.delete_empty! (Path.from_str path)
+ Path.delete_empty!(Path.from_str(path))
## Recursively deletes the directory as well as all files and directories
## inside it.
@@ -53,7 +53,7 @@ delete_empty! = \path ->
## > [Path.delete_all!] does the same thing, except it takes a [Path] instead of a [Str].
delete_all! : Str => Result {} [DirErr IOErr]
delete_all! = \path ->
- Path.delete_all! (Path.from_str path)
+ Path.delete_all!(Path.from_str(path))
## Creates a directory
##
@@ -65,7 +65,7 @@ delete_all! = \path ->
## > [Path.create_dir!] does the same thing, except it takes a [Path] instead of a [Str].
create! : Str => Result {} [DirErr IOErr]
create! = \path ->
- Path.create_dir! (Path.from_str path)
+ Path.create_dir!(Path.from_str(path))
## Creates a directory recursively adding any missing parent directories.
##
@@ -76,4 +76,4 @@ create! = \path ->
## > [Path.create_all!] does the same thing, except it takes a [Path] instead of a [Str].
create_all! : Str => Result {} [DirErr IOErr]
create_all! = \path ->
- Path.create_all! (Path.from_str path)
+ Path.create_all!(Path.from_str(path))
diff --git a/platform/Env.roc b/platform/Env.roc
index 14c015f2..01d3a2be 100644
--- a/platform/Env.roc
+++ b/platform/Env.roc
@@ -18,27 +18,27 @@ import Host
## from the environment. File operations on relative [Path]s are relative to this directory.
cwd! : {} => Result Path [CwdUnavailable]
cwd! = \{} ->
- bytes = Host.cwd! {} |> Result.withDefault []
+ bytes = Host.cwd!({}) |> Result.with_default([])
- if List.isEmpty bytes then
- Err CwdUnavailable
+ if List.is_empty(bytes) then
+ Err(CwdUnavailable)
else
- Ok (InternalPath.from_arbitrary_bytes bytes)
+ Ok(InternalPath.from_arbitrary_bytes(bytes))
## Sets the [current working directory](https://en.wikipedia.org/wiki/Working_directory)
## in the environment. After changing it, file operations on relative [Path]s will be relative
## to this directory.
set_cwd! : Path => Result {} [InvalidCwd]
set_cwd! = \path ->
- Host.set_cwd! (InternalPath.to_bytes path)
- |> Result.mapErr \{} -> InvalidCwd
+ Host.set_cwd!(InternalPath.to_bytes(path))
+ |> Result.map_err(\{} -> InvalidCwd)
## Gets the path to the currently-running executable.
exe_path! : {} => Result Path [ExePathUnavailable]
exe_path! = \{} ->
- when Host.exe_path! {} is
- Ok bytes -> Ok (InternalPath.from_os_bytes bytes)
- Err {} -> Err ExePathUnavailable
+ when Host.exe_path!({}) is
+ Ok(bytes) -> Ok(InternalPath.from_os_bytes(bytes))
+ Err({}) -> Err(ExePathUnavailable)
## Reads the given environment variable.
##
@@ -46,8 +46,8 @@ exe_path! = \{} ->
## [Unicode replacement character](https://unicode.org/glossary/#replacement_character) ('ďż˝').
var! : Str => Result Str [VarNotFound]
var! = \name ->
- Host.env_var! name
- |> Result.mapErr \{} -> VarNotFound
+ Host.env_var!(name)
+ |> Result.map_err(\{} -> VarNotFound)
## Reads the given environment variable and attempts to decode it.
##
@@ -66,7 +66,7 @@ var! = \name ->
## ```
## # Reads "NUM_THINGS" and decodes into a U16
## get_u16_var! : Str => Result U16 [VarNotFound, DecodeErr DecodeError] [Read [Env]]
-## get_u16_var! = \var -> Env.decode! var
+## get_u16_var! = \var -> Env.decode!(var)
## ```
##
## If `NUM_THINGS=123` then `getU16Var` succeeds with the value of `123u16`.
@@ -76,12 +76,12 @@ var! = \name ->
##
decode! : Str => Result val [VarNotFound, DecodeErr DecodeError] where val implements Decoding
decode! = \name ->
- when Host.env_var! name is
- Err {} -> Err VarNotFound
- Ok var_str ->
- Str.toUtf8 var_str
- |> Decode.fromBytes (EnvDecoding.format {})
- |> Result.mapErr (\_ -> DecodeErr TooShort)
+ when Host.env_var!(name) is
+ Err({}) -> Err(VarNotFound)
+ Ok(var_str) ->
+ Str.to_utf8(var_str)
+ |> Decode.from_bytes(EnvDecoding.format({}))
+ |> Result.map_err(\_ -> DecodeErr(TooShort))
## Reads all the process's environment variables into a [Dict].
##
@@ -89,8 +89,8 @@ decode! = \name ->
## will be used in place of any parts of keys or values that are invalid Unicode.
dict! : {} => Dict Str Str
dict! = \{} ->
- Host.env_dict! {}
- |> Dict.fromList
+ Host.env_dict!({})
+ |> Dict.from_list
# ## Walks over the process's environment variables as key-value arguments to the walking function.
# ##
@@ -137,7 +137,7 @@ OS : [LINUX, MACOS, WINDOWS, OTHER Str]
platform! : {} => { arch : ARCH, os : OS }
platform! = \{} ->
- from_rust = Host.current_arch_os! {}
+ from_rust = Host.current_arch_os!({})
arch =
when from_rust.arch is
@@ -145,14 +145,14 @@ platform! = \{} ->
"x86_64" -> X64
"arm" -> ARM
"aarch64" -> AARCH64
- _ -> OTHER from_rust.arch
+ _ -> OTHER(from_rust.arch)
os =
when from_rust.os is
"linux" -> LINUX
"macos" -> MACOS
"windows" -> WINDOWS
- _ -> OTHER from_rust.os
+ _ -> OTHER(from_rust.os)
{ arch, os }
@@ -167,5 +167,5 @@ platform! = \{} ->
##
temp_dir! : {} => Path
temp_dir! = \{} ->
- Host.temp_dir! {}
+ Host.temp_dir!({})
|> InternalPath.from_os_bytes
diff --git a/platform/EnvDecoding.roc b/platform/EnvDecoding.roc
index 0ca77b55..2b819e9a 100644
--- a/platform/EnvDecoding.roc
+++ b/platform/EnvDecoding.roc
@@ -27,82 +27,95 @@ EnvFormat := {} implements [
]
format : {} -> EnvFormat
-format = \{} -> @EnvFormat {}
+format = \{} -> @EnvFormat({})
decode_bytes_to_num = \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 }
+ when Str.from_utf8(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 }
+ Err(_) -> { result: Err(TooShort), rest: bytes }
-env_u8 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toU8
-env_u16 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toU16
-env_u32 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toU32
-env_u64 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toU64
-env_u128 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toU128
-env_i8 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toI8
-env_i16 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toI16
-env_i32 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toI32
-env_i64 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toI64
-env_i128 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toI128
-env_f32 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toF32
-env_f64 = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toF64
-env_dec = Decode.custom \bytes, @EnvFormat {} -> decode_bytes_to_num bytes Str.toDec
+env_u8 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_u8))
+env_u16 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_u16))
+env_u32 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_u32))
+env_u64 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_u64))
+env_u128 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_u128))
+env_i8 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_i8))
+env_i16 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_i16))
+env_i32 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_i32))
+env_i64 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_i64))
+env_i128 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_i128))
+env_f32 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_f32))
+env_f64 = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_f64))
+env_dec = Decode.custom(\bytes, @EnvFormat({}) -> decode_bytes_to_num(bytes, Str.to_dec))
-env_bool = 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 }
+env_bool = Decode.custom(
+ \bytes, @EnvFormat({}) ->
+ when Str.from_utf8(bytes) is
+ Ok("true") -> { result: Ok(Bool.true), rest: [] }
+ Ok("false") -> { result: Ok(Bool.false), rest: [] }
+ _ -> { result: Err(TooShort), rest: bytes },
+)
-env_string = Decode.custom \bytes, @EnvFormat {} ->
- when Str.fromUtf8 bytes is
- Ok s -> { result: Ok s, rest: [] }
- Err _ -> { result: Err TooShort, rest: bytes }
+env_string = Decode.custom(
+ \bytes, @EnvFormat({}) ->
+ when Str.from_utf8(bytes) is
+ Ok(s) -> { result: Ok(s), rest: [] }
+ Err(_) -> { result: Err(TooShort), rest: bytes },
+)
-env_list = \decode_elem -> 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.
- decode_elems = \all_bytes, accum ->
- { to_parse, remainder } =
- when List.splitFirst all_bytes (Num.toU8 ',') is
- Ok { before, after } ->
- { to_parse: before, remainder: Some after }
+env_list = \decode_elem ->
+ 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.
+ decode_elems = \all_bytes, accum ->
+ { to_parse, remainder } =
+ when List.split_first(all_bytes, Num.to_u8(',')) is
+ Ok({ before, after }) ->
+ { to_parse: before, remainder: Some(after) }
- Err NotFound ->
- { to_parse: all_bytes, remainder: None }
+ Err(NotFound) ->
+ { to_parse: all_bytes, remainder: None }
- when Decode.decodeWith to_parse decode_elem (@EnvFormat {}) is
- { result, rest } ->
- when result is
- Ok val ->
- when remainder is
- Some rest_bytes -> decode_elems rest_bytes (List.append accum val)
- None -> Done (List.append accum val)
+ when Decode.decode_with(to_parse, decode_elem, @EnvFormat({})) is
+ { result, rest } ->
+ when result is
+ Ok(val) ->
+ when remainder is
+ Some(rest_bytes) -> decode_elems(rest_bytes, List.append(accum, val))
+ None -> Done(List.append(accum, val))
- Err e -> Errored e rest
+ Err(e) -> Errored(e, rest)
- when decode_elems bytes [] is
- Errored e rest -> { result: Err e, rest }
- Done vals ->
- { result: Ok vals, rest: [] }
+ when decode_elems(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.
env_record : _, (_, _ -> [Keep (Decoder _ _), Skip]), (_, _ -> _) -> Decoder _ _
-env_record = \_initialState, _stepField, _finalizer -> Decode.custom \bytes, @EnvFormat {} ->
- { result: Err TooShort, rest: bytes }
+env_record = \_initialState, _stepField, _finalizer ->
+ Decode.custom(
+ \bytes, @EnvFormat({}) ->
+ { result: Err(TooShort), rest: bytes },
+ )
# 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.
env_tuple : _, (_, _ -> [Next (Decoder _ _), TooLong]), (_ -> _) -> Decoder _ _
-env_tuple = \_initialState, _stepElem, _finalizer -> Decode.custom \bytes, @EnvFormat {} ->
- { result: Err TooShort, rest: bytes }
+env_tuple = \_initialState, _stepElem, _finalizer ->
+ Decode.custom(
+ \bytes, @EnvFormat({}) ->
+ { result: Err(TooShort), rest: bytes },
+ )
diff --git a/platform/File.roc b/platform/File.roc
index 32900cff..d4d42f1d 100644
--- a/platform/File.roc
+++ b/platform/File.roc
@@ -44,17 +44,18 @@ IOErr : InternalIOErr.IOErr
##
## First encode a `val` using a given `fmt` which implements the ability [Encode.EncoderFormatting](https://www.roc-lang.org/builtins/Encode#EncoderFormatting).
##
-## For example, suppose you have a `Json.toCompactUtf8` which implements
+## For example, suppose you have a `Json.to_compact_utf8` which implements
## [Encode.EncoderFormatting](https://www.roc-lang.org/builtins/Encode#EncoderFormatting).
## You can use this to write [JSON](https://en.wikipedia.org/wiki/JSON)
## data to a file like this:
##
## ```
## # Writes `{"some":"json stuff"}` to the file `output.json`:
-## File.write!
-## { some: "json stuff" }
-## (Path.from_str "output.json")
-## Json.toCompactUtf8
+## File.write!(
+## { some: "json stuff" },
+## Path.from_str("output.json"),
+## Json.to_compact_utf8,
+## )
## ```
##
## This opens the file first and closes it after writing to it.
@@ -65,13 +66,13 @@ IOErr : InternalIOErr.IOErr
## > [Path.write!] does the same thing, except it takes a [Path] instead of a [Str].
write! : val, Str, fmt => Result {} [FileWriteErr Path IOErr] where val implements Encoding, fmt implements EncoderFormatting
write! = \val, path, fmt ->
- Path.write! val (Path.from_str path) fmt
+ Path.write!(val, Path.from_str(path), fmt)
## Writes bytes to a file.
##
## ```
## # Writes the bytes 1, 2, 3 to the file `myfile.dat`.
-## File.write_bytes! [1, 2, 3] (Path.from_str "myfile.dat")
+## File.write_bytes!([1, 2, 3], Path.from_str("myfile.dat"))?
## ```
##
## This opens the file first and closes it after writing to it.
@@ -81,13 +82,13 @@ write! = \val, path, fmt ->
## > [Path.write_bytes!] does the same thing, except it takes a [Path] instead of a [Str].
write_bytes! : List U8, Str => Result {} [FileWriteErr Path IOErr]
write_bytes! = \bytes, path ->
- Path.write_bytes! bytes (Path.from_str path)
+ Path.write_bytes!(bytes, Path.from_str(path))
## Writes a [Str] to a file, encoded as [UTF-8](https://en.wikipedia.org/wiki/UTF-8).
##
## ```
## # Writes "Hello!" encoded as UTF-8 to the file `myfile.txt`.
-## File.write_utf8! "Hello!" "myfile.txt"
+## File.write_utf8!("Hello!", "myfile.txt")?
## ```
##
## This opens the file first and closes it after writing to it.
@@ -97,7 +98,7 @@ write_bytes! = \bytes, path ->
## > [Path.write_utf8!] does the same thing, except it takes a [Path] instead of a [Str].
write_utf8! : Str, Str => Result {} [FileWriteErr Path IOErr]
write_utf8! = \str, path ->
- Path.write_utf8! str (Path.from_str path)
+ Path.write_utf8!(str, Path.from_str(path))
## Deletes a file from the filesystem.
##
@@ -109,7 +110,7 @@ write_utf8! = \str, path ->
##
## ```
## # Deletes the file named `myfile.dat`
-## File.delete! (Path.from_str "myfile.dat") [1, 2, 3]
+## File.delete!(Path.from_str("myfile.dat"), [1, 2, 3])?
## ```
##
## > This does not securely erase the file's contents from disk; instead, the operating
@@ -121,13 +122,13 @@ write_utf8! = \str, path ->
## > [Path.delete!] does the same thing, except it takes a [Path] instead of a [Str].
delete! : Str => Result {} [FileWriteErr Path IOErr]
delete! = \path ->
- Path.delete! (Path.from_str path)
+ Path.delete!(Path.from_str(path))
## Reads all the bytes in a file.
##
## ```
## # Read all the bytes in `myfile.txt`.
-## File.read_bytes! "myfile.txt"
+## bytes = File.read_bytes!("myfile.txt")?
## ```
##
## This opens the file first and closes it after reading its contents.
@@ -137,13 +138,13 @@ delete! = \path ->
## > [Path.read_bytes!] does the same thing, except it takes a [Path] instead of a [Str].
read_bytes! : Str => Result (List U8) [FileReadErr Path IOErr]
read_bytes! = \path ->
- Path.read_bytes! (Path.from_str path)
+ Path.read_bytes!(Path.from_str(path))
## Reads a [Str] from a file containing [UTF-8](https://en.wikipedia.org/wiki/UTF-8)-encoded text.
##
## ```
## # Reads UTF-8 encoded text into a Str from the file "myfile.txt"
-## File.read_utf8! "myfile.txt"
+## str = File.read_utf8!("myfile.txt")?
## ```
##
## This opens the file first and closes it after reading its contents.
@@ -154,7 +155,7 @@ read_bytes! = \path ->
## > [Path.read_utf8!] does the same thing, except it takes a [Path] instead of a [Str].
read_utf8! : Str => Result Str [FileReadErr Path IOErr, FileReadUtf8Err Path _]
read_utf8! = \path ->
- Path.read_utf8! (Path.from_str path)
+ Path.read_utf8!(Path.from_str(path))
# read : Str, fmt => Result contents [FileReadErr Path ReadErr, FileReadDecodingFailed] where contents implements Decoding, fmt implements DecoderFormatting
# read = \path, fmt ->
@@ -170,7 +171,7 @@ read_utf8! = \path ->
## > [Path.hard_link!] does the same thing, except it takes a [Path] instead of a [Str].
hard_link! : Str => Result {} [LinkErr IOErr]
hard_link! = \path ->
- Path.hard_link! (Path.from_str path)
+ Path.hard_link!(Path.from_str(path))
## Returns True if the path exists on disk and is pointing at a directory.
## Returns False if the path exists and it is not a directory. If the path does not exist,
@@ -181,7 +182,7 @@ hard_link! = \path ->
## > [Path.is_dir!] does the same thing, except it takes a [Path] instead of a [Str].
is_dir! : Str => Result Bool [PathErr IOErr]
is_dir! = \path ->
- Path.is_dir! (Path.from_str path)
+ Path.is_dir!(Path.from_str(path))
## Returns True if the path exists on disk and is pointing at a regular file.
## Returns False if the path exists and it is not a file. If the path does not exist,
@@ -192,7 +193,7 @@ is_dir! = \path ->
## > [Path.is_file!] does the same thing, except it takes a [Path] instead of a [Str].
is_file! : Str => Result Bool [PathErr IOErr]
is_file! = \path ->
- Path.is_file! (Path.from_str path)
+ Path.is_file!(Path.from_str(path))
## Returns True if the path exists on disk and is pointing at a symbolic link.
## Returns False if the path exists and it is not a symbolic link. If the path does not exist,
@@ -203,7 +204,7 @@ is_file! = \path ->
## > [Path.is_sym_link!] does the same thing, except it takes a [Path] instead of a [Str].
is_sym_link! : Str => Result Bool [PathErr IOErr]
is_sym_link! = \path ->
- Path.is_sym_link! (Path.from_str path)
+ Path.is_sym_link!(Path.from_str(path))
## Return the type of the path if the path exists on disk.
## This uses [rust's std::path::is_symlink](https://doc.rust-lang.org/std/path/struct.Path.html#method.is_symlink).
@@ -211,7 +212,7 @@ is_sym_link! = \path ->
## > [Path.type!] does the same thing, except it takes a [Path] instead of a [Str].
type! : Str => Result [IsFile, IsDir, IsSymLink] [PathErr IOErr]
type! = \path ->
- Path.type! (Path.from_str path)
+ Path.type!(Path.from_str(path))
Reader := { reader : Host.FileReader, path : Path }
@@ -223,12 +224,12 @@ Reader := { reader : Host.FileReader, path : Path }
## Use [read_utf8!] if you want to get the entire file contents at once.
open_reader! : Str => Result Reader [GetFileReadErr Path IOErr]
open_reader! = \path_str ->
- path = Path.from_str path_str
+ path = Path.from_str(path_str)
# 0 means with default capacity
- Host.file_reader! (Str.toUtf8 path_str) 0
- |> Result.mapErr \err -> GetFileReadErr path (InternalIOErr.handle_err err)
- |> Result.map \reader -> @Reader { reader, path }
+ Host.file_reader!(Str.to_utf8(path_str), 0)
+ |> Result.map_err(\err -> GetFileReadErr(path, InternalIOErr.handle_err(err)))
+ |> Result.map(\reader -> @Reader({ reader, path }))
## Try to open a `File.Reader` for buffered (= part by part) reading given a path string.
## The buffer will be created with the specified capacity.
@@ -239,11 +240,11 @@ open_reader! = \path_str ->
## Use [read_utf8!] if you want to get the entire file contents at once.
open_reader_with_capacity! : Str, U64 => Result Reader [GetFileReadErr Path IOErr]
open_reader_with_capacity! = \path_str, capacity ->
- path = Path.from_str path_str
+ path = Path.from_str(path_str)
- Host.file_reader! (Str.toUtf8 path_str) capacity
- |> Result.mapErr \err -> GetFileReadErr path (InternalIOErr.handle_err err)
- |> Result.map \reader -> @Reader { reader, path }
+ Host.file_reader!(Str.to_utf8(path_str), capacity)
+ |> Result.map_err(\err -> GetFileReadErr(path, InternalIOErr.handle_err(err)))
+ |> Result.map(\reader -> @Reader({ reader, path }))
## Try to read a line from a file given a Reader.
## The line will be provided as the list of bytes (`List U8`) until a newline (`0xA` byte).
@@ -254,6 +255,6 @@ open_reader_with_capacity! = \path_str, capacity ->
##
## Use [read_utf8!] if you want to get the entire file contents at once.
read_line! : Reader => Result (List U8) [FileReadErr Path IOErr]
-read_line! = \@Reader { reader, path } ->
- Host.file_read_line! reader
- |> Result.mapErr \err -> FileReadErr path (InternalIOErr.handle_err err)
+read_line! = \@Reader({ reader, path }) ->
+ Host.file_read_line!(reader)
+ |> Result.map_err(\err -> FileReadErr(path, InternalIOErr.handle_err(err)))
diff --git a/platform/FileMetadata.roc b/platform/FileMetadata.roc
index b66dbc17..a78b4a96 100644
--- a/platform/FileMetadata.roc
+++ b/platform/FileMetadata.roc
@@ -20,19 +20,19 @@ FileMetadata := {
## Returns the number of bytes in the associated file.
bytes : FileMetadata -> U64
-bytes = \@FileMetadata info -> info.bytes
+bytes = \@FileMetadata(info) -> info.bytes
## Returns [Bool.true] if the associated file is read-only.
is_readonly : FileMetadata -> Bool
-is_readonly = \@FileMetadata info -> info.is_readonly
+is_readonly = \@FileMetadata(info) -> info.is_readonly
## Returns the type of the associated file.
type : FileMetadata -> [File, Dir, Symlink]
-type = \@FileMetadata info -> info.type
+type = \@FileMetadata(info) -> info.type
## Returns the mode of the associated file.
mode : FileMetadata -> [Unix U32, NonUnix]
-mode = \@FileMetadata info -> info.mode
+mode = \@FileMetadata(info) -> info.mode
# TODO need to create a Time module and return something like Time.Utc here.
# lastModified : FileMetadata -> Utc
diff --git a/platform/Http.roc b/platform/Http.roc
index 374e4170..8930500c 100644
--- a/platform/Http.roc
+++ b/platform/Http.roc
@@ -36,7 +36,7 @@ Response : InternalHttp.Response
##
default_request : Request
default_request = {
- method: Get,
+ method: GET,
headers: [],
uri: "",
body: [],
@@ -56,12 +56,11 @@ header = \(name, value) -> { name, value }
## ```
## # Prints out the HTML of the Roc-lang website.
## response =
-## { Http.default_request & url: "https://www.roc-lang.org" }
-## |> Http.send!
+## Http.send!({ Http.default_request & url: "https://www.roc-lang.org" })
##
## response.body
-## |> Str.fromUtf8
-## |> Result.withDefault "Invalid UTF-8"
+## |> Str.from_utf8
+## |> Result.with_default("Invalid UTF-8")
## |> Stdout.line
## ```
send! : Request => Response
@@ -77,20 +76,20 @@ send! = \request ->
## ```
## import json.Json
##
-## # On the server side we send `Encode.toBytes {foo: "Hello Json!"} Json.utf8`
-## { foo } = Http.get! "http://localhost:8000" Json.utf8
+## # On the server side we send `Encode.to_bytes {foo: "Hello Json!"} Json.utf8`
+## { foo } = Http.get!("http://localhost:8000", Json.utf8)?
## ```
get! : Str, fmt => Result body [HttpDecodingFailed] where body implements Decoding, fmt implements DecoderFormatting
get! = \uri, fmt ->
- response = send! { default_request & uri }
+ response = send!({ default_request & uri })
- Decode.fromBytes response.body fmt
- |> Result.mapErr \_ -> HttpDecodingFailed
+ Decode.from_bytes(response.body, fmt)
+ |> Result.map_err(\_ -> HttpDecodingFailed)
get_utf8! : Str => Result Str [BadBody Str]
get_utf8! = \uri ->
- response = send! { default_request & uri }
+ response = send!({ default_request & uri })
response.body
- |> Str.fromUtf8
- |> Result.mapErr \_ -> BadBody "Invalid UTF-8"
+ |> Str.from_utf8
+ |> Result.map_err(\_ -> BadBody("Invalid UTF-8"))
diff --git a/platform/InternalArg.roc b/platform/InternalArg.roc
index 1f5f2f33..bf9f5c91 100644
--- a/platform/InternalArg.roc
+++ b/platform/InternalArg.roc
@@ -8,7 +8,7 @@ ArgToAndFromHost := {
}
to_os_raw : ArgToAndFromHost -> [Unix (List U8), Windows (List U16)]
-to_os_raw = \@ArgToAndFromHost inner ->
+to_os_raw = \@ArgToAndFromHost(inner) ->
when inner.type is
- Unix -> Unix inner.unix
- Windows -> Windows inner.windows
+ Unix -> Unix(inner.unix)
+ Windows -> Windows(inner.windows)
diff --git a/platform/InternalCmd.roc b/platform/InternalCmd.roc
index 2fe8f9bb..7be8a527 100644
--- a/platform/InternalCmd.roc
+++ b/platform/InternalCmd.roc
@@ -22,7 +22,7 @@ Output : {
from_host_output : OutputFromHost -> Output
from_host_output = \{ status, stdout, stderr } -> {
- status: Result.mapErr status InternalIOErr.handle_err,
+ status: Result.map_err(status, InternalIOErr.handle_err),
stdout,
stderr,
}
diff --git a/platform/InternalDateTime.roc b/platform/InternalDateTime.roc
index 0b219e73..cf9dd220 100644
--- a/platform/InternalDateTime.roc
+++ b/platform/InternalDateTime.roc
@@ -8,18 +8,18 @@ DateTime : { year : I128, month : I128, day : I128, hours : I128, minutes : I128
to_iso_8601 : DateTime -> Str
to_iso_8601 = \{ year, month, day, hours, minutes, seconds } ->
- year_str = year_with_padded_zeros year
- month_str = month_with_padded_zeros month
- day_str = day_with_padded_zeros day
- hour_str = hours_with_padded_zeros hours
- minute_str = minutes_with_padded_zeros minutes
- seconds_str = seconds_with_padded_zeros seconds
+ year_str = year_with_padded_zeros(year)
+ month_str = month_with_padded_zeros(month)
+ day_str = day_with_padded_zeros(day)
+ hour_str = hours_with_padded_zeros(hours)
+ minute_str = minutes_with_padded_zeros(minutes)
+ seconds_str = seconds_with_padded_zeros(seconds)
"$(year_str)-$(month_str)-$(day_str)T$(hour_str):$(minute_str):$(seconds_str)Z"
year_with_padded_zeros : I128 -> Str
year_with_padded_zeros = \year ->
- year_str = Num.toStr year
+ year_str = Num.to_str(year)
if year < 10 then
"000$(year_str)"
else if year < 100 then
@@ -31,7 +31,7 @@ year_with_padded_zeros = \year ->
month_with_padded_zeros : I128 -> Str
month_with_padded_zeros = \month ->
- month_str = Num.toStr month
+ month_str = Num.to_str(month)
if month < 10 then
"0$(month_str)"
else
@@ -59,37 +59,37 @@ is_leap_year = \year ->
(year % 400 == 0) # expecpt when also divisible by 400
)
-expect is_leap_year 2000
-expect is_leap_year 2012
-expect !(is_leap_year 1900)
-expect !(is_leap_year 2015)
-expect List.map [2023, 1988, 1992, 1996] is_leap_year == [Bool.false, Bool.true, Bool.true, Bool.true]
-expect List.map [1700, 1800, 1900, 2100, 2200, 2300, 2500, 2600] is_leap_year == [Bool.false, Bool.false, Bool.false, Bool.false, Bool.false, Bool.false, Bool.false, Bool.false]
+expect is_leap_year(2000)
+expect is_leap_year(2012)
+expect !(is_leap_year(1900))
+expect !(is_leap_year(2015))
+expect List.map([2023, 1988, 1992, 1996], is_leap_year) == [Bool.false, Bool.true, Bool.true, Bool.true]
+expect List.map([1700, 1800, 1900, 2100, 2200, 2300, 2500, 2600], is_leap_year) == [Bool.false, Bool.false, Bool.false, Bool.false, Bool.false, Bool.false, Bool.false, Bool.false]
days_in_month : I128, I128 -> I128
days_in_month = \year, month ->
- if List.contains [1, 3, 5, 7, 8, 10, 12] month then
+ if List.contains([1, 3, 5, 7, 8, 10, 12], month) then
31
- else if List.contains [4, 6, 9, 11] month then
+ else if List.contains([4, 6, 9, 11], month) then
30
else if month == 2 then
- (if is_leap_year year then 29 else 28)
+ (if is_leap_year(year) then 29 else 28)
else
0
-expect days_in_month 2023 1 == 31 # January
-expect days_in_month 2023 2 == 28 # February
-expect days_in_month 1996 2 == 29 # February in a leap year
-expect days_in_month 2023 3 == 31 # March
-expect days_in_month 2023 4 == 30 # April
-expect days_in_month 2023 5 == 31 # May
-expect days_in_month 2023 6 == 30 # June
-expect days_in_month 2023 7 == 31 # July
-expect days_in_month 2023 8 == 31 # August
-expect days_in_month 2023 9 == 30 # September
-expect days_in_month 2023 10 == 31 # October
-expect days_in_month 2023 11 == 30 # November
-expect days_in_month 2023 12 == 31 # December
+expect days_in_month(2023, 1) == 31 # January
+expect days_in_month(2023, 2) == 28 # February
+expect days_in_month(1996, 2) == 29 # February in a leap year
+expect days_in_month(2023, 3) == 31 # March
+expect days_in_month(2023, 4) == 30 # April
+expect days_in_month(2023, 5) == 31 # May
+expect days_in_month(2023, 6) == 30 # June
+expect days_in_month(2023, 7) == 31 # July
+expect days_in_month(2023, 8) == 31 # August
+expect days_in_month(2023, 9) == 30 # September
+expect days_in_month(2023, 10) == 31 # October
+expect days_in_month(2023, 11) == 30 # November
+expect days_in_month(2023, 12) == 31 # December
epoch_millis_to_datetime : I128 -> DateTime
epoch_millis_to_datetime = \millis ->
@@ -100,56 +100,63 @@ epoch_millis_to_datetime = \millis ->
month = 1
year = 1970
- epoch_millis_to_datetimeHelp {
- year,
- month,
- day,
- hours: hours % 24,
- minutes: minutes % 60,
- seconds: seconds % 60,
- }
+ epoch_millis_to_datetimeHelp(
+ {
+ year,
+ month,
+ day,
+ hours: hours % 24,
+ minutes: minutes % 60,
+ seconds: seconds % 60,
+ },
+ )
epoch_millis_to_datetimeHelp : DateTime -> DateTime
epoch_millis_to_datetimeHelp = \current ->
- count_days_in_month = days_in_month current.year current.month
+ count_days_in_month = days_in_month(current.year, current.month)
count_days_in_prev_month =
if current.month == 1 then
- days_in_month (current.year - 1) 12
+ days_in_month((current.year - 1), 12)
else
- days_in_month current.year (current.month - 1)
+ days_in_month(current.year, (current.month - 1))
if current.day < 1 then
- epoch_millis_to_datetimeHelp
+ epoch_millis_to_datetimeHelp(
{ current &
year: if current.month == 1 then current.year - 1 else current.year,
month: if current.month == 1 then 12 else current.month - 1,
day: current.day + count_days_in_prev_month,
- }
+ },
+ )
else if current.hours < 0 then
- epoch_millis_to_datetimeHelp
+ epoch_millis_to_datetimeHelp(
{ current &
day: current.day - 1,
hours: current.hours + 24,
- }
+ },
+ )
else if current.minutes < 0 then
- epoch_millis_to_datetimeHelp
+ epoch_millis_to_datetimeHelp(
{ current &
hours: current.hours - 1,
minutes: current.minutes + 60,
- }
+ },
+ )
else if current.seconds < 0 then
- epoch_millis_to_datetimeHelp
+ epoch_millis_to_datetimeHelp(
{ current &
minutes: current.minutes - 1,
seconds: current.seconds + 60,
- }
+ },
+ )
else if current.day > count_days_in_month then
- epoch_millis_to_datetimeHelp
+ epoch_millis_to_datetimeHelp(
{ current &
year: if current.month == 12 then current.year + 1 else current.year,
month: if current.month == 12 then 1 else current.month + 1,
day: current.day - count_days_in_month,
- }
+ },
+ )
else
current
diff --git a/platform/InternalHttp.roc b/platform/InternalHttp.roc
index 54a7a2a7..e994ca09 100644
--- a/platform/InternalHttp.roc
+++ b/platform/InternalHttp.roc
@@ -19,7 +19,7 @@ module [
# FOR ROC
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
-Method : [Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch, Extension Str]
+Method : [OPTIONS, GET, POST, PUT, DELETE, HEAD, TRACE, CONNECT, PATCH, EXTENSION Str]
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
Header : { name : Str, value : Str }
@@ -64,72 +64,72 @@ to_host_response = \{ status, headers, body } -> {
to_host_request : Request -> RequestToAndFromHost
to_host_request = \{ method, headers, uri, body, timeout_ms } -> {
- method: to_host_method method,
- method_ext: to_host_method_ext method,
+ method: to_host_method(method),
+ method_ext: to_host_method_ext(method),
headers,
uri,
body,
- timeout_ms: to_host_timeout timeout_ms,
+ timeout_ms: to_host_timeout(timeout_ms),
}
to_host_method : Method -> _
to_host_method = \method ->
when method is
- Options -> 5
- Get -> 3
- Post -> 7
- Put -> 8
- Delete -> 1
- Head -> 4
- Trace -> 9
- Connect -> 0
- Patch -> 6
- Extension _ -> 2
+ OPTIONS -> 5
+ GET -> 3
+ POST -> 7
+ PUT -> 8
+ DELETE -> 1
+ HEAD -> 4
+ TRACE -> 9
+ CONNECT -> 0
+ PATCH -> 6
+ EXTENSION(_) -> 2
to_host_method_ext : Method -> Str
to_host_method_ext = \method ->
when method is
- Extension ext -> ext
+ EXTENSION(ext) -> ext
_ -> ""
to_host_timeout : _ -> U64
to_host_timeout = \timeout ->
when timeout is
- TimeoutMilliseconds ms -> ms
+ TimeoutMilliseconds(ms) -> ms
NoTimeout -> 0
from_host_request : RequestToAndFromHost -> Request
from_host_request = \{ method, method_ext, headers, uri, body, timeout_ms } -> {
- method: from_host_method method method_ext,
+ method: from_host_method(method, method_ext),
headers,
uri,
body,
- timeout_ms: from_host_timeout timeout_ms,
+ timeout_ms: from_host_timeout(timeout_ms),
}
from_host_method : U64, Str -> Method
from_host_method = \tag, ext ->
when tag is
- 5 -> Options
- 3 -> Get
- 7 -> Post
- 8 -> Put
- 1 -> Delete
- 4 -> Head
- 9 -> Trace
- 0 -> Connect
- 6 -> Patch
- 2 -> Extension ext
- _ -> crash "invalid tag from host"
+ 5 -> OPTIONS
+ 3 -> GET
+ 7 -> POST
+ 8 -> PUT
+ 1 -> DELETE
+ 4 -> HEAD
+ 9 -> TRACE
+ 0 -> CONNECT
+ 6 -> PATCH
+ 2 -> EXTENSION(ext)
+ _ -> crash("invalid tag from host")
from_host_timeout : U64 -> [TimeoutMilliseconds U64, NoTimeout]
from_host_timeout = \timeout ->
when timeout is
0 -> NoTimeout
- _ -> TimeoutMilliseconds timeout
+ _ -> TimeoutMilliseconds(timeout)
-expect from_host_timeout 0 == NoTimeout
-expect from_host_timeout 1 == TimeoutMilliseconds 1
+expect from_host_timeout(0) == NoTimeout
+expect from_host_timeout(1) == TimeoutMilliseconds(1)
from_host_response : ResponseToAndFromHost -> Response
from_host_response = \{ status, headers, body } -> {
diff --git a/platform/InternalIOErr.roc b/platform/InternalIOErr.roc
index ef95d767..5d5f20e5 100644
--- a/platform/InternalIOErr.roc
+++ b/platform/InternalIOErr.roc
@@ -55,4 +55,4 @@ handle_err = \{ tag, msg } ->
Interrupted -> Interrupted
Unsupported -> Unsupported
OutOfMemory -> OutOfMemory
- Other | EndOfFile -> Other msg
+ Other | EndOfFile -> Other(msg)
diff --git a/platform/InternalPath.roc b/platform/InternalPath.roc
index 258fc8b1..05779bf7 100644
--- a/platform/InternalPath.roc
+++ b/platform/InternalPath.roc
@@ -57,22 +57,22 @@ wrap : UnwrappedPath -> InternalPath
wrap = @InternalPath
unwrap : InternalPath -> UnwrappedPath
-unwrap = \@InternalPath raw -> raw
+unwrap = \@InternalPath(raw) -> raw
## TODO do this in the host, and iterate over the Str
## bytes when possible instead of always converting to
## a heap-allocated List.
to_bytes : InternalPath -> List U8
-to_bytes = \@InternalPath path ->
+to_bytes = \@InternalPath(path) ->
when path is
- FromOperatingSystem bytes -> bytes
- ArbitraryBytes bytes -> bytes
- FromStr str -> Str.toUtf8 str
+ FromOperatingSystem(bytes) -> bytes
+ ArbitraryBytes(bytes) -> bytes
+ FromStr(str) -> Str.to_utf8(str)
from_arbitrary_bytes : List U8 -> InternalPath
from_arbitrary_bytes = \bytes ->
- @InternalPath (ArbitraryBytes bytes)
+ @InternalPath(ArbitraryBytes(bytes))
from_os_bytes : List U8 -> InternalPath
from_os_bytes = \bytes ->
- @InternalPath (FromOperatingSystem bytes)
+ @InternalPath(FromOperatingSystem(bytes))
diff --git a/platform/Locale.roc b/platform/Locale.roc
index 57a9b51d..3ffddfba 100644
--- a/platform/Locale.roc
+++ b/platform/Locale.roc
@@ -10,8 +10,8 @@ import Host
## The returned [Str] is a BCP 47 language tag, like `en-US` or `fr-CA`.
get! : {} => Result Str [NotAvailable]
get! = \{} ->
- Host.get_locale! {}
- |> Result.mapErr \{} -> NotAvailable
+ Host.get_locale!({})
+ |> Result.map_err(\{} -> NotAvailable)
## Returns the preferred locales for the system or application.
##
diff --git a/platform/Path.roc b/platform/Path.roc
index 6116e20e..4f3bf215 100644
--- a/platform/Path.roc
+++ b/platform/Path.roc
@@ -57,10 +57,11 @@ IOErr : InternalIOErr.IOErr
##
## ```
## # Writes `{"some":"json stuff"}` to the file `output.json`:
-## Path.write!
-## { some: "json stuff" }
-## (Path.from_str "output.json")
-## Json.toCompactUtf8
+## Path.write!(
+## { some: "json stuff" },
+## Path.from_str("output.json"),
+## Json.toCompactUtf8,
+## )?
## ```
##
## This opens the file first and closes it after writing to it.
@@ -69,16 +70,16 @@ IOErr : InternalIOErr.IOErr
## > To write unformatted bytes to a file, you can use [Path.write_bytes!] instead.
write! : val, Path, fmt => Result {} [FileWriteErr Path IOErr] where val implements Encoding, fmt implements EncoderFormatting
write! = \val, path, fmt ->
- bytes = Encode.toBytes val fmt
+ bytes = Encode.to_bytes(val, fmt)
# TODO handle encoding errors here, once they exist
- write_bytes! bytes path
+ write_bytes!(bytes, path)
## Writes bytes to a file.
##
## ```
## # Writes the bytes 1, 2, 3 to the file `myfile.dat`.
-## Path.write_bytes! [1, 2, 3] (Path.from_str "myfile.dat")
+## Path.write_bytes!([1, 2, 3], Path.from_str("myfile.dat"))?
## ```
##
## This opens the file first and closes it after writing to it.
@@ -86,16 +87,16 @@ write! = \val, path, fmt ->
## > To format data before writing it to a file, you can use [Path.write!] instead.
write_bytes! : List U8, Path => Result {} [FileWriteErr Path IOErr]
write_bytes! = \bytes, path ->
- path_bytes = InternalPath.to_bytes path
+ path_bytes = InternalPath.to_bytes(path)
- Host.file_write_bytes! path_bytes bytes
- |> Result.mapErr \err -> FileWriteErr path (InternalIOErr.handle_err err)
+ Host.file_write_bytes!(path_bytes, bytes)
+ |> Result.map_err(\err -> FileWriteErr(path, InternalIOErr.handle_err(err)))
## Writes a [Str] to a file, encoded as [UTF-8](https://en.wikipedia.org/wiki/UTF-8).
##
## ```
## # Writes "Hello!" encoded as UTF-8 to the file `myfile.txt`.
-## Path.write_utf8! "Hello!" (Path.from_str "myfile.txt")
+## Path.write_utf8!("Hello!", Path.from_str("myfile.txt"))?
## ```
##
## This opens the file first and closes it after writing to it.
@@ -103,10 +104,10 @@ write_bytes! = \bytes, path ->
## > To write unformatted bytes to a file, you can use [Path.write_bytes!] instead.
write_utf8! : Str, Path => Result {} [FileWriteErr Path IOErr]
write_utf8! = \str, path ->
- path_bytes = InternalPath.to_bytes path
+ path_bytes = InternalPath.to_bytes(path)
- Host.file_write_utf8! path_bytes str
- |> Result.mapErr \err -> FileWriteErr path (InternalIOErr.handle_err err)
+ Host.file_write_utf8!(path_bytes, str)
+ |> Result.map_err(\err -> FileWriteErr(path, InternalIOErr.handle_err(err)))
## Note that the path may not be valid depending on the filesystem where it is used.
## For example, paths containing `:` are valid on ext4 and NTFS filesystems, but not
@@ -119,7 +120,7 @@ write_utf8! = \str, path ->
## up front for a false sense of security (given symlinks, parts of a path being renamed, etc.).
from_str : Str -> Path
from_str = \str ->
- FromStr str
+ FromStr(str)
|> InternalPath.wrap
## Not all filesystems use Unicode paths. This function can be used to create a path which
@@ -129,7 +130,7 @@ from_str = \str ->
## (e.g. `Path.read_bytes` or `WriteStream.openPath`) will fail.
from_bytes : List U8 -> Path
from_bytes = \bytes ->
- ArbitraryBytes bytes
+ ArbitraryBytes(bytes)
|> InternalPath.wrap
## Unfortunately, operating system paths do not include information about which charset
@@ -165,13 +166,13 @@ from_bytes = \bytes ->
## `toStrUsingCharset` instead of [display].
display : Path -> Str
display = \path ->
- when InternalPath.unwrap path is
- FromStr str -> str
- FromOperatingSystem bytes | ArbitraryBytes bytes ->
- when Str.fromUtf8 bytes is
- Ok str -> str
+ when InternalPath.unwrap(path) is
+ FromStr(str) -> str
+ FromOperatingSystem(bytes) | ArbitraryBytes(bytes) ->
+ when Str.from_utf8(bytes) is
+ Ok(str) -> str
# TODO: this should use the builtin Str.display to display invalid UTF-8 chars in just the right spots, but that does not exist yet!
- Err _ -> "ďż˝"
+ Err(_) -> "ďż˝"
## Returns true if the path exists on disk and is pointing at a directory.
## Returns `Ok false` if the path exists and it is not a directory. If the path does not exist,
@@ -182,8 +183,8 @@ display = \path ->
## > [`File.is_dir`](File#is_dir!) does the same thing, except it takes a [Str] instead of a [Path].
is_dir! : Path => Result Bool [PathErr IOErr]
is_dir! = \path ->
- res = type!? path
- Ok (res == IsDir)
+ res = type!(path)?
+ Ok((res == IsDir))
## Returns true if the path exists on disk and is pointing at a regular file.
## Returns `Ok false` if the path exists and it is not a file. If the path does not exist,
@@ -194,8 +195,8 @@ is_dir! = \path ->
## > [`File.is_file`](File#is_file!) does the same thing, except it takes a [Str] instead of a [Path].
is_file! : Path => Result Bool [PathErr IOErr]
is_file! = \path ->
- res = type!? path
- Ok (res == IsFile)
+ res = type!(path)?
+ Ok((res == IsFile))
## Returns true if the path exists on disk and is pointing at a symbolic link.
## Returns `Ok false` if the path exists and it is not a symbolic link. If the path does not exist,
@@ -206,59 +207,61 @@ is_file! = \path ->
## > [`File.is_sym_link`](File#is_sym_link!) does the same thing, except it takes a [Str] instead of a [Path].
is_sym_link! : Path => Result Bool [PathErr IOErr]
is_sym_link! = \path ->
- res = type!? path
- Ok (res == IsSymLink)
+ res = type!(path)?
+ Ok((res == IsSymLink))
## Return the type of the path if the path exists on disk.
##
## > [`File.type`](File#type!) does the same thing, except it takes a [Str] instead of a [Path].
type! : Path => Result [IsFile, IsDir, IsSymLink] [PathErr IOErr]
type! = \path ->
- Host.path_type! (InternalPath.to_bytes path)
- |> Result.mapErr \err -> PathErr (InternalIOErr.handle_err err)
- |> Result.map \path_type ->
- if path_type.is_sym_link then
- IsSymLink
- else if path_type.is_dir then
- IsDir
- else
- IsFile
+ Host.path_type!(InternalPath.to_bytes(path))
+ |> Result.map_err(\err -> PathErr(InternalIOErr.handle_err(err)))
+ |> Result.map(
+ \path_type ->
+ if path_type.is_sym_link then
+ IsSymLink
+ else if path_type.is_dir then
+ IsDir
+ else
+ IsFile,
+ )
## If the last component of this path has no `.`, appends `.` followed by the given string.
## Otherwise, replaces everything after the last `.` with the given string.
##
## ```
## # Each of these gives "foo/bar/baz.txt"
-## Path.from_str "foo/bar/baz" |> Path.with_extension "txt"
-## Path.from_str "foo/bar/baz." |> Path.with_extension "txt"
-## Path.from_str "foo/bar/baz.xz" |> Path.with_extension "txt"
+## Path.from_str("foo/bar/baz") |> Path.with_extension("txt")
+## Path.from_str("foo/bar/baz.") |> Path.with_extension("txt")
+## Path.from_str("foo/bar/baz.xz") |> Path.with_extension("txt")
## ```
with_extension : Path, Str -> Path
with_extension = \path, extension ->
- when InternalPath.unwrap path is
- FromOperatingSystem bytes | ArbitraryBytes bytes ->
+ when InternalPath.unwrap(path) is
+ FromOperatingSystem(bytes) | ArbitraryBytes(bytes) ->
before_dot =
- when List.splitLast bytes (Num.toU8 '.') is
- Ok { before } -> before
- Err NotFound -> bytes
+ when List.split_last(bytes, Num.to_u8('.')) is
+ Ok({ before }) -> before
+ Err(NotFound) -> bytes
before_dot
- |> List.reserve (Str.countUtf8Bytes extension |> Num.intCast |> Num.addSaturated 1)
- |> List.append (Num.toU8 '.')
- |> List.concat (Str.toUtf8 extension)
+ |> List.reserve((Str.count_utf8_bytes(extension) |> Num.int_cast |> Num.add_saturated(1)))
+ |> List.append(Num.to_u8('.'))
+ |> List.concat(Str.to_utf8(extension))
|> ArbitraryBytes
|> InternalPath.wrap
- FromStr str ->
+ FromStr(str) ->
before_dot =
- when Str.splitLast str "." is
- Ok { before } -> before
- Err NotFound -> str
+ when Str.split_last(str, ".") is
+ Ok({ before }) -> before
+ Err(NotFound) -> str
before_dot
- |> Str.reserve (Str.countUtf8Bytes extension |> Num.addSaturated 1)
- |> Str.concat "."
- |> Str.concat extension
+ |> Str.reserve((Str.count_utf8_bytes(extension) |> Num.add_saturated(1)))
+ |> Str.concat(".")
+ |> Str.concat(extension)
|> FromStr
|> InternalPath.wrap
@@ -272,7 +275,7 @@ with_extension = \path, extension ->
##
## ```
## # Deletes the file named `myfile.dat`
-## Path.delete (Path.from_str "myfile.dat") [1, 2, 3]
+## Path.delete(Path.from_str("myfile.dat"), [1, 2, 3])?
## ```
##
## > This does not securely erase the file's contents from disk; instead, the operating
@@ -284,14 +287,14 @@ with_extension = \path, extension ->
## > [`File.delete`](File#delete!) does the same thing, except it takes a [Str] instead of a [Path].
delete! : Path => Result {} [FileWriteErr Path IOErr]
delete! = \path ->
- Host.file_delete! (InternalPath.to_bytes path)
- |> Result.mapErr \err -> FileWriteErr path (InternalIOErr.handle_err err)
+ Host.file_delete!(InternalPath.to_bytes(path))
+ |> Result.map_err(\err -> FileWriteErr(path, InternalIOErr.handle_err(err)))
## Reads a [Str] from a file containing [UTF-8](https://en.wikipedia.org/wiki/UTF-8)-encoded text.
##
## ```
## # Reads UTF-8 encoded text into a Str from the file "myfile.txt"
-## Path.read_utf8 (Path.from_str "myfile.txt")
+## contents_str = Path.read_utf8(Path.from_str("myfile.txt"))?
## ```
##
## This opens the file first and closes it after reading its contents.
@@ -303,17 +306,17 @@ delete! = \path ->
read_utf8! : Path => Result Str [FileReadErr Path IOErr, FileReadUtf8Err Path _]
read_utf8! = \path ->
bytes =
- Host.file_read_bytes! (InternalPath.to_bytes path)
- |> Result.mapErr? \read_err -> FileReadErr path (InternalIOErr.handle_err read_err)
+ Host.file_read_bytes!(InternalPath.to_bytes(path))
+ |> Result.map_err?(\read_err -> FileReadErr(path, InternalIOErr.handle_err(read_err)))
- Str.fromUtf8 bytes
- |> Result.mapErr \err -> FileReadUtf8Err path err
+ Str.from_utf8(bytes)
+ |> Result.map_err(\err -> FileReadUtf8Err(path, err))
## Reads all the bytes in a file.
##
## ```
## # Read all the bytes in `myfile.txt`.
-## Path.read_bytes! (Path.from_str "myfile.txt")
+## contents_bytes = Path.read_bytes!(Path.from_str("myfile.txt"))?
## ```
##
## This opens the file first and closes it after reading its contents.
@@ -323,17 +326,17 @@ read_utf8! = \path ->
## > [`File.read_bytes`](File#read_bytes!) does the same thing, except it takes a [Str] instead of a [Path].
read_bytes! : Path => Result (List U8) [FileReadErr Path IOErr]
read_bytes! = \path ->
- Host.file_read_bytes! (InternalPath.to_bytes path)
- |> Result.mapErr \err -> FileReadErr path (InternalIOErr.handle_err err)
+ Host.file_read_bytes!(InternalPath.to_bytes(path))
+ |> Result.map_err(\err -> FileReadErr(path, InternalIOErr.handle_err(err)))
## Lists the files and directories inside the directory.
##
## > [`Dir.list`](Dir#list!) does the same thing, except it takes a [Str] instead of a [Path].
list_dir! : Path => Result (List Path) [DirErr IOErr]
list_dir! = \path ->
- when Host.dir_list! (InternalPath.to_bytes path) is
- Ok entries -> Ok (List.map entries InternalPath.from_os_bytes)
- Err err -> Err (DirErr (InternalIOErr.handle_err err))
+ when Host.dir_list!(InternalPath.to_bytes(path)) is
+ Ok(entries) -> Ok(List.map(entries, InternalPath.from_os_bytes))
+ Err(err) -> Err(DirErr(InternalIOErr.handle_err(err)))
## Deletes a directory if it's empty
##
@@ -346,8 +349,8 @@ list_dir! = \path ->
## > [`Dir.delete_empty`](Dir#delete_empty!) does the same thing, except it takes a [Str] instead of a [Path].
delete_empty! : Path => Result {} [DirErr IOErr]
delete_empty! = \path ->
- Host.dir_delete_empty! (InternalPath.to_bytes path)
- |> Result.mapErr \err -> DirErr (InternalIOErr.handle_err err)
+ Host.dir_delete_empty!(InternalPath.to_bytes(path))
+ |> Result.map_err(\err -> DirErr(InternalIOErr.handle_err(err)))
## Recursively deletes a directory as well as all files and directories
## inside it.
@@ -361,8 +364,8 @@ delete_empty! = \path ->
## > [`Dir.delete_all`](Dir#delete_all!) does the same thing, except it takes a [Str] instead of a [Path].
delete_all! : Path => Result {} [DirErr IOErr]
delete_all! = \path ->
- Host.dir_delete_all! (InternalPath.to_bytes path)
- |> Result.mapErr \err -> DirErr (InternalIOErr.handle_err err)
+ Host.dir_delete_all!(InternalPath.to_bytes(path))
+ |> Result.map_err(\err -> DirErr(InternalIOErr.handle_err(err)))
## Creates a directory
##
@@ -374,8 +377,8 @@ delete_all! = \path ->
## > [`Dir.create`](Dir#create!) does the same thing, except it takes a [Str] instead of a [Path].
create_dir! : Path => Result {} [DirErr IOErr]
create_dir! = \path ->
- Host.dir_create! (InternalPath.to_bytes path)
- |> Result.mapErr \err -> DirErr (InternalIOErr.handle_err err)
+ Host.dir_create!(InternalPath.to_bytes(path))
+ |> Result.map_err(\err -> DirErr(InternalIOErr.handle_err(err)))
## Creates a directory recursively adding any missing parent directories.
##
@@ -386,8 +389,8 @@ create_dir! = \path ->
## > [`Dir.create_all`](Dir#create_all!) does the same thing, except it takes a [Str] instead of a [Path].
create_all! : Path => Result {} [DirErr IOErr]
create_all! = \path ->
- Host.dir_create_all! (InternalPath.to_bytes path)
- |> Result.mapErr \err -> DirErr (InternalIOErr.handle_err err)
+ Host.dir_create_all!(InternalPath.to_bytes(path))
+ |> Result.map_err(\err -> DirErr(InternalIOErr.handle_err(err)))
## Creates a new hard link on the filesystem.
##
@@ -399,6 +402,6 @@ create_all! = \path ->
## > [File.hard_link!] does the same thing, except it takes a [Str] instead of a [Path].
hard_link! : Path => Result {} [LinkErr IOErr]
hard_link! = \path ->
- Host.hard_link! (InternalPath.to_bytes path)
- |> Result.mapErr InternalIOErr.handle_err
- |> Result.mapErr LinkErr
+ Host.hard_link!(InternalPath.to_bytes(path))
+ |> Result.map_err(InternalIOErr.handle_err)
+ |> Result.map_err(LinkErr)
diff --git a/platform/Sleep.roc b/platform/Sleep.roc
index 8c677455..e5ca383f 100644
--- a/platform/Sleep.roc
+++ b/platform/Sleep.roc
@@ -9,4 +9,4 @@ import Host
##
millis! : U64 => {}
millis! = \n ->
- Host.sleep_millis! n
+ Host.sleep_millis!(n)
diff --git a/platform/Sqlite.roc b/platform/Sqlite.roc
index dfe044f0..549722ef 100644
--- a/platform/Sqlite.roc
+++ b/platform/Sqlite.roc
@@ -145,19 +145,19 @@ Stmt := Box {}
## preparing the query each time it is called. This is usually done in `init!` with the prepared `Stmt` stored in the model.
##
## ```
-## prepared_query = try Sqlite.prepare! {
+## prepared_query = Sqlite.prepare!({
## path : "path/to/database.db",
## query : "SELECT * FROM todos;",
-## }
+## })?
##
-## Sqlite.query_many_prepared! {
+## Sqlite.query_many_prepared!({
## stmt: prepared_query,
## bindings: [],
## rows: { Sqlite.decode_record <-
-## id: Sqlite.i64 "id",
-## task: Sqlite.str "task",
+## id: Sqlite.i64("id"),
+## task: Sqlite.str("task"),
## },
-## }
+## })
## ```
prepare! :
{
@@ -166,51 +166,51 @@ prepare! :
}
=> Result Stmt [SqliteErr ErrCode Str]
prepare! = \{ path, query: q } ->
- Host.sqlite_prepare! path q
- |> Result.map @Stmt
- |> Result.mapErr internal_to_external_error
+ Host.sqlite_prepare!(path, q)
+ |> Result.map(@Stmt)
+ |> Result.map_err(internal_to_external_error)
# internal use only
bind! : Stmt, List Binding => Result {} [SqliteErr ErrCode Str]
-bind! = \@Stmt stmt, bindings ->
- Host.sqlite_bind! stmt bindings
- |> Result.mapErr internal_to_external_error
+bind! = \@Stmt(stmt), bindings ->
+ Host.sqlite_bind!(stmt, bindings)
+ |> Result.map_err(internal_to_external_error)
# internal use only
columns! : Stmt => List Str
-columns! = \@Stmt stmt ->
- Host.sqlite_columns! stmt
+columns! = \@Stmt(stmt) ->
+ Host.sqlite_columns!(stmt)
# internal use only
column_value! : Stmt, U64 => Result Value [SqliteErr ErrCode Str]
-column_value! = \@Stmt stmt, i ->
- Host.sqlite_column_value! stmt i
- |> Result.mapErr internal_to_external_error
+column_value! = \@Stmt(stmt), i ->
+ Host.sqlite_column_value!(stmt, i)
+ |> Result.map_err(internal_to_external_error)
# internal use only
step! : Stmt => Result [Row, Done] [SqliteErr ErrCode Str]
-step! = \@Stmt stmt ->
- Host.sqlite_step! stmt
- |> Result.mapErr internal_to_external_error
+step! = \@Stmt(stmt) ->
+ Host.sqlite_step!(stmt)
+ |> Result.map_err(internal_to_external_error)
# internal use only
reset! : Stmt => Result {} [SqliteErr ErrCode Str]
-reset! = \@Stmt stmt ->
- Host.sqlite_reset! stmt
- |> Result.mapErr internal_to_external_error
+reset! = \@Stmt(stmt) ->
+ Host.sqlite_reset!(stmt)
+ |> Result.map_err(internal_to_external_error)
## Execute a SQL statement that doesn't return any rows (like INSERT, UPDATE, DELETE).
##
## Example:
## ```
-## Sqlite.execute! {
+## Sqlite.execute!({
## path: "path/to/database.db",
## query: "INSERT INTO users (first, last) VALUES (:first, :last);",
## bindings: [
-## { name: ":first", value: String "John" },
-## { name: ":last", value: String "Smith" },
+## { name: ":first", value: String("John") },
+## { name: ":last", value: String("Smith") },
## ],
-## }
+## })?
## ```
execute! :
{
@@ -220,8 +220,8 @@ execute! :
}
=> Result {} [SqliteErr ErrCode Str, UnhandledRows]
execute! = \{ path, query: q, bindings } ->
- stmt = try prepare! { path, query: q }
- execute_prepared! { stmt, bindings }
+ stmt = try(prepare!, { path, query: q })
+ execute_prepared!({ stmt, bindings })
## Execute a prepared SQL statement that doesn't return any rows.
##
@@ -234,30 +234,30 @@ execute_prepared! :
}
=> Result {} [SqliteErr ErrCode Str, UnhandledRows]
execute_prepared! = \{ stmt, bindings } ->
- try bind! stmt bindings
- res = step! stmt
- try reset! stmt
+ try(bind!, stmt, bindings)
+ res = step!(stmt)
+ try(reset!, stmt)
when res is
- Ok Done ->
- Ok {}
+ Ok(Done) ->
+ Ok({})
- Ok Row ->
- Err UnhandledRows
+ Ok(Row) ->
+ Err(UnhandledRows)
- Err e ->
- Err e
+ Err(e) ->
+ Err(e)
## Execute a SQL query and decode exactly one row into a value.
##
## Example:
## ```
## # count the number of rows in the `users` table
-## count = try Sqlite.query! {
+## count = Sqlite.query!({
## path: db_path,
## query: "SELECT COUNT(*) as \"count\" FROM users;",
## bindings: [],
-## row: Sqlite.u64 "count",
-## }
+## row: Sqlite.u64("count"),
+## })?
## ```
query! :
{
@@ -268,8 +268,8 @@ query! :
}
=> Result a (SqlDecodeErr (RowCountErr err))
query! = \{ path, query: q, bindings, row } ->
- stmt = try prepare! { path, query: q }
- query_prepared! { stmt, bindings, row }
+ stmt = try(prepare!, { path, query: q })
+ query_prepared!({ stmt, bindings, row })
## Execute a prepared SQL query and decode exactly one row into a value.
##
@@ -283,24 +283,24 @@ query_prepared! :
}
=> Result a (SqlDecodeErr (RowCountErr err))
query_prepared! = \{ stmt, bindings, row: decode } ->
- try bind! stmt bindings
- res = decode_exactly_one_row! stmt decode
- try reset! stmt
+ try(bind!, stmt, bindings)
+ res = decode_exactly_one_row!(stmt, decode)
+ try(reset!, stmt)
res
## Execute a SQL query and decode multiple rows into a list of values.
##
## Example:
## ```
-## Sqlite.query_many! {
+## rows = Sqlite.query_many!({
## path: "path/to/database.db",
## query: "SELECT * FROM todos;",
## bindings: [],
## rows: { Sqlite.decode_record <-
-## id: Sqlite.i64 "id",
-## task: Sqlite.str "task",
+## id: Sqlite.i64("id"),
+## task: Sqlite.str("task"),
## },
-## }
+## })?
## ```
query_many! :
{
@@ -311,8 +311,8 @@ query_many! :
}
=> Result (List a) (SqlDecodeErr err)
query_many! = \{ path, query: q, bindings, rows } ->
- stmt = try prepare! { path, query: q }
- query_many_prepared! { stmt, bindings, rows }
+ stmt = try(prepare!, { path, query: q })
+ query_many_prepared!({ stmt, bindings, rows })
## Execute a prepared SQL query and decode multiple rows into a list of values.
##
@@ -326,9 +326,9 @@ query_many_prepared! :
}
=> Result (List a) (SqlDecodeErr err)
query_many_prepared! = \{ stmt, bindings, rows: decode } ->
- try bind! stmt bindings
- res = decode_rows! stmt decode
- try reset! stmt
+ try(bind!, stmt, bindings)
+ res = decode_rows!(stmt, decode)
+ try(reset!, stmt)
res
SqlDecodeErr err : [FieldNotFound Str, SqliteErr ErrCode Str]err
@@ -339,119 +339,128 @@ SqlDecode a err := List Str -> (Stmt => Result a (SqlDecodeErr err))
## Example:
## ```
## { Sqlite.decode_record <-
-## id: Sqlite.i64 "id",
-## task: Sqlite.str "task",
+## id: Sqlite.i64("id"),
+## task: Sqlite.str("task"),
## }
## ```
decode_record : SqlDecode a err, SqlDecode b err, (a, b -> c) -> SqlDecode c err
-decode_record = \@SqlDecode gen_first, @SqlDecode gen_second, mapper ->
- @SqlDecode \cols ->
- decode_first! = gen_first cols
- decode_second! = gen_second cols
-
- \stmt ->
- first = try decode_first! stmt
- second = try decode_second! stmt
- Ok (mapper first second)
+decode_record = \@SqlDecode(gen_first), @SqlDecode(gen_second), mapper ->
+ @SqlDecode(
+ \cols ->
+ decode_first! = gen_first(cols)
+ decode_second! = gen_second(cols)
+
+ \stmt ->
+ first = try(decode_first!, stmt)
+ second = try(decode_second!, stmt)
+ Ok(mapper(first, second)),
+ )
## Transform the output of a decoder by applying a function to the decoded value.
##
## Example:
## ```
-## Sqlite.i64 "id" |> Sqlite.map_value Num.toStr
+## Sqlite.i64("id") |> Sqlite.map_value(Num.to_str)
## ```
map_value : SqlDecode a err, (a -> b) -> SqlDecode b err
-map_value = \@SqlDecode gen_decode, mapper ->
- @SqlDecode \cols ->
- decode! = gen_decode cols
+map_value = \@SqlDecode(gen_decode), mapper ->
+ @SqlDecode(
+ \cols ->
+ decode! = gen_decode(cols)
- \stmt ->
- val = try decode! stmt
- Ok (mapper val)
+ \stmt ->
+ val = try(decode!, stmt)
+ Ok(mapper(val)),
+ )
RowCountErr err : [NoRowsReturned, TooManyRowsReturned]err
# internal use only
decode_exactly_one_row! : Stmt, SqlDecode a (RowCountErr err) => Result a (SqlDecodeErr (RowCountErr err))
-decode_exactly_one_row! = \stmt, @SqlDecode gen_decode ->
- cols = columns! stmt
- decode_row! = gen_decode cols
+decode_exactly_one_row! = \stmt, @SqlDecode(gen_decode) ->
+ cols = columns!(stmt)
+ decode_row! = gen_decode(cols)
- when try step! stmt is
+ when try(step!, stmt) is
Row ->
- row = try decode_row! stmt
- when try step! stmt is
+ row = try(decode_row!, stmt)
+ when try(step!, stmt) is
Done ->
- Ok row
+ Ok(row)
Row ->
- Err TooManyRowsReturned
+ Err(TooManyRowsReturned)
Done ->
- Err NoRowsReturned
+ Err(NoRowsReturned)
# internal use only
decode_rows! : Stmt, SqlDecode a err => Result (List a) (SqlDecodeErr err)
-decode_rows! = \stmt, @SqlDecode gen_decode ->
- cols = columns! stmt
- decode_row! = gen_decode cols
+decode_rows! = \stmt, @SqlDecode(gen_decode) ->
+ cols = columns!(stmt)
+ decode_row! = gen_decode(cols)
helper! = \out ->
- when try step! stmt is
+ when try(step!, stmt) is
Done ->
- Ok out
+ Ok(out)
Row ->
- row = try decode_row! stmt
+ row = try(decode_row!, stmt)
- List.append out row
+ List.append(out, row)
|> helper!
- helper! []
+ helper!([])
# internal use only
decoder : (Value -> Result a (SqlDecodeErr err)) -> (Str -> SqlDecode a err)
-decoder = \fn -> \name ->
- @SqlDecode \cols ->
-
- found = List.findFirstIndex cols \x -> x == name
- when found is
- Ok index ->
- \stmt ->
- try column_value! stmt index
- |> fn
-
- Err NotFound ->
- \_ ->
- Err (FieldNotFound name)
+decoder = \fn ->
+ \name ->
+ @SqlDecode(
+ \cols ->
+
+ found = List.find_first_index(cols, \x -> x == name)
+ when found is
+ Ok(index) ->
+ \stmt ->
+ try(column_value!, stmt, index)
+ |> fn
+
+ Err(NotFound) ->
+ \_ ->
+ Err(FieldNotFound(name)),
+ )
## Decode a [Value] keeping it tagged. This is useful when data could be many possible types.
##
## For example here we build a decoder that decodes the rows into a list of records with `id` and `mixed_data` fields:
## ```
-## Sqlite.query_many! {
+## rows = Sqlite.query_many!({
## path: "path/to/database.db",
## query: "SELECT id, mix_data FROM users;",
## bindings: [],
## rows: { Sqlite.decode_record <-
-## id: Sqlite.i64 "id",
-## mix_data: Sqlite.tagged_value "mixed_data",
+## id: Sqlite.i64("id"),
+## mix_data: Sqlite.tagged_value("mixed_data"),
## },
-## }
+## })?
## ```
tagged_value : Str -> SqlDecode Value []
-tagged_value = decoder \val ->
- Ok val
+tagged_value = decoder(
+ \val ->
+ Ok(val),
+)
to_unexpected_type_err = \val ->
type =
when val is
- Integer _ -> Integer
- Real _ -> Real
- String _ -> String
- Bytes _ -> Bytes
+ Integer(_) -> Integer
+ Real(_) -> Real
+ String(_) -> String
+ Bytes(_) -> Bytes
Null -> Null
- Err (UnexpectedType type)
+ Err(UnexpectedType(type))
UnexpectedTypeErr : [UnexpectedType [Integer, Real, String, Bytes, Null]]
@@ -459,97 +468,105 @@ UnexpectedTypeErr : [UnexpectedType [Integer, Real, String, Bytes, Null]]
##
## For example here we build a decoder that decodes the rows into a list of records with `id` and `name` fields:
## ```
-## Sqlite.query_many! {
+## rows = Sqlite.query_many!({
## path: "path/to/database.db",
## query: "SELECT id, name FROM users;",
## bindings: [],
## rows: { Sqlite.decode_record <-
-## id: Sqlite.i64 "id",
-## task: Sqlite.str "name",
+## id: Sqlite.i64("id"),
+## task: Sqlite.str("name"),
## },
-## }
+## })?
## ```
str : Str -> SqlDecode Str UnexpectedTypeErr
-str = decoder \val ->
- when val is
- String s -> Ok s
- _ -> to_unexpected_type_err val
+str = decoder(
+ \val ->
+ when val is
+ String(s) -> Ok(s)
+ _ -> to_unexpected_type_err(val),
+)
## Decode a [Value] to a [List U8].
bytes : Str -> SqlDecode (List U8) UnexpectedTypeErr
-bytes = decoder \val ->
- when val is
- Bytes b -> Ok b
- _ -> to_unexpected_type_err val
+bytes = decoder(
+ \val ->
+ when val is
+ Bytes(b) -> Ok(b)
+ _ -> to_unexpected_type_err(val),
+)
# internal use only
int_decoder : (I64 -> Result a err) -> (Str -> SqlDecode a [FailedToDecodeInteger err]UnexpectedTypeErr)
int_decoder = \cast ->
- decoder \val ->
- when val is
- Integer i -> cast i |> Result.mapErr FailedToDecodeInteger
- _ -> to_unexpected_type_err val
+ decoder(
+ \val ->
+ when val is
+ Integer(i) -> cast(i) |> Result.map_err(FailedToDecodeInteger)
+ _ -> to_unexpected_type_err(val),
+ )
# internal use only
real_decoder : (F64 -> Result a err) -> (Str -> SqlDecode a [FailedToDecodeReal err]UnexpectedTypeErr)
real_decoder = \cast ->
- decoder \val ->
- when val is
- Real r -> cast r |> Result.mapErr FailedToDecodeReal
- _ -> to_unexpected_type_err val
+ decoder(
+ \val ->
+ when val is
+ Real(r) -> cast(r) |> Result.map_err(FailedToDecodeReal)
+ _ -> to_unexpected_type_err(val),
+ )
## Decode a [Value] to a [I64].
##
## For example here we build a decoder that decodes the rows into a list of records with `id` and `name` fields:
## ```
-## Sqlite.query_many! {
+## rows = Sqlite.query_many!({
## path: "path/to/database.db",
## query: "SELECT id, name FROM users;",
## bindings: [],
## rows: { Sqlite.decode_record <-
-## id: Sqlite.i64 "id",
-## task: Sqlite.str "name",
+## id: Sqlite.i64("id"),
+## task: Sqlite.str("name"),
## },
-## }
+## })?
## ```
i64 : Str -> SqlDecode I64 [FailedToDecodeInteger []]UnexpectedTypeErr
-i64 = int_decoder Ok
+i64 = int_decoder(Ok)
## Decode a [Value] to a [I32].
i32 : Str -> SqlDecode I32 [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-i32 = int_decoder Num.toI32Checked
+i32 = int_decoder(Num.to_i32_checked)
## Decode a [Value] to a [I16].
i16 : Str -> SqlDecode I16 [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-i16 = int_decoder Num.toI16Checked
+i16 = int_decoder(Num.to_i16_checked)
## Decode a [Value] to a [I8].
i8 : Str -> SqlDecode I8 [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-i8 = int_decoder Num.toI8Checked
+i8 = int_decoder(Num.to_i8_checked)
## Decode a [Value] to a [U64].
u64 : Str -> SqlDecode U64 [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-u64 = int_decoder Num.toU64Checked
+u64 = int_decoder(Num.to_u64_checked)
## Decode a [Value] to a [U32].
u32 : Str -> SqlDecode U32 [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-u32 = int_decoder Num.toU32Checked
+u32 = int_decoder(Num.to_u32_checked)
## Decode a [Value] to a [U16].
u16 : Str -> SqlDecode U16 [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-u16 = int_decoder Num.toU16Checked
+u16 = int_decoder(Num.to_u16_checked)
## Decode a [Value] to a [U8].
u8 : Str -> SqlDecode U8 [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-u8 = int_decoder Num.toU8Checked
+u8 = int_decoder(Num.to_u8_checked)
## Decode a [Value] to a [F64].
f64 : Str -> SqlDecode F64 [FailedToDecodeReal []]UnexpectedTypeErr
-f64 = real_decoder Ok
+f64 = real_decoder(Ok)
## Decode a [Value] to a [F32].
f32 : Str -> SqlDecode F32 [FailedToDecodeReal []]UnexpectedTypeErr
-f32 = real_decoder (\x -> Num.toF32 x |> Ok)
+f32 = real_decoder(\x -> Num.to_f32(x) |> Ok)
# TODO: Mising Num.toDec and Num.toDecChecked
# dec = realSqlDecoder Ok
@@ -562,77 +579,85 @@ Nullable a : [NotNull a, Null]
## Decode a [Value] to a [Nullable Str].
nullable_str : Str -> SqlDecode (Nullable Str) UnexpectedTypeErr
-nullable_str = decoder \val ->
- when val is
- String s -> Ok (NotNull s)
- Null -> Ok Null
- _ -> to_unexpected_type_err val
+nullable_str = decoder(
+ \val ->
+ when val is
+ String(s) -> Ok(NotNull(s))
+ Null -> Ok(Null)
+ _ -> to_unexpected_type_err(val),
+)
## Decode a [Value] to a [Nullable (List U8)].
nullable_bytes : Str -> SqlDecode (Nullable (List U8)) UnexpectedTypeErr
-nullable_bytes = decoder \val ->
- when val is
- Bytes b -> Ok (NotNull b)
- Null -> Ok Null
- _ -> to_unexpected_type_err val
+nullable_bytes = decoder(
+ \val ->
+ when val is
+ Bytes(b) -> Ok(NotNull(b))
+ Null -> Ok(Null)
+ _ -> to_unexpected_type_err(val),
+)
# internal use only
nullable_int_decoder : (I64 -> Result a err) -> (Str -> SqlDecode (Nullable a) [FailedToDecodeInteger err]UnexpectedTypeErr)
nullable_int_decoder = \cast ->
- decoder \val ->
- when val is
- Integer i -> cast i |> Result.map NotNull |> Result.mapErr FailedToDecodeInteger
- Null -> Ok Null
- _ -> to_unexpected_type_err val
+ decoder(
+ \val ->
+ when val is
+ Integer(i) -> cast(i) |> Result.map(NotNull) |> Result.map_err(FailedToDecodeInteger)
+ Null -> Ok(Null)
+ _ -> to_unexpected_type_err(val),
+ )
# internal use only
nullable_real_decoder : (F64 -> Result a err) -> (Str -> SqlDecode (Nullable a) [FailedToDecodeReal err]UnexpectedTypeErr)
nullable_real_decoder = \cast ->
- decoder \val ->
- when val is
- Real r -> cast r |> Result.map NotNull |> Result.mapErr FailedToDecodeReal
- Null -> Ok Null
- _ -> to_unexpected_type_err val
+ decoder(
+ \val ->
+ when val is
+ Real(r) -> cast(r) |> Result.map(NotNull) |> Result.map_err(FailedToDecodeReal)
+ Null -> Ok(Null)
+ _ -> to_unexpected_type_err(val),
+ )
## Decode a [Value] to a [Nullable I64].
nullable_i64 : Str -> SqlDecode (Nullable I64) [FailedToDecodeInteger []]UnexpectedTypeErr
-nullable_i64 = nullable_int_decoder Ok
+nullable_i64 = nullable_int_decoder(Ok)
## Decode a [Value] to a [Nullable I32].
nullable_i32 : Str -> SqlDecode (Nullable I32) [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-nullable_i32 = nullable_int_decoder Num.toI32Checked
+nullable_i32 = nullable_int_decoder(Num.to_i32_checked)
## Decode a [Value] to a [Nullable I16].
nullable_i16 : Str -> SqlDecode (Nullable I16) [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-nullable_i16 = nullable_int_decoder Num.toI16Checked
+nullable_i16 = nullable_int_decoder(Num.to_i16_checked)
## Decode a [Value] to a [Nullable I8].
nullable_i8 : Str -> SqlDecode (Nullable I8) [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-nullable_i8 = nullable_int_decoder Num.toI8Checked
+nullable_i8 = nullable_int_decoder(Num.to_i8_checked)
## Decode a [Value] to a [Nullable U64].
nullable_u64 : Str -> SqlDecode (Nullable U64) [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-nullable_u64 = nullable_int_decoder Num.toU64Checked
+nullable_u64 = nullable_int_decoder(Num.to_u64_checked)
## Decode a [Value] to a [Nullable U32].
nullable_u32 : Str -> SqlDecode (Nullable U32) [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-nullable_u32 = nullable_int_decoder Num.toU32Checked
+nullable_u32 = nullable_int_decoder(Num.to_u32_checked)
## Decode a [Value] to a [Nullable U16].
nullable_u16 : Str -> SqlDecode (Nullable U16) [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-nullable_u16 = nullable_int_decoder Num.toU16Checked
+nullable_u16 = nullable_int_decoder(Num.to_u16_checked)
## Decode a [Value] to a [Nullable U8].
nullable_u8 : Str -> SqlDecode (Nullable U8) [FailedToDecodeInteger [OutOfBounds]]UnexpectedTypeErr
-nullable_u8 = nullable_int_decoder Num.toU8Checked
+nullable_u8 = nullable_int_decoder(Num.to_u8_checked)
## Decode a [Value] to a [Nullable F64].
nullable_f64 : Str -> SqlDecode (Nullable F64) [FailedToDecodeReal []]UnexpectedTypeErr
-nullable_f64 = nullable_real_decoder Ok
+nullable_f64 = nullable_real_decoder(Ok)
## Decode a [Value] to a [Nullable F32].
nullable_f32 : Str -> SqlDecode (Nullable F32) [FailedToDecodeReal []]UnexpectedTypeErr
-nullable_f32 = nullable_real_decoder (\x -> Num.toF32 x |> Ok)
+nullable_f32 = nullable_real_decoder(\x -> Num.to_f32(x) |> Ok)
# TODO: Mising Num.toDec and Num.toDecChecked
# nullable_dec = nullable_real_decoder Ok
@@ -640,7 +665,7 @@ nullable_f32 = nullable_real_decoder (\x -> Num.toF32 x |> Ok)
# internal use only
internal_to_external_error : InternalSqlite.SqliteError -> [SqliteErr ErrCode Str]
internal_to_external_error = \{ code, message } ->
- SqliteErr (code_from_i64 code) message
+ SqliteErr(code_from_i64(code), message)
# internal use only
code_from_i64 : I64 -> ErrCode
@@ -706,7 +731,7 @@ code_from_i64 = \code ->
else if code == 101 then
Done
else
- Unknown code
+ Unknown(code)
## Convert a [ErrCode] to a pretty string for display purposes.
errcode_to_str : ErrCode -> Str
@@ -742,4 +767,4 @@ errcode_to_str = \code ->
Warning -> "Warning: Warnings from sqlite3_log()"
Row -> "Row: sqlite3_step() has another row ready"
Done -> "Done: sqlite3_step() has finished executing"
- Unknown c -> "Unknown: error code $(Num.toStr c) not known"
+ Unknown(c) -> "Unknown: error code $(Num.to_str(c)) not known"
diff --git a/platform/Stderr.roc b/platform/Stderr.roc
index d5aedf35..90bbc4ca 100644
--- a/platform/Stderr.roc
+++ b/platform/Stderr.roc
@@ -36,14 +36,14 @@ IOErr : [
handle_err : InternalIOErr.IOErrFromHost -> [StderrErr IOErr]
handle_err = \{ tag, msg } ->
when tag is
- NotFound -> StderrErr NotFound
- PermissionDenied -> StderrErr PermissionDenied
- BrokenPipe -> StderrErr BrokenPipe
- AlreadyExists -> StderrErr AlreadyExists
- Interrupted -> StderrErr Interrupted
- Unsupported -> StderrErr Unsupported
- OutOfMemory -> StderrErr OutOfMemory
- Other | EndOfFile -> StderrErr (Other msg)
+ NotFound -> StderrErr(NotFound)
+ PermissionDenied -> StderrErr(PermissionDenied)
+ BrokenPipe -> StderrErr(BrokenPipe)
+ AlreadyExists -> StderrErr(AlreadyExists)
+ Interrupted -> StderrErr(Interrupted)
+ Unsupported -> StderrErr(Unsupported)
+ OutOfMemory -> StderrErr(OutOfMemory)
+ Other | EndOfFile -> StderrErr(Other(msg))
## Write the given string to [standard error](https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)),
## followed by a newline.
@@ -51,8 +51,8 @@ handle_err = \{ tag, msg } ->
## > To write to `stderr` without the newline, see [Stderr.write!].
line! : Str => Result {} [StderrErr IOErr]
line! = \str ->
- Host.stderr_line! str
- |> Result.mapErr handle_err
+ Host.stderr_line!(str)
+ |> Result.map_err(handle_err)
## Write the given string to [standard error](https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)).
##
@@ -62,5 +62,5 @@ line! = \str ->
## > To write to `stderr` with a newline at the end, see [Stderr.line!].
write! : Str => Result {} [StderrErr IOErr]
write! = \str ->
- Host.stderr_write! str
- |> Result.mapErr handle_err
+ Host.stderr_write!(str)
+ |> Result.map_err(handle_err)
diff --git a/platform/Stdin.roc b/platform/Stdin.roc
index 96fe164c..f492c5cb 100644
--- a/platform/Stdin.roc
+++ b/platform/Stdin.roc
@@ -37,15 +37,15 @@ IOErr : [
handle_err : InternalIOErr.IOErrFromHost -> [EndOfFile, StdinErr IOErr]
handle_err = \{ tag, msg } ->
when tag is
- NotFound -> StdinErr NotFound
- PermissionDenied -> StdinErr PermissionDenied
- BrokenPipe -> StdinErr BrokenPipe
- AlreadyExists -> StdinErr AlreadyExists
- Interrupted -> StdinErr Interrupted
- Unsupported -> StdinErr Unsupported
- OutOfMemory -> StdinErr OutOfMemory
+ NotFound -> StdinErr(NotFound)
+ PermissionDenied -> StdinErr(PermissionDenied)
+ BrokenPipe -> StdinErr(BrokenPipe)
+ AlreadyExists -> StdinErr(AlreadyExists)
+ Interrupted -> StdinErr(Interrupted)
+ Unsupported -> StdinErr(Unsupported)
+ OutOfMemory -> StdinErr(OutOfMemory)
EndOfFile -> EndOfFile
- Other -> StdinErr (Other msg)
+ Other -> StdinErr(Other(msg))
## Read a line from [standard input](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)).
##
@@ -55,8 +55,8 @@ handle_err = \{ tag, msg } ->
## the user knows it's necessary to enter something before the program will continue.
line! : {} => Result Str [EndOfFile, StdinErr IOErr]
line! = \{} ->
- Host.stdin_line! {}
- |> Result.mapErr handle_err
+ Host.stdin_line!({})
+ |> Result.map_err(handle_err)
## Read bytes from [standard input](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)).
## ‼️ This function can read no more than 16,384 bytes at a time. Use [readToEnd!] if you need more.
@@ -66,21 +66,23 @@ line! = \{} ->
## without buffering until Enter key is pressed.
bytes! : {} => Result (List U8) [EndOfFile, StdinErr IOErr]
bytes! = \{} ->
- Host.stdin_bytes! {}
- |> Result.mapErr handle_err
+ Host.stdin_bytes!({})
+ |> Result.map_err(handle_err)
## Read all bytes from [standard input](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)) until EOF in this source.
read_to_end! : {} => Result (List U8) [StdinErr IOErr]
read_to_end! = \{} ->
- Host.stdin_read_to_end! {}
- |> Result.mapErr \{ tag, msg } ->
- when tag is
- NotFound -> StdinErr NotFound
- PermissionDenied -> StdinErr PermissionDenied
- BrokenPipe -> StdinErr BrokenPipe
- AlreadyExists -> StdinErr AlreadyExists
- Interrupted -> StdinErr Interrupted
- Unsupported -> StdinErr Unsupported
- OutOfMemory -> StdinErr OutOfMemory
- EndOfFile -> crash "unreachable, reading to EOF"
- Other -> StdinErr (Other msg)
+ Host.stdin_read_to_end!({})
+ |> Result.map_err(
+ \{ tag, msg } ->
+ when tag is
+ NotFound -> StdinErr(NotFound)
+ PermissionDenied -> StdinErr(PermissionDenied)
+ BrokenPipe -> StdinErr(BrokenPipe)
+ AlreadyExists -> StdinErr(AlreadyExists)
+ Interrupted -> StdinErr(Interrupted)
+ Unsupported -> StdinErr(Unsupported)
+ OutOfMemory -> StdinErr(OutOfMemory)
+ EndOfFile -> crash("unreachable, reading to EOF")
+ Other -> StdinErr(Other(msg)),
+ )
diff --git a/platform/Stdout.roc b/platform/Stdout.roc
index 567ce3e2..4dcca59a 100644
--- a/platform/Stdout.roc
+++ b/platform/Stdout.roc
@@ -36,14 +36,14 @@ IOErr : [
handle_err : InternalIOErr.IOErrFromHost -> [StdoutErr IOErr]
handle_err = \{ tag, msg } ->
when tag is
- NotFound -> StdoutErr NotFound
- PermissionDenied -> StdoutErr PermissionDenied
- BrokenPipe -> StdoutErr BrokenPipe
- AlreadyExists -> StdoutErr AlreadyExists
- Interrupted -> StdoutErr Interrupted
- Unsupported -> StdoutErr Unsupported
- OutOfMemory -> StdoutErr OutOfMemory
- Other | EndOfFile -> StdoutErr (Other msg)
+ NotFound -> StdoutErr(NotFound)
+ PermissionDenied -> StdoutErr(PermissionDenied)
+ BrokenPipe -> StdoutErr(BrokenPipe)
+ AlreadyExists -> StdoutErr(AlreadyExists)
+ Interrupted -> StdoutErr(Interrupted)
+ Unsupported -> StdoutErr(Unsupported)
+ OutOfMemory -> StdoutErr(OutOfMemory)
+ Other | EndOfFile -> StdoutErr(Other(msg))
## Write the given string to [standard output](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)),
## followed by a newline.
@@ -52,8 +52,8 @@ handle_err = \{ tag, msg } ->
##
line! : Str => Result {} [StdoutErr IOErr]
line! = \str ->
- Host.stdout_line! str
- |> Result.mapErr handle_err
+ Host.stdout_line!(str)
+ |> Result.map_err(handle_err)
## Write the given string to [standard output](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)).
##
@@ -63,5 +63,5 @@ line! = \str ->
## > To write to `stdout` with a newline at the end, see [Stdout.line!].
write! : Str => Result {} [StdoutErr IOErr]
write! = \str ->
- Host.stdout_write! str
- |> Result.mapErr handle_err
+ Host.stdout_write!(str)
+ |> Result.map_err(handle_err)
diff --git a/platform/Tcp.roc b/platform/Tcp.roc
index 797f3d86..01b23fa4 100644
--- a/platform/Tcp.roc
+++ b/platform/Tcp.roc
@@ -42,7 +42,7 @@ parse_connect_err = \err ->
"ErrorKind::Interrupted" -> Interrupted
"ErrorKind::TimedOut" -> TimedOut
"ErrorKind::Unsupported" -> Unsupported
- other -> Unrecognized other
+ other -> Unrecognized(other)
## Represents errors that can occur when performing an effect with a [Stream].
StreamErr : [
@@ -66,13 +66,13 @@ parse_stream_err = \err ->
"ErrorKind::Interrupted" -> Interrupted
"ErrorKind::OutOfMemory" -> OutOfMemory
"ErrorKind::BrokenPipe" -> BrokenPipe
- other -> Unrecognized other
+ other -> Unrecognized(other)
## Opens a TCP connection to a remote host.
##
## ```
## # Connect to localhost:8080
-## stream = Tcp.connect! "localhost" 8080
+## stream = Tcp.connect!("localhost", 8080)?
## ```
##
## The connection is automatically closed when the last reference to the stream is dropped.
@@ -85,46 +85,47 @@ parse_stream_err = \err ->
##
connect! : Str, U16 => Result Stream ConnectErr
connect! = \host, port ->
- Host.tcp_connect! host port
- |> Result.map @Stream
- |> Result.mapErr parse_connect_err
+ Host.tcp_connect!(host, port)
+ |> Result.map(@Stream)
+ |> Result.map_err(parse_connect_err)
## Read up to a number of bytes from the TCP stream.
##
## ```
-## # Read up to 64 bytes from the stream and convert to a Str
-## received = File.read_up_to! stream 64
-## Str.fromUtf8 received
+## # Read up to 64 bytes from the stream
+## received_bytes = File.read_up_to!(stream, 64)?
## ```
##
## > To read an exact number of bytes or fail, you can use [Tcp.read_exactly!] instead.
read_up_to! : Stream, U64 => Result (List U8) [TcpReadErr StreamErr]
-read_up_to! = \@Stream stream, bytes_to_read ->
- Host.tcp_read_up_to! stream bytes_to_read
- |> Result.mapErr \err -> TcpReadErr (parse_stream_err err)
+read_up_to! = \@Stream(stream), bytes_to_read ->
+ Host.tcp_read_up_to!(stream, bytes_to_read)
+ |> Result.map_err(\err -> TcpReadErr(parse_stream_err(err)))
## Read an exact number of bytes or fail.
##
## ```
-## bytes = File.read_exactly!? stream 64
+## bytes = File.read_exactly!(stream, 64)?
## ```
##
## `TcpUnexpectedEOF` is returned if the stream ends before the specfied number of bytes is reached.
##
read_exactly! : Stream, U64 => Result (List U8) [TcpReadErr StreamErr, TcpUnexpectedEOF]
-read_exactly! = \@Stream stream, bytes_to_read ->
- Host.tcp_read_exactly! stream bytes_to_read
- |> Result.mapErr \err ->
- if err == unexpected_eof_error_message then
- TcpUnexpectedEOF
- else
- TcpReadErr (parse_stream_err err)
+read_exactly! = \@Stream(stream), bytes_to_read ->
+ Host.tcp_read_exactly!(stream, bytes_to_read)
+ |> Result.map_err(
+ \err ->
+ if err == unexpected_eof_error_message then
+ TcpUnexpectedEOF
+ else
+ TcpReadErr(parse_stream_err(err)),
+ )
## Read until a delimiter or EOF is reached.
##
## ```
## # Read until null terminator
-## File.read_until! stream 0
+## bytes = File.read_until!(stream, 0)?
## ```
##
## If found, the delimiter is included as the last byte.
@@ -132,58 +133,58 @@ read_exactly! = \@Stream stream, bytes_to_read ->
## > To read until a newline is found, you can use [Tcp.read_line!] which
## conveniently decodes to a [Str].
read_until! : Stream, U8 => Result (List U8) [TcpReadErr StreamErr]
-read_until! = \@Stream stream, byte ->
- Host.tcp_read_until! stream byte
- |> Result.mapErr \err -> TcpReadErr (parse_stream_err err)
+read_until! = \@Stream(stream), byte ->
+ Host.tcp_read_until!(stream, byte)
+ |> Result.map_err(\err -> TcpReadErr(parse_stream_err(err)))
## Read until a newline or EOF is reached.
##
## ```
## # Read a line and then print it to `stdout`
-## lineStr = File.read_line! stream
-## Stdout.line lineStr
+## line_str = File.read_line!(stream)?
+## Stdout.line(lineStr)?
## ```
##
## If found, the newline is included as the last character in the [Str].
##
read_line! : Stream => Result Str [TcpReadErr StreamErr, TcpReadBadUtf8 _]
read_line! = \stream ->
- bytes = read_until!? stream '\n'
+ bytes = read_until!(stream, '\n')?
- Str.fromUtf8 bytes
- |> Result.mapErr TcpReadBadUtf8
+ Str.from_utf8(bytes)
+ |> Result.map_err(TcpReadBadUtf8)
## Writes bytes to a TCP stream.
##
## ```
## # Writes the bytes 1, 2, 3
-## Tcp.write!? stream [1, 2, 3]
+## Tcp.write!(stream, [1, 2, 3])?
## ```
##
## > To write a [Str], you can use [Tcp.write_utf8!] instead.
write! : Stream, List U8 => Result {} [TcpWriteErr StreamErr]
-write! = \@Stream stream, bytes ->
- Host.tcp_write! stream bytes
- |> Result.mapErr \err -> TcpWriteErr (parse_stream_err err)
+write! = \@Stream(stream), bytes ->
+ Host.tcp_write!(stream, bytes)
+ |> Result.map_err(\err -> TcpWriteErr(parse_stream_err(err)))
## Writes a [Str] to a TCP stream, encoded as [UTF-8](https://en.wikipedia.org/wiki/UTF-8).
##
## ```
## # Write "Hi from Roc!" encoded as UTF-8
-## Tcp.write_utf8! stream "Hi from Roc!"
+## Tcp.write_utf8!(stream, "Hi from Roc!")?
## ```
##
## > To write unformatted bytes, you can use [Tcp.write!] instead.
write_utf8! : Stream, Str => Result {} [TcpWriteErr StreamErr]
write_utf8! = \stream, str ->
- write! stream (Str.toUtf8 str)
+ write!(stream, Str.to_utf8(str))
## Convert a [ConnectErr] to a [Str] you can print.
##
## ```
## when err is
-## TcpPerfomErr (TcpConnectErr connectErr) ->
-## Stderr.line (Tcp.connect_err_to_str connectErr)
+## TcpPerfomErr(TcpConnectErr(connectErr)) ->
+## Stderr.line!(Tcp.connect_err_to_str(connectErr))
## ```
##
connect_err_to_str : ConnectErr -> Str
@@ -196,19 +197,19 @@ connect_err_to_str = \err ->
Interrupted -> "Interrupted"
TimedOut -> "TimedOut"
Unsupported -> "Unsupported"
- Unrecognized message -> "Unrecognized Error: $(message)"
+ Unrecognized(message) -> "Unrecognized Error: $(message)"
## Convert a [StreamErr] to a [Str] you can print.
##
## ```
## when err is
-## TcpPerformErr (TcpReadErr err) ->
-## errStr = Tcp.stream_err_to_str err
-## Stderr.line "Error while reading: $(errStr)"
+## TcpPerformErr(TcpReadErr(err)) ->
+## errStr = Tcp.stream_err_to_str(err)
+## Stderr.line!("Error while reading: $(errStr)")
##
-## TcpPerformErr (TcpWriteErr err) ->
-## errStr = Tcp.stream_err_to_str err
-## Stderr.line "Error while writing: $(errStr)"
+## TcpPerformErr(TcpWriteErr(err)) ->
+## errStr = Tcp.stream_err_to_str(err)
+## Stderr.line!("Error while writing: $(errStr)")
## ```
##
stream_err_to_str : StreamErr -> Str
@@ -221,4 +222,4 @@ stream_err_to_str = \err ->
Interrupted -> "Interrupted"
OutOfMemory -> "OutOfMemory"
BrokenPipe -> "BrokenPipe"
- Unrecognized message -> "Unrecognized Error: $(message)"
+ Unrecognized(message) -> "Unrecognized Error: $(message)"
diff --git a/platform/Tty.roc b/platform/Tty.roc
index 380e1a31..49b570f2 100644
--- a/platform/Tty.roc
+++ b/platform/Tty.roc
@@ -21,7 +21,7 @@ import Host
##
enable_raw_mode! : {} => {}
enable_raw_mode! = \{} ->
- Host.tty_mode_raw! {}
+ Host.tty_mode_raw!({})
## Revert terminal to default behaviour
##
@@ -29,4 +29,4 @@ enable_raw_mode! = \{} ->
##
disable_raw_mode! : {} => {}
disable_raw_mode! = \{} ->
- Host.tty_mode_canonical! {}
+ Host.tty_mode_canonical!({})
diff --git a/platform/Url.roc b/platform/Url.roc
index 6f00f254..b96cd41b 100644
--- a/platform/Url.roc
+++ b/platform/Url.roc
@@ -12,6 +12,7 @@ module [
with_query,
with_fragment,
query_params,
+ path,
]
## A [Uniform Resource Locator](https://en.wikipedia.org/wiki/URL).
@@ -25,54 +26,54 @@ Url := Str implements [Inspect]
##
## The following example reserves 50 bytes, then builds the url `https://example.com/stuff?caf%C3%A9=du%20Monde&email=hi%40example.com`;
## ```
-## Url.from_str "https://example.com"
-## |> Url.reserve 50
-## |> Url.append "stuff"
-## |> Url.append_param "café" "du Monde"
-## |> Url.append_param "email" "hi@example.com"
+## Url.from_str("https://example.com")
+## |> Url.reserve(50)
+## |> Url.append("stuff")
+## |> Url.append_param("café", "du Monde")
+## |> Url.append_param("email", "hi@example.com")
## ```
-## The [Str.countUtf8Bytes](https://www.roc-lang.org/builtins/Str#countUtf8Bytes) function can be helpful in finding out how many bytes to reserve.
+## The [Str.count_utf8_bytes](https://www.roc-lang.org/builtins/Str#countUtf8Bytes) function can be helpful in finding out how many bytes to reserve.
##
-## There is no `Url.withCapacity` because it's better to reserve extra capacity
+## There is no `Url.with_capacity` because it's better to reserve extra capacity
## on a [Str] first, and then pass that string to [Url.from_str]. This function will make use
## of the extra capacity.
reserve : Url, U64 -> Url
-reserve = \@Url str, cap ->
- @Url (Str.reserve str (Num.intCast cap))
+reserve = \@Url(str), cap ->
+ @Url(Str.reserve(str, Num.int_cast(cap)))
## Create a [Url] without validating or [percent-encoding](https://en.wikipedia.org/wiki/Percent-encoding)
## anything.
##
## ```
-## Url.from_str "https://example.com#stuff"
+## Url.from_str("https://example.com#stuff")
## ```
##
## URLs can be absolute, like `https://example.com`, or they can be relative, like `/blah`.
##
## ```
-## Url.from_str "/this/is#relative"
+## Url.from_str("/this/is#relative")
## ```
##
## Since nothing is validated, this can return invalid URLs.
##
## ```
-## Url.from_str "https://this is not a valid URL, not at all!"
+## Url.from_str("https://this is not a valid URL, not at all!")
## ```
##
## Naturally, passing invalid URLs to functions that need valid ones will tend to result in errors.
##
from_str : Str -> Url
-from_str = \str -> @Url str
+from_str = \str -> @Url(str)
## Return a [Str] representation of this URL.
## ```
## # Gives "https://example.com/two%20words"
-## Url.from_str "https://example.com"
-## |> Url.append "two words"
+## Url.from_str("https://example.com")
+## |> Url.append("two words")
## |> Url.to_str
## ```
to_str : Url -> Str
-to_str = \@Url str -> str
+to_str = \@Url(str) -> str
## [Percent-encodes](https://en.wikipedia.org/wiki/Percent-encoding) a
## [path component](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax)
@@ -83,105 +84,105 @@ to_str = \@Url str -> str
##
## ```
## # Gives https://example.com/some%20stuff
-## Url.from_str "https://example.com"
-## |> Url.append "some stuff"
+## Url.from_str("https://example.com")
+## |> Url.append("some stuff")
##
## # Gives https://example.com/stuff?search=blah#fragment
-## Url.from_str "https://example.com?search=blah#fragment"
-## |> Url.append "stuff"
+## Url.from_str("https://example.com?search=blah#fragment")
+## |> Url.append("stuff")
##
## # Gives https://example.com/things/stuff/more/etc/"
## Url.from_str "https://example.com/things/"
-## |> Url.append "/stuff/"
-## |> Url.append "/more/etc/"
+## |> Url.append("/stuff/")
+## |> Url.append("/more/etc/")
##
## # Gives https://example.com/things
-## Url.from_str "https://example.com/things"
-## |> Url.append ""
+## Url.from_str("https://example.com/things")
+## |> Url.append("")
## ```
append : Url, Str -> Url
-append = \@Url url_str, suffix_unencoded ->
- suffix = percent_encode suffix_unencoded
+append = \@Url(url_str), suffix_unencoded ->
+ suffix = percent_encode(suffix_unencoded)
- when Str.splitFirst url_str "?" is
- Ok { before, after } ->
+ when Str.split_first(url_str, "?") is
+ Ok({ before, after }) ->
bytes =
- Str.countUtf8Bytes before
+ Str.count_utf8_bytes(before)
+ 1 # for "/"
- + Str.countUtf8Bytes suffix
+ + Str.count_utf8_bytes(suffix)
+ 1 # for "?"
- + Str.countUtf8Bytes after
+ + Str.count_utf8_bytes(after)
before
- |> Str.reserve bytes
- |> append_help suffix
- |> Str.concat "?"
- |> Str.concat after
+ |> Str.reserve(bytes)
+ |> append_help(suffix)
+ |> Str.concat("?")
+ |> Str.concat(after)
|> @Url
- Err NotFound ->
+ Err(NotFound) ->
# There wasn't a query, but there might still be a fragment
- when Str.splitFirst url_str "#" is
- Ok { before, after } ->
+ when Str.split_first(url_str, "#") is
+ Ok({ before, after }) ->
bytes =
- Str.countUtf8Bytes before
+ Str.count_utf8_bytes(before)
+ 1 # for "/"
- + Str.countUtf8Bytes suffix
+ + Str.count_utf8_bytes(suffix)
+ 1 # for "#"
- + Str.countUtf8Bytes after
+ + Str.count_utf8_bytes(after)
before
- |> Str.reserve bytes
- |> append_help suffix
- |> Str.concat "#"
- |> Str.concat after
+ |> Str.reserve(bytes)
+ |> append_help(suffix)
+ |> Str.concat("#")
+ |> Str.concat(after)
|> @Url
- Err NotFound ->
+ Err(NotFound) ->
# No query and no fragment, so just append it
- @Url (append_help url_str suffix)
+ @Url(append_help(url_str, suffix))
## Internal helper
append_help : Str, Str -> Str
append_help = \prefix, suffix ->
- if Str.endsWith prefix "/" then
- if Str.startsWith suffix "/" then
+ if Str.ends_with(prefix, "/") then
+ if Str.starts_with(suffix, "/") then
# Avoid a double-slash by appending only the part of the suffix after the "/"
- when Str.splitFirst suffix "/" is
- Ok { after } ->
+ when Str.split_first(suffix, "/") is
+ Ok({ after }) ->
# TODO `expect before == ""`
- Str.concat prefix after
+ Str.concat(prefix, after)
- Err NotFound ->
+ Err(NotFound) ->
# This should never happen, because we already verified
# that the suffix startsWith "/"
# TODO `expect Bool.false` here with a comment
- Str.concat prefix suffix
+ Str.concat(prefix, suffix)
else
# prefix ends with "/" but suffix doesn't start with one, so just append.
- Str.concat prefix suffix
- else if Str.startsWith suffix "/" then
+ Str.concat(prefix, suffix)
+ else if Str.starts_with(suffix, "/") then
# Suffix starts with "/" but prefix doesn't end with one, so just append them.
- Str.concat prefix suffix
- else if Str.isEmpty prefix then
+ Str.concat(prefix, suffix)
+ else if Str.is_empty(prefix) then
# Prefix is empty; return suffix.
suffix
- else if Str.isEmpty suffix then
+ else if Str.is_empty(suffix) then
# Suffix is empty; return prefix.
prefix
else
# Neither is empty, but neither has a "/", so add one in between.
prefix
- |> Str.concat "/"
- |> Str.concat suffix
+ |> Str.concat("/")
+ |> Str.concat(suffix)
## Internal helper. This is intentionally unexposed so that you don't accidentally
## double-encode things. If you really want to percent-encode an arbitrary string,
## you can always do:
##
## ```
-## Url.from_str ""
-## |> Url.append myStrToEncode
+## Url.from_str("")
+## |> Url.append(myStrToEncode)
## |> Url.to_str
## ```
##
@@ -193,38 +194,42 @@ percent_encode : Str -> Str
percent_encode = \input ->
# Optimistically assume we won't need any percent encoding, and can have
# the same capacity as the input string. If we're wrong, it will get doubled.
- initial_output = List.withCapacity (Str.countUtf8Bytes input |> Num.intCast)
+ initial_output = List.with_capacity((Str.count_utf8_bytes(input) |> Num.int_cast))
answer =
- List.walk (Str.toUtf8 input) initial_output \output, byte ->
- # Spec for percent-encoding: https://www.ietf.org/rfc/rfc3986.txt
- if
- (byte >= 97 && byte <= 122) # lowercase ASCII
- || (byte >= 65 && byte <= 90) # uppercase ASCII
- || (byte >= 48 && byte <= 57) # digit
- then
- # This is the most common case: an unreserved character,
- # which needs no encoding in a path
- List.append output byte
- else
- when byte is
- 46 # '.'
- | 95 # '_'
- | 126 # '~'
- | 150 -> # '-'
- # These special characters can all be unescaped in paths
- List.append output byte
-
- _ ->
- # This needs encoding in a path
- suffix =
- Str.toUtf8 percent_encoded
- |> List.sublist { len: 3, start: 3 * Num.intCast byte }
-
- List.concat output suffix
-
- Str.fromUtf8 answer
- |> Result.withDefault "" # This should never fail
+ List.walk(
+ Str.to_utf8(input),
+ initial_output,
+ \output, byte ->
+ # Spec for percent-encoding: https://www.ietf.org/rfc/rfc3986.txt
+ if
+ (byte >= 97 && byte <= 122) # lowercase ASCII
+ || (byte >= 65 && byte <= 90) # uppercase ASCII
+ || (byte >= 48 && byte <= 57) # digit
+ then
+ # This is the most common case: an unreserved character,
+ # which needs no encoding in a path
+ List.append(output, byte)
+ else
+ when byte is
+ 46 # '.'
+ | 95 # '_'
+ | 126 # '~'
+ | 150 -> # '-'
+ # These special characters can all be unescaped in paths
+ List.append(output, byte)
+
+ _ ->
+ # This needs encoding in a path
+ suffix =
+ Str.to_utf8(percent_encoded)
+ |> List.sublist({ len: 3, start: 3 * Num.int_cast(byte) })
+
+ List.concat(output, suffix),
+ )
+
+ Str.from_utf8(answer)
+ |> Result.with_default("") # This should never fail
## Adds a [Str] query parameter to the end of the [Url].
##
@@ -232,49 +237,49 @@ percent_encode = \input ->
##
## ```
## # Gives https://example.com?email=someone%40example.com
-## Url.from_str "https://example.com"
-## |> Url.append_param "email" "someone@example.com"
+## Url.from_str("https://example.com")
+## |> Url.append_param("email", "someone@example.com")
## ```
##
## This can be called multiple times on the same URL.
##
## ```
## # Gives https://example.com?caf%C3%A9=du%20Monde&email=hi%40example.com
-## Url.from_str "https://example.com"
-## |> Url.append_param "café" "du Monde"
-## |> Url.append_param "email" "hi@example.com"
+## Url.from_str("https://example.com")
+## |> Url.append_param("café", "du Monde")
+## |> Url.append_param("email", "hi@example.com")
## ```
##
append_param : Url, Str, Str -> Url
-append_param = \@Url url_str, key, value ->
+append_param = \@Url(url_str), key, value ->
{ without_fragment, after_query } =
- when Str.splitLast url_str "#" is
- Ok { before, after } ->
+ when Str.split_last(url_str, "#") is
+ Ok({ before, after }) ->
# The fragment is almost certainly going to be a small string,
# so this interpolation should happen on the stack.
{ without_fragment: before, after_query: "#$(after)" }
- Err NotFound ->
+ Err(NotFound) ->
{ without_fragment: url_str, after_query: "" }
- encoded_key = percent_encode key
- encoded_value = percent_encode value
+ encoded_key = percent_encode(key)
+ encoded_value = percent_encode(value)
bytes =
- Str.countUtf8Bytes without_fragment
+ Str.count_utf8_bytes(without_fragment)
+ 1 # for "?" or "&"
- + Str.countUtf8Bytes encoded_key
+ + Str.count_utf8_bytes(encoded_key)
+ 1 # for "="
- + Str.countUtf8Bytes encoded_value
- + Str.countUtf8Bytes after_query
+ + Str.count_utf8_bytes(encoded_value)
+ + Str.count_utf8_bytes(after_query)
without_fragment
- |> Str.reserve bytes
- |> Str.concat (if has_query (@Url without_fragment) then "&" else "?")
- |> Str.concat encoded_key
- |> Str.concat "="
- |> Str.concat encoded_value
- |> Str.concat after_query
+ |> Str.reserve(bytes)
+ |> Str.concat((if has_query(@Url(without_fragment)) then "&" else "?"))
+ |> Str.concat(encoded_key)
+ |> Str.concat("=")
+ |> Str.concat(encoded_value)
+ |> Str.concat(after_query)
|> @Url
## Replaces the URL's [query](https://en.wikipedia.org/wiki/URL#Syntax)—the part
@@ -284,44 +289,44 @@ append_param = \@Url url_str, key, value ->
##
## ```
## # Gives https://example.com?newQuery=thisRightHere#stuff
-## Url.from_str "https://example.com?key1=val1&key2=val2#stuff"
-## |> Url.with_query "newQuery=thisRightHere"
+## Url.from_str("https://example.com?key1=val1&key2=val2#stuff")
+## |> Url.with_query("newQuery=thisRightHere")
##
## # Gives https://example.com#stuff
-## Url.from_str "https://example.com?key1=val1&key2=val2#stuff"
-## |> Url.with_query ""
+## Url.from_str("https://example.com?key1=val1&key2=val2#stuff")
+## |> Url.with_query("")
## ```
with_query : Url, Str -> Url
-with_query = \@Url url_str, query_str ->
+with_query = \@Url(url_str), query_str ->
{ without_fragment, after_query } =
- when Str.splitLast url_str "#" is
- Ok { before, after } ->
+ when Str.split_last(url_str, "#") is
+ Ok({ before, after }) ->
# The fragment is almost certainly going to be a small string,
# so this interpolation should happen on the stack.
{ without_fragment: before, after_query: "#$(after)" }
- Err NotFound ->
+ Err(NotFound) ->
{ without_fragment: url_str, after_query: "" }
before_query =
- when Str.splitLast without_fragment "?" is
- Ok { before } -> before
- Err NotFound -> without_fragment
+ when Str.split_last(without_fragment, "?") is
+ Ok({ before }) -> before
+ Err(NotFound) -> without_fragment
- if Str.isEmpty query_str then
- @Url (Str.concat before_query after_query)
+ if Str.is_empty(query_str) then
+ @Url(Str.concat(before_query, after_query))
else
bytes =
- Str.countUtf8Bytes before_query
+ Str.count_utf8_bytes(before_query)
+ 1 # for "?"
- + Str.countUtf8Bytes query_str
- + Str.countUtf8Bytes after_query
+ + Str.count_utf8_bytes(query_str)
+ + Str.count_utf8_bytes(after_query)
before_query
- |> Str.reserve bytes
- |> Str.concat "?"
- |> Str.concat query_str
- |> Str.concat after_query
+ |> Str.reserve(bytes)
+ |> Str.concat("?")
+ |> Str.concat(query_str)
+ |> Str.concat(after_query)
|> @Url
## Returns the URL's [query](https://en.wikipedia.org/wiki/URL#Syntax)—the part after
@@ -331,40 +336,40 @@ with_query = \@Url url_str, query_str ->
##
## ```
## # Gives "key1=val1&key2=val2&key3=val3"
-## Url.from_str "https://example.com?key1=val1&key2=val2&key3=val3#stuff"
+## Url.from_str("https://example.com?key1=val1&key2=val2&key3=val3#stuff")
## |> Url.query
##
## # Gives ""
-## Url.from_str "https://example.com#stuff"
+## Url.from_str("https://example.com#stuff")
## |> Url.query
## ```
##
query : Url -> Str
-query = \@Url url_str ->
+query = \@Url(url_str) ->
without_fragment =
- when Str.splitLast url_str "#" is
- Ok { before } -> before
- Err NotFound -> url_str
+ when Str.split_last(url_str, "#") is
+ Ok({ before }) -> before
+ Err(NotFound) -> url_str
- when Str.splitLast without_fragment "?" is
- Ok { after } -> after
- Err NotFound -> ""
+ when Str.split_last(without_fragment, "?") is
+ Ok({ after }) -> after
+ Err(NotFound) -> ""
## Returns [Bool.true] if the URL has a `?` in it.
##
## ```
## # Gives Bool.true
-## Url.from_str "https://example.com?key=value#stuff"
+## Url.from_str("https://example.com?key=value#stuff")
## |> Url.has_query
##
## # Gives Bool.false
-## Url.from_str "https://example.com#stuff"
+## Url.from_str("https://example.com#stuff")
## |> Url.has_query
## ```
##
has_query : Url -> Bool
-has_query = \@Url url_str ->
- Str.contains url_str "?"
+has_query = \@Url(url_str) ->
+ Str.contains(url_str, "?")
## Returns the URL's [fragment](https://en.wikipedia.org/wiki/URL#Syntax)—the part after
## the `#`, if it has one.
@@ -373,19 +378,19 @@ has_query = \@Url url_str ->
##
## ```
## # Gives "stuff"
-## Url.from_str "https://example.com#stuff"
+## Url.from_str("https://example.com#stuff")
## |> Url.fragment
##
## # Gives ""
-## Url.from_str "https://example.com"
+## Url.from_str("https://example.com")
## |> Url.fragment
## ```
##
fragment : Url -> Str
-fragment = \@Url url_str ->
- when Str.splitLast url_str "#" is
- Ok { after } -> after
- Err NotFound -> ""
+fragment = \@Url(url_str) ->
+ when Str.split_last(url_str, "#") is
+ Ok({ after }) -> after
+ Err(NotFound) -> ""
## Replaces the URL's [fragment](https://en.wikipedia.org/wiki/URL#Syntax).
##
@@ -393,52 +398,52 @@ fragment = \@Url url_str ->
##
## ```
## # Gives https://example.com#things
-## Url.from_str "https://example.com#stuff"
-## |> Url.with_fragment "things"
+## Url.from_str("https://example.com#stuff")
+## |> Url.with_fragment("things")
##
## # Gives https://example.com#things
-## Url.from_str "https://example.com"
-## |> Url.with_fragment "things"
+## Url.from_str("https://example.com")
+## |> Url.with_fragment("things")
##
## # Gives https://example.com
-## Url.from_str "https://example.com#stuff"
+## Url.from_str("https://example.com#stuff")
## |> Url.with_fragment ""
## ```
##
with_fragment : Url, Str -> Url
-with_fragment = \@Url url_str, fragment_str ->
- when Str.splitLast url_str "#" is
- Ok { before } ->
- if Str.isEmpty fragment_str then
+with_fragment = \@Url(url_str), fragment_str ->
+ when Str.split_last(url_str, "#") is
+ Ok({ before }) ->
+ if Str.is_empty(fragment_str) then
# If the given fragment is empty, remove the URL's fragment
- @Url before
+ @Url(before)
else
# Replace the URL's old fragment with this one, discarding `after`
- @Url "$(before)#$(fragment_str)"
+ @Url("$(before)#$(fragment_str)")
- Err NotFound ->
- if Str.isEmpty fragment_str then
+ Err(NotFound) ->
+ if Str.is_empty(fragment_str) then
# If the given fragment is empty, leave the URL as having no fragment
- @Url url_str
+ @Url(url_str)
else
# The URL didn't have a fragment, so give it this one
- @Url "$(url_str)#$(fragment_str)"
+ @Url("$(url_str)#$(fragment_str)")
## Returns [Bool.true] if the URL has a `#` in it.
##
## ```
## # Gives Bool.true
-## Url.from_str "https://example.com?key=value#stuff"
+## Url.from_str("https://example.com?key=value#stuff")
## |> Url.has_fragment
##
## # Gives Bool.false
-## Url.from_str "https://example.com?key=value"
+## Url.from_str("https://example.com?key=value")
## |> Url.has_fragment
## ```
##
has_fragment : Url -> Bool
-has_fragment = \@Url url_str ->
- Str.contains url_str "#"
+has_fragment = \@Url(url_str) ->
+ Str.contains(url_str, "#")
# Adapted from the percent-encoding crate, © The rust-url developers, Apache2-licensed
#
@@ -448,9 +453,50 @@ percent_encoded = "%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%
query_params : Url -> Dict Str Str
query_params = \url ->
- query url
- |> Str.splitOn "&"
- |> List.walk (Dict.empty {}) \dict, pair ->
- when Str.splitFirst pair "=" is
- Ok { before, after } -> Dict.insert dict before after
- Err NotFound -> Dict.insert dict pair ""
+ query(url)
+ |> Str.split_on("&")
+ |> List.walk(
+ Dict.empty({}),
+ \dict, pair ->
+ when Str.split_first(pair, "=") is
+ Ok({ before, after }) -> Dict.insert(dict, before, after)
+ Err(NotFound) -> Dict.insert(dict, pair, ""),
+ )
+
+## Returns the URL's [path](https://en.wikipedia.org/wiki/URL#Syntax)—the part after
+## the scheme and authority (e.g. `https://`) but before any `?` or `#` it might have.
+##
+## Returns `""` if the URL has no path.
+##
+## ```
+## # Gives "example.com/"
+## Url.fromStr("https://example.com/?key1=val1&key2=val2&key3=val3#stuff")
+## |> Url.path
+## ```
+##
+## ```
+## # Gives "/foo/"
+## Url.fromStr("/foo/?key1=val1&key2=val2&key3=val3#stuff")
+## |> Url.path
+## ```
+path : Url -> Str
+path = \@Url urlStr ->
+ withoutAuthority =
+ when Str.split_first urlStr ":" is
+ Ok { after } ->
+ when Str.split_first after "//" is
+ # Only drop the `//` if it's right after the `://` like in `https://`
+ # (so, `before` is empty) - otherwise, the `//` is part of the path!
+ Ok { before, after: afterSlashes } if Str.is_empty before -> afterSlashes
+ _ -> after
+
+ # There's no `//` and also no `:` so this must be a path-only URL, e.g. "/foo?bar=baz#blah"
+ Err NotFound -> urlStr
+
+ # Drop the query and/or fragment
+ when Str.split_last withoutAuthority "?" is
+ Ok { before } -> before
+ Err NotFound ->
+ when Str.split_last withoutAuthority "#" is
+ Ok { before } -> before
+ Err NotFound -> withoutAuthority
diff --git a/platform/Utc.roc b/platform/Utc.roc
index 9415b405..7703d193 100644
--- a/platform/Utc.roc
+++ b/platform/Utc.roc
@@ -19,24 +19,24 @@ Utc := I128 implements [Inspect]
## Duration since UNIX EPOCH
now! : {} => Utc
now! = \{} ->
- @Utc (Num.toI128 (Host.posix_time! {}))
+ @Utc(Num.to_i128(Host.posix_time!({})))
# Constant number of nanoseconds in a millisecond
nanos_per_milli = 1_000_000
## Convert Utc timestamp to milliseconds
to_millis_since_epoch : Utc -> I128
-to_millis_since_epoch = \@Utc nanos ->
+to_millis_since_epoch = \@Utc(nanos) ->
nanos // nanos_per_milli
## Convert milliseconds to Utc timestamp
from_millis_since_epoch : I128 -> Utc
from_millis_since_epoch = \millis ->
- @Utc (millis * nanos_per_milli)
+ @Utc((millis * nanos_per_milli))
## Convert Utc timestamp to nanoseconds
to_nanos_since_epoch : Utc -> I128
-to_nanos_since_epoch = \@Utc nanos ->
+to_nanos_since_epoch = \@Utc(nanos) ->
nanos
## Convert nanoseconds to Utc timestamp
@@ -46,34 +46,34 @@ from_nanos_since_epoch = @Utc
## Calculate milliseconds between two Utc timestamps
delta_as_millis : Utc, Utc -> U128
delta_as_millis = \utc_a, utc_b ->
- (delta_as_nanos utc_a utc_b) // nanos_per_milli
+ (delta_as_nanos(utc_a, utc_b)) // nanos_per_milli
## Calculate nanoseconds between two Utc timestamps
delta_as_nanos : Utc, Utc -> U128
-delta_as_nanos = \@Utc nanos_a, @Utc nanos_b ->
+delta_as_nanos = \@Utc(nanos_a), @Utc(nanos_b) ->
# bitwiseXor for best performance
- nanos_a_shifted = Num.bitwiseXor (Num.toU128 nanos_a) (Num.shiftLeftBy 1 127)
- nanos_b_shifted = Num.bitwiseXor (Num.toU128 nanos_b) (Num.shiftLeftBy 1 127)
+ nanos_a_shifted = Num.bitwise_xor(Num.to_u128(nanos_a), Num.shift_left_by(1, 127))
+ nanos_b_shifted = Num.bitwise_xor(Num.to_u128(nanos_b), Num.shift_left_by(1, 127))
- Num.absDiff nanos_a_shifted nanos_b_shifted
+ Num.abs_diff(nanos_a_shifted, nanos_b_shifted)
## Convert Utc timestamp to ISO 8601 string
## Example: 2023-11-14T23:39:39Z
to_iso_8601 : Utc -> Str
-to_iso_8601 = \@Utc nanos ->
+to_iso_8601 = \@Utc(nanos) ->
nanos
- |> Num.divTrunc nanos_per_milli
+ |> Num.div_trunc(nanos_per_milli)
|> InternalDateTime.epoch_millis_to_datetime
|> InternalDateTime.to_iso_8601
# TESTS
-expect delta_as_nanos (from_nanos_since_epoch 0) (from_nanos_since_epoch 0) == 0
-expect delta_as_nanos (from_nanos_since_epoch 1) (from_nanos_since_epoch 2) == 1
-expect delta_as_nanos (from_nanos_since_epoch -1) (from_nanos_since_epoch 1) == 2
-expect delta_as_nanos (from_nanos_since_epoch Num.minI128) (from_nanos_since_epoch Num.maxI128) == Num.maxU128
+expect delta_as_nanos(from_nanos_since_epoch(0), from_nanos_since_epoch(0)) == 0
+expect delta_as_nanos(from_nanos_since_epoch(1), from_nanos_since_epoch(2)) == 1
+expect delta_as_nanos(from_nanos_since_epoch(-1), from_nanos_since_epoch(1)) == 2
+expect delta_as_nanos(from_nanos_since_epoch(Num.min_i128), from_nanos_since_epoch(Num.max_i128)) == Num.max_u128
-expect delta_as_millis (from_millis_since_epoch 0) (from_millis_since_epoch 0) == 0
-expect delta_as_millis (from_nanos_since_epoch 1) (from_nanos_since_epoch 2) == 0
-expect delta_as_millis (from_millis_since_epoch 1) (from_millis_since_epoch 2) == 1
-expect delta_as_millis (from_millis_since_epoch -1) (from_millis_since_epoch 1) == 2
-expect delta_as_millis (from_nanos_since_epoch Num.minI128) (from_nanos_since_epoch Num.maxI128) == Num.maxU128 // nanos_per_milli
+expect delta_as_millis(from_millis_since_epoch(0), from_millis_since_epoch(0)) == 0
+expect delta_as_millis(from_nanos_since_epoch(1), from_nanos_since_epoch(2)) == 0
+expect delta_as_millis(from_millis_since_epoch(1), from_millis_since_epoch(2)) == 1
+expect delta_as_millis(from_millis_since_epoch(-1), from_millis_since_epoch(1)) == 2
+expect delta_as_millis(from_nanos_since_epoch(Num.min_i128), from_nanos_since_epoch(Num.max_i128)) == Num.max_u128 // nanos_per_milli
diff --git a/platform/glue-internal-arg.roc b/platform/glue-internal-arg.roc
index 010cad8f..b4ff8a02 100644
--- a/platform/glue-internal-arg.roc
+++ b/platform/glue-internal-arg.roc
@@ -12,9 +12,9 @@ platform "glue-types"
exposes []
packages {}
imports []
- provides [mainForHost]
+ provides [main_for_host]
import InternalArg
-mainForHost : InternalArg.ArgToAndFromHost
-mainForHost = main
+main_for_host : InternalArg.ArgToAndFromHost
+main_for_host = main
diff --git a/platform/glue-internal-cmd.roc b/platform/glue-internal-cmd.roc
index ad9d8696..4a113622 100644
--- a/platform/glue-internal-cmd.roc
+++ b/platform/glue-internal-cmd.roc
@@ -12,9 +12,9 @@ platform "glue-types"
exposes []
packages {}
imports []
- provides [mainForHost]
+ provides [main_for_host]
import InternalCmd
-mainForHost : InternalCmd.OutputFromHost
-mainForHost = main
+main_for_host : InternalCmd.OutputFromHost
+main_for_host = main
diff --git a/platform/glue-internal-http.roc b/platform/glue-internal-http.roc
index f0285ee4..6505bbef 100644
--- a/platform/glue-internal-http.roc
+++ b/platform/glue-internal-http.roc
@@ -12,12 +12,12 @@ platform "glue-types"
exposes []
packages {}
imports []
- provides [mainForHost]
+ provides [main_for_host]
import InternalHttp
-mainForHost : {
+main_for_host : {
a : InternalHttp.RequestToAndFromHost,
b : InternalHttp.ResponseToAndFromHost,
}
-mainForHost = main
+main_for_host = main
diff --git a/platform/libapp.roc b/platform/libapp.roc
index 52874983..64972aae 100644
--- a/platform/libapp.roc
+++ b/platform/libapp.roc
@@ -3,4 +3,4 @@ app [main!] { pf: platform "main.roc" }
# Throw an error here so we can easily confirm the host
# executable built correctly just by running it.
main! : _ => Result {} [Exit I32 Str]_
-main! = \_ -> Err JustAStub
+main! = \_ -> Err(JustAStub)
diff --git a/platform/main.roc b/platform/main.roc
index 4d096bbb..e57ed198 100644
--- a/platform/main.roc
+++ b/platform/main.roc
@@ -33,26 +33,26 @@ main_for_host! = \raw_args ->
args =
raw_args
- |> List.map InternalArg.to_os_raw
- |> List.map Arg.from_os_raw
+ |> List.map(InternalArg.to_os_raw)
+ |> List.map(Arg.from_os_raw)
- when main! args is
- Ok {} -> 0
- Err (Exit code msg) ->
- if Str.isEmpty msg then
+ when main!(args) is
+ Ok({}) -> 0
+ Err(Exit(code, msg)) ->
+ if Str.is_empty(msg) then
code
else
- _ = Stderr.line! msg
+ _ = Stderr.line!(msg)
code
- Err msg ->
+ Err(msg) ->
help_msg =
"""
Program exited with error:
- $(Inspect.toStr msg)
+ $(Inspect.to_str(msg))
- Tip: If you do not want to exit on this error, use `Result.mapErr` to handle the error. Docs for `Result.mapErr`:
+ Tip: If you do not want to exit on this error, use `Result.map_err` to handle the error. Docs for `Result.map_err`:
"""
- _ = Stderr.line! help_msg
+ _ = Stderr.line!(help_msg)
1