diff --git a/.github/workflows/generate-docs.yaml b/.github/workflows/generate-docs.yaml index 73be7ea..1c11abd 100644 --- a/.github/workflows/generate-docs.yaml +++ b/.github/workflows/generate-docs.yaml @@ -20,6 +20,7 @@ jobs: uses: hasnep/setup-roc@main with: roc-version: nightly + testing: "true" - name: Generate docs run: roc docs platform/main.roc - name: Fix absolute paths diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index f0d2756..c134973 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -7,71 +7,53 @@ concurrency: cancel-in-progress: true jobs: - test-examples-linux: - runs-on: ubuntu-latest - env: - ROC_VERSION: nightly + build-and-test-native: + runs-on: ${{ matrix.operating-system }} + strategy: + fail-fast: false + matrix: + include: + - operating-system: ubuntu-20.04 + roc-nightly-release: roc_nightly-linux_x86_64-latest.tar.gz + roc-testing-release: roc_nightly-linux_x86_64-TESTING.tar.gz + - operating-system: ubuntu-22.04 + roc-nightly-release: roc_nightly-linux_x86_64-latest.tar.gz + roc-testing-release: roc_nightly-linux_x86_64-TESTING.tar.gz + - operating-system: macos-13 + roc-nightly-release: roc_nightly-macos_x86_64-latest.tar.gz + roc-testing-release: roc_nightly-macos_x86_64-TESTING.tar.gz + - operating-system: macos-14 + roc-nightly-release: roc_nightly-macos_apple_silicon-latest.tar.gz + roc-testing-release: roc_nightly-macos_apple_silicon-TESTING.tar.gz steps: - - name: Checkout code - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Update apt-get - run: sudo apt-get update + - name: install z3 for macOS + if: runner.os == 'macOS' + run: brew install z3 - - name: Install Build Essentials - run: sudo apt install build-essential git + - id: try_fetching_testing_release + name: try TESTING release + continue-on-error: true + run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/${{ matrix.roc-testing-release }} - - name: Install Rust and Cargo - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - source $HOME/.cargo/env + - name: fetch NIGHTLY release + if: steps.try_fetching_testing_release.outcome == 'failure' + run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/${{ matrix.roc-nightly-release }} - - name: Install ROC - run: | - # Install ROC - curl -fOL https://github.com/roc-lang/roc/releases/download/${ROC_VERSION}/roc_nightly-linux_x86_64-latest.tar.gz - mv $(ls | grep "roc_nightly.*tar\.gz") roc_nightly.tar.gz - tar -xzf roc_nightly.tar.gz - rm roc_nightly.tar.gz - mv roc_nightly* roc_nightly + - name: rename nightly tar + run: mv $(ls | grep "roc_nightly.*tar\.gz") roc_nightly.tar.gz - - name: Check ROC version - run: ./roc_nightly/roc version - - - name: Run all tests - run: ROC=./roc_nightly/roc ./ci/all_tests.sh - - test-examples-macos: - runs-on: macos-latest - env: - ROC_VERSION: nightly - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Build Essentials - run: brew install automake autoconf libtool - - - name: Install Rust and Cargo - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - source $HOME/.cargo/env + - name: decompress the tar + run: tar -xzf roc_nightly.tar.gz - - name: Export Homebrew paths for roc - run: | - brew install z3 zstd - export LIBRARY_PATH="/opt/homebrew/lib:$LIBRARY_PATH" + - name: remove tar + run: rm roc_nightly.tar.gz - - name: Install ROC - run: | - # Install ROC - curl -fOL https://github.com/roc-lang/roc/releases/download/${ROC_VERSION}/roc_nightly-macos_apple_silicon-latest.tar.gz - mv $(ls | grep "roc_nightly.*tar\.gz") roc_nightly.tar.gz - tar -xzf roc_nightly.tar.gz - rm roc_nightly.tar.gz - mv roc_nightly* roc_nightly + - name: simplify nightly folder name + run: mv roc_nightly* roc_nightly - - name: Check ROC version + - name: Check roc version run: ./roc_nightly/roc version - name: Run all tests diff --git a/.gitignore b/.gitignore index 26f77ca..9a40700 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ target/ platform/*.a platform/*.lib platform/*.tar.br +platform/*.tar.gz platform/*.lib # examples diff --git a/Cargo.lock b/Cargo.lock index 5a9ccf3..b251439 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.0" @@ -50,27 +41,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -109,9 +79,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bitmaps" @@ -140,43 +110,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" -[[package]] -name = "bytes" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" - -[[package]] -name = "cc" -version = "1.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" -dependencies = [ - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - [[package]] name = "crc32fast" version = "1.4.2" @@ -239,56 +178,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "hashbrown" version = "0.14.5" @@ -324,78 +213,6 @@ dependencies = [ "utf8-width", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.4.10", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http", - "hyper", - "rustls", - "rustls-native-certs", - "tokio", - "tokio-rustls", -] - [[package]] name = "im" version = "15.1.0" @@ -426,9 +243,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -442,9 +259,9 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "linked-hash-map" @@ -469,70 +286,32 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", ] -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "object" -version = "0.36.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "plist" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ - "base64 0.22.1", + "base64", "indexmap", "quick-xml", "serde", @@ -547,9 +326,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -560,7 +339,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "memchr", "unicase", ] @@ -576,9 +355,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -633,25 +412,10 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.52.0", -] - [[package]] name = "roc_collections" version = "0.0.1" -source = "git+https://github.com/roc-lang/roc.git#c89dccb6f4e458904c396953a7a469b2a88a3666" +source = "git+https://github.com/roc-lang/roc.git#cf1cfefadbf16af21a74bbe16f1547f358ac9874" dependencies = [ "bitvec", "bumpalo", @@ -667,7 +431,7 @@ dependencies = [ [[package]] name = "roc_command" version = "0.0.1" -source = "git+https://github.com/roc-lang/basic-cli.git#bb7295ba1bafea2d1d2a2f5fe82740cb272b04b1" +source = "git+https://github.com/roc-lang/basic-cli.git#12b84550c8f183c3073af25465c9563774b66fa9" dependencies = [ "roc_io_error", "roc_std", @@ -676,7 +440,7 @@ dependencies = [ [[package]] name = "roc_env" version = "0.0.1" -source = "git+https://github.com/roc-lang/basic-cli.git#bb7295ba1bafea2d1d2a2f5fe82740cb272b04b1" +source = "git+https://github.com/roc-lang/basic-cli.git#12b84550c8f183c3073af25465c9563774b66fa9" dependencies = [ "roc_file", "roc_std", @@ -686,12 +450,12 @@ dependencies = [ [[package]] name = "roc_error_macros" version = "0.0.1" -source = "git+https://github.com/roc-lang/roc.git#c89dccb6f4e458904c396953a7a469b2a88a3666" +source = "git+https://github.com/roc-lang/roc.git#cf1cfefadbf16af21a74bbe16f1547f358ac9874" [[package]] name = "roc_file" version = "0.0.1" -source = "git+https://github.com/roc-lang/basic-cli.git#bb7295ba1bafea2d1d2a2f5fe82740cb272b04b1" +source = "git+https://github.com/roc-lang/basic-cli.git#12b84550c8f183c3073af25465c9563774b66fa9" dependencies = [ "memchr", "roc_io_error", @@ -702,7 +466,7 @@ dependencies = [ [[package]] name = "roc_highlight" version = "0.0.1" -source = "git+https://github.com/roc-lang/roc.git#c89dccb6f4e458904c396953a7a469b2a88a3666" +source = "git+https://github.com/roc-lang/roc.git#cf1cfefadbf16af21a74bbe16f1547f358ac9874" dependencies = [ "html-escape", "roc_parse", @@ -713,45 +477,25 @@ dependencies = [ name = "roc_host" version = "0.1.0" dependencies = [ - "hyper", - "hyper-rustls", "libc", "roc_command", "roc_env", "roc_file", - "roc_http", "roc_io_error", "roc_std", "roc_stdio", "ssg", - "tokio", -] - -[[package]] -name = "roc_http" -version = "0.0.1" -source = "git+https://github.com/roc-lang/basic-cli.git#bb7295ba1bafea2d1d2a2f5fe82740cb272b04b1" -dependencies = [ - "bytes", - "hyper", - "hyper-rustls", - "memchr", - "roc_file", - "roc_io_error", - "roc_std", - "roc_std_heap", - "tokio", ] [[package]] name = "roc_ident" version = "0.0.1" -source = "git+https://github.com/roc-lang/roc.git#c89dccb6f4e458904c396953a7a469b2a88a3666" +source = "git+https://github.com/roc-lang/roc.git#cf1cfefadbf16af21a74bbe16f1547f358ac9874" [[package]] name = "roc_io_error" version = "0.0.1" -source = "git+https://github.com/roc-lang/basic-cli.git#bb7295ba1bafea2d1d2a2f5fe82740cb272b04b1" +source = "git+https://github.com/roc-lang/basic-cli.git#12b84550c8f183c3073af25465c9563774b66fa9" dependencies = [ "roc_std", "roc_std_heap", @@ -760,7 +504,7 @@ dependencies = [ [[package]] name = "roc_module" version = "0.0.1" -source = "git+https://github.com/roc-lang/roc.git#c89dccb6f4e458904c396953a7a469b2a88a3666" +source = "git+https://github.com/roc-lang/roc.git#cf1cfefadbf16af21a74bbe16f1547f358ac9874" dependencies = [ "bumpalo", "roc_collections", @@ -773,7 +517,7 @@ dependencies = [ [[package]] name = "roc_parse" version = "0.0.1" -source = "git+https://github.com/roc-lang/roc.git#c89dccb6f4e458904c396953a7a469b2a88a3666" +source = "git+https://github.com/roc-lang/roc.git#cf1cfefadbf16af21a74bbe16f1547f358ac9874" dependencies = [ "bumpalo", "encode_unicode", @@ -787,7 +531,7 @@ dependencies = [ [[package]] name = "roc_region" version = "0.0.1" -source = "git+https://github.com/roc-lang/roc.git#c89dccb6f4e458904c396953a7a469b2a88a3666" +source = "git+https://github.com/roc-lang/roc.git#cf1cfefadbf16af21a74bbe16f1547f358ac9874" dependencies = [ "static_assertions", ] @@ -795,7 +539,7 @@ dependencies = [ [[package]] name = "roc_std" version = "0.0.1" -source = "git+https://github.com/roc-lang/roc.git#c89dccb6f4e458904c396953a7a469b2a88a3666" +source = "git+https://github.com/roc-lang/roc.git#cf1cfefadbf16af21a74bbe16f1547f358ac9874" dependencies = [ "arrayvec", "static_assertions", @@ -804,7 +548,7 @@ dependencies = [ [[package]] name = "roc_std_heap" version = "0.0.1" -source = "git+https://github.com/roc-lang/roc.git#c89dccb6f4e458904c396953a7a469b2a88a3666" +source = "git+https://github.com/roc-lang/roc.git#cf1cfefadbf16af21a74bbe16f1547f358ac9874" dependencies = [ "memmap2", "roc_std", @@ -813,60 +557,12 @@ dependencies = [ [[package]] name = "roc_stdio" version = "0.0.1" -source = "git+https://github.com/roc-lang/basic-cli.git#bb7295ba1bafea2d1d2a2f5fe82740cb272b04b1" +source = "git+https://github.com/roc-lang/basic-cli.git#12b84550c8f183c3073af25465c9563774b66fa9" dependencies = [ "roc_io_error", "roc_std", ] -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "ryu" version = "1.0.18" @@ -882,62 +578,20 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.6.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -946,9 +600,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", "memchr", @@ -956,12 +610,6 @@ dependencies = [ "serde", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "sized-chunks" version = "0.6.5" @@ -981,33 +629,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "soa" version = "0.0.1" -source = "git+https://github.com/roc-lang/roc.git#c89dccb6f4e458904c396953a7a469b2a88a3666" - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +source = "git+https://github.com/roc-lang/roc.git#cf1cfefadbf16af21a74bbe16f1547f358ac9874" [[package]] name = "ssg" @@ -1027,9 +649,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "2.0.90" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -1124,61 +746,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tokio" -version = "1.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" -dependencies = [ - "backtrace", - "libc", - "mio", - "pin-project-lite", - "socket2 0.5.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "typenum" version = "1.17.0" @@ -1187,21 +754,15 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" [[package]] name = "utf8-width" @@ -1225,21 +786,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - [[package]] name = "winapi" version = "0.3.9" @@ -1262,7 +808,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -1271,46 +817,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -1319,46 +832,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1371,48 +866,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/Cargo.toml b/Cargo.toml index c35adb3..4f833b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ roc_command = { git = "https://github.com/roc-lang/basic-cli.git" } roc_io_error = { git = "https://github.com/roc-lang/basic-cli.git" } roc_stdio = { git = "https://github.com/roc-lang/basic-cli.git" } roc_file = { git = "https://github.com/roc-lang/basic-cli.git" } -roc_http = { git = "https://github.com/roc-lang/basic-cli.git" } syntect = { version = "5.0", default-features = false, features = [ "default-fancy", ] } @@ -23,13 +22,3 @@ roc_highlight = { git = "https://github.com/roc-lang/roc.git", package = "roc_hi pulldown-cmark = { version = "0.9.2", default-features = false } libc = "0.2" ssg = { path = "crates/ssg" } -hyper = { version = "=0.14.27", default-features = false, features = [ - "http1", - "client", -] } -hyper-rustls = { version = "=0.24.2", default-features = false, features = [ - "http1", - "tls12", - "native-tokio", -] } -tokio = { version = "=1.31.0", default-features = false } diff --git a/README.md b/README.md index 45a0ce8..a6d115b 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,11 @@ app [main!] { pf: platform "" } import pf.SSG import pf.Types exposing [Args] import pf.Html exposing [div, link, text, a, html, head, body, meta, ul, li] -import pf.Html.Attributes exposing [class, httpEquiv, href, rel, content, lang, title] +import pf.Html.Attributes exposing [class, http_equiv, href, rel, content, lang, title] main! : Args => Result {} _ -main! = \{ inputDir, outputDir } -> - # ... use SSG.files!, SSG.parseMarkdown!, and SSG.writeFile! here to generate site +main! = \{ input_dir, output_dir } -> + # ... use SSG.files!, SSG.parse_markdown!, and SSG.write_file! here to generate site ``` ## Platform Development diff --git a/build.roc b/build.roc index 6298381..7fee2fd 100644 --- a/build.roc +++ b/build.roc @@ -1,78 +1,73 @@ -app [main] { - cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.17.0/lZFLstMUCUvd5bjnnpYromZJXkQUrdhbva4xdBInicE.tar.br", +app [main!] { + cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.19.0/bi5zubJ-_Hva9vxxPq4kNx4WHX6oFs8OP6Ad0tCYlrY.tar.br", + weaver: "https://github.com/smores56/weaver/releases/download/0.6.0/4GmRnyE7EFjzv6dDpebJoWWwXV285OMt4ntHIc6qvmY.tar.br", } import cli.Cmd import cli.Stdout import cli.Env import cli.Arg -import cli.Arg.Opt -import cli.Arg.Cli +import weaver.Cli +import weaver.Opt ## Builds the basic-ssg [platform](https://www.roc-lang.org/platforms). ## ## run with: roc ./build.roc --release ## -main : Task {} _ -main = +main! = |args| cli_parser = - { Arg.Cli.combine <- - release: Arg.Opt.flag { short: "r", long: "release", help: "DEBUG build native target only, or RELEASE build for all supported targets." }, - bundle: Arg.Opt.flag { short: "b", long: "bundle", help: "Bundle platform files into a package for distribution" }, - maybe_roc: Arg.Opt.maybeStr { short: "p", long: "roc", help: "Path to the roc executable. Can be just `roc` or a full path." }, + { Cli.weave <- + release: Opt.flag({ short: "r", long: "release", help: "DEBUG build native target only, or RELEASE build for all supported targets." }), + bundle: Opt.flag({ short: "b", long: "bundle", help: "Bundle platform files into a package for distribution" }), + roc: Opt.str({ short: "p", long: "roc", help: "Path to the roc executable. Can be just `roc` or a full path.", default: Value("roc") }), } - |> Arg.Cli.finish { - name: "basic-ssg-builder", - version: "", - authors: ["Luke Boswell "], - description: "Generates all files needed by Roc to use this basic-ssg platform.", - } - |> Arg.Cli.assertValid - - when Arg.Cli.parseOrDisplayMessage cli_parser (Arg.list! {}) is - Ok args -> run args - Err err_msg -> Task.err (Exit 1 err_msg) - -run : { release : Bool, bundle : Bool, maybe_roc : Result Str err } -> Task {} _ -run = \{ release, bundle, maybe_roc } -> - - roc = maybe_roc |> Result.withDefault "roc" + |> Cli.finish( + { + name: "basic-ssg-builder", + version: "", + authors: ["Luke Boswell "], + description: "Generates all files needed by Roc to use this basic-ssg platform.", + }, + ) + |> Cli.assert_valid + + { release, bundle, roc } = + Cli.parse_or_display_message(cli_parser, args, Arg.to_os_raw) ? |message| Err(Exit(1, message)) # target is MacosArm64, LinuxX64,... - info! "Getting the native target ..." - native_target = - Env.platform - |> Task.await! get_native_target + info!("Getting the native target ...")? - build_tasks = + native_target = get_native_target!(Env.platform!({}))? + + targets_to_build = if release then [ - build MacosArm64 RELEASE, - build MacosX64 RELEASE, - build LinuxArm64 RELEASE, - build LinuxX64 RELEASE, - build WindowsArm64 RELEASE, - build WindowsX64 RELEASE, + (MacosArm64, RELEASE), + (MacosX64, RELEASE), + (LinuxArm64, RELEASE), + (LinuxX64, RELEASE), + #(WindowsArm64, RELEASE), + #(WindowsX64, RELEASE), ] else [ - build native_target DEBUG, + (native_target, DEBUG), ] - _ = Task.sequence! build_tasks - - bundle_task = - if bundle then - info! "Bundling platform binaries ..." - roc - |> Cmd.exec ["build", "--bundle", ".tar.br", "platform/main.roc"] - |> Task.mapErr! ErrBundlingPlatform - else - Task.ok {} + List.for_each_try!( + targets_to_build, + |(target, opt_level)| + build!(target, opt_level), + )? - bundle_task! + if bundle then + info!("Bundling platform binaries ...")? + Cmd.exec!(roc, ["build", "--bundle", ".tar.br", "platform/main.roc"]) ? ErrBundlingPlatform + {} + else + {} - info! "Successfully completed building platform binaries." + info!("Successfully completed building platform binaries.") RocTarget : [ MacosArm64, @@ -84,7 +79,7 @@ RocTarget : [ ] roc_target : RocTarget -> Str -roc_target = \target -> +roc_target = |target| when target is MacosArm64 -> "macos-arm64" MacosX64 -> "macos-x64" @@ -94,19 +89,19 @@ roc_target = \target -> WindowsX64 -> "windows-x64" from_lib_path : RocTarget -> Str -from_lib_path = \target -> +from_lib_path = |target| when target is MacosArm64 | MacosX64 | LinuxArm64 | LinuxX64 -> "libhost.a" WindowsArm64 | WindowsX64 -> "host.lib" to_lib_path : RocTarget -> Str -to_lib_path = \target -> +to_lib_path = |target| when target is - MacosArm64 | MacosX64 | LinuxArm64 | LinuxX64 -> "$(roc_target target).a" - WindowsArm64 | WindowsX64 -> "$(roc_target target).lib" + MacosArm64 | MacosX64 | LinuxArm64 | LinuxX64 -> "${roc_target(target)}.a" + WindowsArm64 | WindowsX64 -> "${roc_target(target)}.lib" rustc_target : RocTarget -> Str -rustc_target = \target -> +rustc_target = |target| when target is MacosArm64 -> "aarch64-apple-darwin" MacosX64 -> "x86_64-apple-darwin" @@ -115,40 +110,38 @@ rustc_target = \target -> WindowsArm64 -> "aarch64-pc-windows-msvc" WindowsX64 -> "x86_64-pc-windows-msvc" -info : Str -> Task {} _ -info = \msg -> - Stdout.line! "\u(001b)[34mINFO:\u(001b)[0m $(msg)" +info! : Str => Result {} _ +info! = |msg| + Stdout.line!("\u(001b)[34mINFO:\u(001b)[0m ${msg}") -get_native_target : _ -> Task RocTarget _ -get_native_target = \{ os, arch } -> +get_native_target! : _ => Result _ _ +get_native_target! = |{ os, arch }| when (os, arch) is - (MACOS, AARCH64) -> Task.ok MacosArm64 - (MACOS, X64) -> Task.ok MacosX64 - (LINUX, AARCH64) -> Task.ok LinuxArm64 - (LINUX, X64) -> Task.ok LinuxX64 - _ -> Task.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 : RocTarget, [DEBUG, RELEASE] -> Task {} _ -build = \target, release_mode -> +build! : RocTarget, [DEBUG, RELEASE] => Result {} _ +build! = |target, release_mode| - target_str = rustc_target target + target_str = rustc_target(target) (release_mode_str, cargo_build_args) = when release_mode is - RELEASE -> ("release", ["build", "--release", "--target=$(target_str)"]) - DEBUG -> ("debug", ["build", "--target=$(target_str)"]) + RELEASE -> ("release", ["build", "--release", "--target=${target_str}"]) + DEBUG -> ("debug", ["build", "--target=${target_str}"]) + + info!("Building legacy binary for ${target_str} ...")? - info! "Building legacy binary for $(target_str) ..." + Cmd.exec!("cargo", cargo_build_args) ? |err| ErrBuildingLegacyBinary(target_str, err) - "cargo" - |> Cmd.exec cargo_build_args - |> Task.mapErr! \err -> ErrBuildingLegacyBinary target_str err + from = "target/${target_str}/${release_mode_str}/${from_lib_path(target)}" + to = "platform/${to_lib_path(target)}" - from = "target/$(target_str)/$(release_mode_str)/$(from_lib_path target)" - to = "platform/$(to_lib_path target)" + info!("Moving legacy binary from ${from} to ${to} ...")? - info! "Moving legacy binary from $(from) to $(to) ..." + Cmd.exec!("cp", [from, to]) ? |err| ErrMovingLegacyBinary(target_str, err) - "cp" - |> Cmd.exec [from, to] - |> Task.mapErr! \err -> ErrMovingLegacyBinary target_str err + Ok({}) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index 004f962..ca9f103 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -6,6 +6,7 @@ set -euxo pipefail if [ -z "${ROC:-}" ]; then echo "INFO: The ROC environment variable is not set." export ROC=$(which roc) + echo "INFO: defaulting ROC to use $ROC" fi if [ -z "${CARGO:-}" ]; then @@ -24,14 +25,8 @@ rm -rf target/ find . -name "*.a" -delete find . -name "*.tar.br" -delete -echo "Build the platform for native" -$CARGO build - -echo "Copy prebuilt artifact to platform/ NOTE the hack for all platforms DO NOT COPY THIS" -cp target/debug/libhost.a platform/macos-arm64.a -cp target/debug/libhost.a platform/linux-arm64.a -cp target/debug/libhost.a platform/linux-x64.a -cp target/debug/libhost.a platform/macos-x64.a +echo "Build the platform" +$ROC build.roc echo "run the example" $ROC --linker=legacy ./example/main.roc -- ./example/content/ ./example/www/ diff --git a/crates/roc_host/Cargo.toml b/crates/roc_host/Cargo.toml index d5e7771..0917cb0 100644 --- a/crates/roc_host/Cargo.toml +++ b/crates/roc_host/Cargo.toml @@ -12,7 +12,3 @@ roc_command.workspace = true roc_io_error.workspace = true roc_stdio.workspace = true roc_file.workspace = true -roc_http.workspace = true -hyper.workspace = true -hyper-rustls.workspace = true -tokio.workspace = true diff --git a/crates/roc_host/src/lib.rs b/crates/roc_host/src/lib.rs index c35b597..ce24187 100644 --- a/crates/roc_host/src/lib.rs +++ b/crates/roc_host/src/lib.rs @@ -1,16 +1,6 @@ use core::ffi::c_void; -use roc_std::{RocBox, RocList, RocResult, RocStr}; +use roc_std::{RocList, RocResult, RocStr}; use std::path::PathBuf; -use std::time::Duration; -use tokio::runtime::Runtime; - -thread_local! { - static TOKIO_RUNTIME: Runtime = tokio::runtime::Builder::new_current_thread() - .enable_io() - .enable_time() - .build() - .unwrap(); -} /// # Safety /// @@ -132,12 +122,6 @@ pub fn init() { roc_fx_get_locale as _, roc_fx_get_locales as _, roc_fx_posix_time as _, - roc_fx_send_request as _, - roc_fx_tcp_connect as _, - roc_fx_tcp_read_up_to as _, - roc_fx_tcp_read_exactly as _, - roc_fx_tcp_read_until as _, - roc_fx_tcp_write as _, ]; #[allow(forgetting_references)] @@ -290,122 +274,3 @@ pub extern "C" fn roc_fx_get_locales() -> RocList { pub extern "C" fn roc_fx_posix_time() -> roc_std::U128 { roc_env::posix_time() } - -#[no_mangle] -pub extern "C" fn roc_fx_send_request( - roc_request: &roc_http::RequestToAndFromHost, -) -> roc_http::ResponseToAndFromHost { - TOKIO_RUNTIME.with(|rt| { - let request = match roc_request.to_hyper_request() { - Ok(r) => r, - Err(err) => return err.into(), - }; - - match roc_request.has_timeout() { - Some(time_limit) => rt - .block_on(async { - tokio::time::timeout( - Duration::from_millis(time_limit), - async_send_request(request), - ) - .await - }) - .unwrap_or_else(|_err| roc_http::ResponseToAndFromHost { - status: 408, - headers: RocList::empty(), - body: "Request Timeout".as_bytes().into(), - }), - None => rt.block_on(async_send_request(request)), - } - }) -} - -async fn async_send_request(request: hyper::Request) -> roc_http::ResponseToAndFromHost { - use hyper::Client; - use hyper_rustls::HttpsConnectorBuilder; - - let https = HttpsConnectorBuilder::new() - .with_native_roots() - .https_or_http() - .enable_http1() - .build(); - - let client: Client<_, String> = Client::builder().build(https); - let res = client.request(request).await; - - match res { - Ok(response) => { - let status = response.status(); - - let headers = RocList::from_iter(response.headers().iter().map(|(name, value)| { - roc_http::Header::new(name.as_str(), value.to_str().unwrap_or_default()) - })); - - let status = status.as_u16(); - - let bytes = hyper::body::to_bytes(response.into_body()).await.unwrap(); - let body: RocList = RocList::from_iter(bytes); - - roc_http::ResponseToAndFromHost { - body, - status, - headers, - } - } - Err(err) => { - if err.is_timeout() { - roc_http::ResponseToAndFromHost { - status: 408, - headers: RocList::empty(), - body: "Request Timeout".as_bytes().into(), - } - } else if err.is_connect() || err.is_closed() { - roc_http::ResponseToAndFromHost { - status: 500, - headers: RocList::empty(), - body: "Network Error".as_bytes().into(), - } - } else { - roc_http::ResponseToAndFromHost { - status: 500, - headers: RocList::empty(), - body: err.to_string().as_bytes().into(), - } - } - } - } -} - -#[no_mangle] -pub extern "C" fn roc_fx_tcp_connect(host: &RocStr, port: u16) -> RocResult, RocStr> { - roc_http::tcp_connect(host, port) -} - -#[no_mangle] -pub extern "C" fn roc_fx_tcp_read_up_to( - stream: RocBox<()>, - bytes_to_read: u64, -) -> RocResult, RocStr> { - roc_http::tcp_read_up_to(stream, bytes_to_read) -} - -#[no_mangle] -pub extern "C" fn roc_fx_tcp_read_exactly( - stream: RocBox<()>, - bytes_to_read: u64, -) -> RocResult, RocStr> { - roc_http::tcp_read_exactly(stream, bytes_to_read) -} - -#[no_mangle] -pub extern "C" fn roc_fx_tcp_read_until( - stream: RocBox<()>, - byte: u8, -) -> RocResult, RocStr> { - roc_http::tcp_read_until(stream, byte) -} - -#[no_mangle] -pub extern "C" fn roc_fx_tcp_write(stream: RocBox<()>, msg: &RocList) -> RocResult<(), RocStr> { - roc_http::tcp_write(stream, msg) -} diff --git a/example/content/fruit/codeExample.roc b/example/content/fruit/codeExample.roc index cf107ef..3b4b03d 100644 --- a/example/content/fruit/codeExample.roc +++ b/example/content/fruit/codeExample.roc @@ -1,9 +1,9 @@ ## This is a documentation comment # This is a comment -app [transformFileContent] { pf: platform "platform/main.roc" } +app [transform_file_content] { pf: platform "platform/main.roc" } import pf.Html exposing [html, head, body, div, text, a, ul, li, link, meta] -import pf.Html.Attributes exposing [httpEquiv, content, href, rel, lang, class, title] +import pf.Html.Attributes exposing [http_equiv, content, href, rel, lang, class, title] NavLink : { # this is another comment @@ -12,61 +12,87 @@ NavLink : { text : Str, } -navLinks : List NavLink -navLinks = [ +nav_links : List NavLink +nav_links = [ { url: "apple.html", title: "Exempli Gratia Pagina Pomi", text: "Apple" }, { url: "banana.html", title: "Exempli Gratia Pagina Musa", text: "Banana" }, { url: "cherry.html", title: "Exempli Pagina Cerasus", text: "Cherry" }, ] -transformFileContent : Str, Str -> Str -transformFileContent = \currentUrl, htmlContent -> - List.findFirst navLinks (\{ url } -> url == currentUrl) - |> Result.map (\currentNavLink -> view currentNavLink htmlContent) - |> Result.map Html.render - |> Result.withDefault "" +transform_file_content : Str, Str -> Str +transform_file_content = |current_url, html_content| + List.find_first(nav_links, |{ url }| url == current_url) + |> Result.map_ok(|current_nav_link| view(current_nav_link, html_content)) + |> Result.map_ok(Html.render) + |> Result.with_default("") ### start snippet view view : NavLink, Str -> Html.Node -view = \currentNavLink, htmlContent -> - html [lang "en"] [ - head [] [ - meta [httpEquiv "content-type", content "text/html; charset=utf-8"] [], - Html.title [] [text currentNavLink.title], - link [rel "stylesheet", href "style.css"] [], - ], - ### start snippet body - body [] [ - div [class "main"] [ - div [class "navbar"] [ - viewNavbar currentNavLink, +view = |current_nav_link, html_content| + html( + [lang("en")], + [ + head( + [], + [ + meta([http_equiv("content-type"), content("text/html; charset=utf-8")], []), + Html.title([], [text(current_nav_link.title)]), + link([rel("stylesheet"), href("style.css")], []), ], - div [class "article"] [ - # For now `text` is not escaped so we can use it to insert HTML - # We'll probably want something more explicit in the long term though! - text htmlContent, + ), + ### start snippet body + body( + [], + [ + div( + [class("main")], + [ + div( + [class("navbar")], + [ + view_navbar(current_nav_link), + ], + ), + div( + [class("article")], + [ + # For now `text` is not escaped so we can use it to insert HTML + # We'll probably want something more explicit in the long term though! + text(html_content), + ], + ), + ], + ), ], - ], + ), + ### end snippet body ], - ### end snippet body - ] + ) ### end snippet view -viewNavbar : NavLink -> Html.Node -viewNavbar = \currentNavLink -> - ul - [] - (List.map navLinks \nl -> viewNavLink (nl == currentNavLink) nl) +view_navbar : NavLink -> Html.Node +view_navbar = |current_nav_link| + ul( + [], + List.map(nav_links, |nl| view_nav_link((nl == current_nav_link), nl)), + ) -viewNavLink : Bool, NavLink -> Html.Node -viewNavLink = \isCurrent, navlink -> - if isCurrent then - li [class "nav-link nav-link--current"] [ - text navlink.text, - ] +view_nav_link : Bool, NavLink -> Html.Node +view_nav_link = |is_current, navlink| + if is_current then + li( + [class("nav-link nav-link--current")], + [ + text(navlink.text), + ], + ) else - li [class "nav-link"] [ - a - [href navlink.url, title navlink.title] - [text navlink.text], - ] + li( + [class("nav-link")], + [ + a( + [href(navlink.url), title(navlink.title)], + [text(navlink.text)], + ), + ], + ) diff --git a/example/main.roc b/example/main.roc index 62e4d02..4175c80 100644 --- a/example/main.roc +++ b/example/main.roc @@ -3,31 +3,31 @@ app [main!] { pf: platform "../platform/main.roc" } import pf.SSG import pf.Types exposing [Args] import pf.Html exposing [div, link, text, a, html, head, body, meta, ul, li] -import pf.Html.Attributes exposing [class, httpEquiv, href, rel, content, lang, title] +import pf.Html.Attributes exposing [class, http_equiv, href, rel, content, lang, title] main! : Args => Result {} _ -main! = \{ inputDir, outputDir } -> +main! = \{ input_dir, output_dir } -> # get the path and url of markdown files in content directory - files = SSG.files!? inputDir + files = SSG.files!(input_dir)? # helper Task to process each file process_file! = \{ path, relpath, url } -> - inHtml = SSG.parse_markdown!? path + in_html = SSG.parse_markdown!(path)? - outHtml = transform_file_content url inHtml + out_html = transform_file_content(url, in_html) - SSG.write_file! { outputDir, relpath, content: outHtml } + SSG.write_file!({ output_dir, relpath, content: out_html }) ## process each file - List.forEachTry! files process_file! + List.for_each_try!(files, process_file!) transform_file_content : Str, Str -> Str transform_file_content = \current_url, html_content -> - when List.findFirst nav_links (\{ url } -> url == current_url) is - Ok current_nav_link -> Html.render (view current_nav_link html_content) - Err _ -> crash "unable to find nav link for URL: $(current_url)" + when List.find_first(nav_links, \{ url } -> url == current_url) is + Ok(current_nav_link) -> Html.render(view(current_nav_link, html_content)) + Err(_) -> crash("unable to find nav link for URL: $(current_url)") NavLink : { url : Str, @@ -46,41 +46,43 @@ nav_links = [ view : NavLink, Str -> Html.Node view = \current_nav_link, html_content -> - html [lang "en"] [ - head [] [ - meta [httpEquiv "content-type", content "text/html; charset=utf-8"], - Html.title [] [text current_nav_link.title], - link [rel "stylesheet", href "/style.css"], - ], - body [] [ - div [class "main"] [ - div [class "navbar"] [ - view_navbar current_nav_link, - ], - div [class "article"] [ + html([lang("en")], [ + head([], [ + meta([http_equiv("content-type"), content("text/html; charset=utf-8")]), + Html.title([], [text(current_nav_link.title)]), + link([rel("stylesheet"), href("/style.css")]), + ]), + body([], [ + div([class("main")], [ + div([class("navbar")], [ + view_navbar(current_nav_link), + ]), + div([class("article")], [ # For now `text` is not escaped so we can use it to insert HTML # We'll probably want something more explicit in the long term though! - text html_content, - ], - ], - ], - ] + text(html_content), + ]), + ]), + ]), + ]) view_navbar : NavLink -> Html.Node view_navbar = \current_nav_link -> - ul - [] - (List.map nav_links \nl -> view_nav_link (nl == current_nav_link) nl) + ul( + [], + List.map(nav_links, \nl -> view_nav_link((nl == current_nav_link), nl)), + ) view_nav_link : Bool, NavLink -> Html.Node -view_nav_link = \isCurrent, navlink -> - if isCurrent then - li [class "nav-link nav-link--current"] [ - text navlink.text, - ] +view_nav_link = \is_current, navlink -> + if is_current then + li([class("nav-link nav-link--current")], [ + text(navlink.text), + ]) else - li [class "nav-link"] [ - a - [href navlink.url, title navlink.title] - [text navlink.text], - ] + li([class("nav-link")], [ + a( + [href(navlink.url), title(navlink.title)], + [text(navlink.text)], + ), + ]) diff --git a/example/run.sh b/example/run.sh old mode 100644 new mode 100755 index a70df28..395e7af --- a/example/run.sh +++ b/example/run.sh @@ -9,4 +9,4 @@ roc build --linker=legacy main.roc ./main content/ www/ -simple-http-server www/ +simple-http-server --index --open --ip 127.0.0.1 www/ diff --git a/flake.lock b/flake.lock index c958c29..2a9e97b 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1732722421, - "narHash": "sha256-HRJ/18p+WoXpWJkcdsk9St5ZiukCqSDgbOGFa8Okehg=", + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", "owner": "edolstra", "repo": "flake-compat", - "rev": "9ed2ac151eada2306ca8c418ebd97807bb08f6ac", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", "type": "github" }, "original": { @@ -102,11 +102,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1734463130, - "narHash": "sha256-y/8DmzG81mefYst0cleyguR2IdUNRW4pGc2zJnNLtGU=", + "lastModified": 1737745102, + "narHash": "sha256-y/e5SAV36ESCU1eKPtfn44Vyl/LFt2AkuDu8G0YhTKc=", "owner": "roc-lang", "repo": "roc", - "rev": "c89dccb6f4e458904c396953a7a469b2a88a3666", + "rev": "cf1cfefadbf16af21a74bbe16f1547f358ac9874", "type": "github" }, "original": { @@ -134,11 +134,11 @@ ] }, "locked": { - "lastModified": 1732802692, - "narHash": "sha256-kFrxb45qj52TT/OFUFyTdmvXkn/KXDUL0/DOtjHEQvs=", + "lastModified": 1736303309, + "narHash": "sha256-IKrk7RL+Q/2NC6+Ql6dwwCNZI6T6JH2grTdJaVWHF0A=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "34971069ec33755b2adf2481851f66d8ec9a6bfa", + "rev": "a0b81d4fa349d9af1765b0f0b4a899c13776f706", "type": "github" }, "original": { @@ -154,11 +154,11 @@ ] }, "locked": { - "lastModified": 1734402816, - "narHash": "sha256-cgQ8mjUJz7J3fp97lnvl0dSJ6vLt8yzUSmw3B7QKw94=", + "lastModified": 1737685583, + "narHash": "sha256-p+NVABRpGi+pT+xxf9HcLcFVxG6L+vEEy+NwzB9T0f8=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "e38fbd6e56e8cd1d61c65a21bbb7785e966707b4", + "rev": "eb64cbcc8eee0fa87ebded92805280d2ec97415a", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index ebd8aa7..28c9333 100644 --- a/flake.nix +++ b/flake.nix @@ -44,8 +44,8 @@ sharedInputs = (with pkgs; [ jq rust - llvmPkgs.clang - llvmPkgs.lldb # for debugging + # llvmPkgs.clang + # llvmPkgs.lldb # for debugging expect nmap simple-http-server diff --git a/platform/Cmd.roc b/platform/Cmd.roc index 701a17f..16b8e8d 100644 --- a/platform/Cmd.roc +++ b/platform/Cmd.roc @@ -24,81 +24,80 @@ 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, - } +new = |program| + @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, keyValues -> - values = keyValues |> 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 ## @@ -106,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 -> +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/Env.roc b/platform/Env.roc index e3d53a3..3652ec5 100644 --- a/platform/Env.roc +++ b/platform/Env.roc @@ -14,8 +14,8 @@ import Host ## [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. ## @@ -44,12 +44,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 varStr -> - Str.toUtf8 varStr - |> 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]. ## @@ -57,8 +57,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 ARCH : [X86, X64, ARM, AARCH64, OTHER Str] OS : [LINUX, MACOS, WINDOWS, OTHER Str] @@ -73,21 +73,21 @@ OS : [LINUX, MACOS, WINDOWS, OTHER Str] platform! : {} => { arch : ARCH, os : OS } platform! = \{} -> - fromRust = Host.current_arch_os! {} + from_rust = Host.current_arch_os!({}) arch = - when fromRust.arch is + when from_rust.arch is "x86" -> X86 "x86_64" -> X64 "arm" -> ARM "aarch64" -> AARCH64 - _ -> OTHER fromRust.arch + _ -> OTHER(from_rust.arch) os = - when fromRust.os is + when from_rust.os is "linux" -> LINUX "macos" -> MACOS "windows" -> WINDOWS - _ -> OTHER fromRust.os + _ -> OTHER(from_rust.os) { arch, os } diff --git a/platform/EnvDecoding.roc b/platform/EnvDecoding.roc index b80d91d..4d22ad1 100644 --- a/platform/EnvDecoding.roc +++ b/platform/EnvDecoding.roc @@ -5,102 +5,105 @@ module [ EnvFormat := {} implements [ DecoderFormatting { - u8: envU8, - u16: envU16, - u32: envU32, - u64: envU64, - u128: envU128, - i8: envI8, - i16: envI16, - i32: envI32, - i64: envI64, - i128: envI128, - f32: envF32, - f64: envF64, - dec: envDec, - bool: envBool, - string: envString, - list: envList, - record: envRecord, - tuple: envTuple, + u8: env_u8, + u16: env_u16, + u32: env_u32, + u64: env_u64, + u128: env_u128, + i8: env_i8, + i16: env_i16, + i32: env_i32, + i64: env_i64, + i128: env_i128, + f32: env_f32, + f64: env_f64, + dec: env_dec, + bool: env_bool, + string: env_string, + list: env_list, + record: env_record, + tuple: env_tuple, }, ] format : {} -> EnvFormat -format = \{} -> @EnvFormat {} +format = \{} -> @EnvFormat({}) -decodeBytesToNum = \bytes, transformer -> - when Str.fromUtf8 bytes is - Ok s -> - when transformer s is - Ok n -> { result: Ok n, rest: [] } - Err _ -> { result: Err TooShort, rest: bytes } +decode_bytes_to_num = \bytes, transformer -> + 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 } -envU8 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toU8 -envU16 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toU16 -envU32 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toU32 -envU64 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toU64 -envU128 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toU128 -envI8 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toI8 -envI16 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toI16 -envI32 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toI32 -envI64 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toI64 -envI128 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toI128 -envF32 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toF32 -envF64 = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toF64 -envDec = Decode.custom \bytes, @EnvFormat {} -> decodeBytesToNum bytes Str.toDec -envBool = Decode.custom \bytes, @EnvFormat {} -> - when Str.fromUtf8 bytes is - Ok "true" -> { result: Ok Bool.true, rest: [] } - Ok "false" -> { result: Ok Bool.false, rest: [] } - _ -> { result: Err TooShort, rest: bytes } -envString = Decode.custom \bytes, @EnvFormat {} -> - when Str.fromUtf8 bytes is - Ok s -> { result: Ok s, rest: [] } - Err _ -> { result: Err TooShort, rest: bytes } +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.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.from_utf8(bytes) is + Ok(s) -> { result: Ok(s), rest: [] } + Err(_) -> { result: Err(TooShort), rest: bytes }) -envList = \decodeElem -> Decode.custom \bytes, @EnvFormat {} -> - # Per our supported methods of decoding, this is either a list of strings or - # a list of numbers; in either case, the list of bytes must be Utf-8 - # decodable. So just parse it as a list of strings and pass each chunk to - # the element decoder. By construction, our element decoders expect to parse - # a whole list of bytes anyway. - decodeElems = \allBytes, accum -> - { toParse, remainder } = - when List.splitFirst allBytes (Num.toU8 ',') is - Ok { before, after } -> - { toParse: before, remainder: Some after } +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 -> - { toParse: allBytes, remainder: None } + Err(NotFound) -> + { to_parse: all_bytes, remainder: None } - when Decode.decodeWith toParse decodeElem (@EnvFormat {}) is - { result, rest } -> - when result is - Ok val -> - when remainder is - Some restBytes -> decodeElems restBytes (List.append accum val) - None -> Done (List.append accum val) + 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 decodeElems 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. -envRecord : _, (_, _ -> [Keep (Decoder _ _), Skip]), (_, _ -> _) -> Decoder _ _ -envRecord = \_initialState, _stepField, _finalizer -> Decode.custom \bytes, @EnvFormat {} -> - { result: Err TooShort, rest: bytes } +env_record : _, (_, _ -> [Keep (Decoder _ _), Skip]), (_, _ -> _) -> Decoder _ _ +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. -envTuple : _, (_, _ -> [Next (Decoder _ _), TooLong]), (_ -> _) -> Decoder _ _ -envTuple = \_initialState, _stepElem, _finalizer -> Decode.custom \bytes, @EnvFormat {} -> - { result: Err TooShort, rest: bytes } +env_tuple : _, (_, _ -> [Next (Decoder _ _), TooLong]), (_ -> _) -> Decoder _ _ +env_tuple = \_initialState, _stepElem, _finalizer -> + Decode.custom(\bytes, @EnvFormat({}) -> + { result: Err(TooShort), rest: bytes }) diff --git a/platform/Host.roc b/platform/Host.roc index 51fd133..ee3eb79 100644 --- a/platform/Host.roc +++ b/platform/Host.roc @@ -1,6 +1,5 @@ hosted Host exposes [ - TcpStream, find_files!, parse_markdown!, write_file!, @@ -16,18 +15,11 @@ hosted Host get_locale!, get_locales!, posix_time!, - send_request!, - tcp_connect!, - tcp_read_up_to!, - tcp_read_exactly!, - tcp_read_until!, - tcp_write!, ] imports [Types] import InternalIOErr import InternalCmd -import InternalHttp # Static Site Generation find_files! : Str => Result (List Types.Files) Str @@ -55,13 +47,3 @@ get_locales! : {} => List Str # UTC posix_time! : {} => U128 # TODO why is this a U128 but then getting converted to a I128 in Utc.roc? - -# TCP -send_request! : InternalHttp.RequestToAndFromHost => InternalHttp.ResponseToAndFromHost - -TcpStream := Box {} -tcp_connect! : Str, U16 => Result TcpStream Str -tcp_read_up_to! : TcpStream, U64 => Result (List U8) Str -tcp_read_exactly! : TcpStream, U64 => Result (List U8) Str -tcp_read_until! : TcpStream, U8 => Result (List U8) Str -tcp_write! : TcpStream, List U8 => Result {} Str diff --git a/platform/Html.roc b/platform/Html.roc index a7a731f..fd26be8 100644 --- a/platform/Html.roc +++ b/platform/Html.roc @@ -2,9 +2,9 @@ module [ Node, Attribute, render, - renderWithoutDocType, + render_without_doc_type, element, - unclosedElem, + unclosed_elem, text, attribute, html, @@ -150,35 +150,35 @@ text = Text ## html = blink [] [ text "This text is blinking!" ] ## element : Str -> (List Attribute, List Node -> Node) -element = \tagName -> +element = \tag_name -> \attrs, children -> # While building the node tree, calculate the size of Str it will render to - withTag = 2 * (3 + Str.countUtf8Bytes tagName) - withAttrs = List.walk attrs withTag \acc, Attribute name val -> - acc + Str.countUtf8Bytes name + Str.countUtf8Bytes val + 4 - totalSize = List.walk children withAttrs \acc, child -> - acc + nodeSize child + with_tag = 2 * (3 + Str.count_utf8_bytes(tag_name)) + with_attrs = List.walk(attrs, with_tag, \acc, Attribute(name, val) -> + acc + Str.count_utf8_bytes(name) + Str.count_utf8_bytes(val) + 4) + total_size = List.walk(children, with_attrs, \acc, child -> + acc + node_size(child)) - Element tagName totalSize attrs children + Element(tag_name, total_size, attrs, children) -unclosedElem : Str -> (List Attribute -> Node) -unclosedElem = \tagName -> +unclosed_elem : Str -> (List Attribute -> Node) +unclosed_elem = \tag_name -> \attrs -> # While building the node tree, calculate the size of Str it will render to - withTag = 2 * (3 + Str.countUtf8Bytes tagName) - totalSize = List.walk attrs withTag \acc, Attribute name val -> - acc + Str.countUtf8Bytes name + Str.countUtf8Bytes val + 4 + with_tag = 2 * (3 + Str.count_utf8_bytes(tag_name)) + total_size = List.walk(attrs, with_tag, \acc, Attribute(name, val) -> + acc + Str.count_utf8_bytes(name) + Str.count_utf8_bytes(val) + 4) - UnclosedElem tagName totalSize attrs + UnclosedElem(tag_name, total_size, attrs) # internal helper -nodeSize : Node -> U64 -nodeSize = \node -> +node_size : Node -> U64 +node_size = \node -> when node is - Text content -> - Str.countUtf8Bytes content + Text(content) -> + Str.count_utf8_bytes(content) - Element _ size _ _ | UnclosedElem _ size _ -> + Element(_, size, _, _) | UnclosedElem(_, size, _) -> size ## Render a Node to an HTML string @@ -189,188 +189,188 @@ nodeSize = \node -> ## See also `renderWithoutDocType`. render : Node -> Str render = \node -> - buffer = Str.reserve "" (nodeSize node) + buffer = Str.reserve("", node_size(node)) - renderHelp buffer node + render_help(buffer, node) ## Render a Node to a string, without a DOCTYPE tag -renderWithoutDocType : Node -> Str -renderWithoutDocType = \node -> - buffer = Str.reserve "" (nodeSize node) +render_without_doc_type : Node -> Str +render_without_doc_type = \node -> + buffer = Str.reserve("", node_size(node)) - renderHelp buffer node + render_help(buffer, node) # internal helper -renderHelp : Str, Node -> Str -renderHelp = \buffer, node -> +render_help : Str, Node -> Str +render_help = \buffer, node -> when node is - Text content -> - Str.concat buffer content - - Element tagName _ attrs children -> - withTagName = "$(buffer)<$(tagName)" - withAttrs = - if List.isEmpty attrs then - withTagName + Text(content) -> + Str.concat(buffer, content) + + Element(tag_name, _, attrs, children) -> + with_tag_name = "$(buffer)<$(tag_name)" + with_attrs = + if List.is_empty(attrs) then + with_tag_name else - List.walk attrs "$(withTagName) " renderAttr - withTag = Str.concat withAttrs ">" - withChildren = List.walk children withTag renderHelp + List.walk(attrs, "$(with_tag_name) ", render_attr) + with_tag = Str.concat(with_attrs, ">") + with_children = List.walk(children, with_tag, render_help) - "$(withChildren)" + "$(with_children)" - UnclosedElem tagName _ attrs -> - if List.isEmpty attrs then - "$(buffer)<$(tagName)>" + UnclosedElem(tag_name, _, attrs) -> + if List.is_empty(attrs) then + "$(buffer)<$(tag_name)>" else attrs - |> List.walk "$(buffer)<$(tagName) " renderAttr - |> Str.concat ">" + |> List.walk("$(buffer)<$(tag_name) ", render_attr) + |> Str.concat(">") # internal helper -renderAttr : Str, Attribute -> Str -renderAttr = \buffer, Attribute key val -> +render_attr : Str, Attribute -> Str +render_attr = \buffer, Attribute(key, val) -> "$(buffer) $(key)=\"$(val)\"" # Main root -html = element "html" +html = element("html") # Document metadata -base = element "base" -head = element "head" -link = unclosedElem "link" -meta = unclosedElem "meta" -style = element "style" -title = element "title" +base = element("base") +head = element("head") +link = unclosed_elem("link") +meta = unclosed_elem("meta") +style = element("style") +title = element("title") # Sectioning root -body = element "body" +body = element("body") # Content sectioning -address = element "address" -article = element "article" -aside = element "aside" -footer = element "footer" -header = element "header" -h1 = element "h1" -h2 = element "h2" -h3 = element "h3" -h4 = element "h4" -h5 = element "h5" -h6 = element "h6" -main = element "main" -nav = element "nav" -section = element "section" +address = element("address") +article = element("article") +aside = element("aside") +footer = element("footer") +header = element("header") +h1 = element("h1") +h2 = element("h2") +h3 = element("h3") +h4 = element("h4") +h5 = element("h5") +h6 = element("h6") +main = element("main") +nav = element("nav") +section = element("section") # Text content -blockquote = element "blockquote" -dd = element "dd" -div = element "div" -dl = element "dl" -dt = element "dt" -figcaption = element "figcaption" -figure = element "figure" -hr = element "hr" -li = element "li" -menu = element "menu" -ol = element "ol" -p = element "p" -pre = element "pre" -ul = element "ul" +blockquote = element("blockquote") +dd = element("dd") +div = element("div") +dl = element("dl") +dt = element("dt") +figcaption = element("figcaption") +figure = element("figure") +hr = element("hr") +li = element("li") +menu = element("menu") +ol = element("ol") +p = element("p") +pre = element("pre") +ul = element("ul") # Inline text semantics -a = element "a" -abbr = element "abbr" -b = element "b" -bdi = element "bdi" -bdo = element "bdo" -br = element "br" -cite = element "cite" -code = element "code" -data = element "data" -dfn = element "dfn" -em = element "em" -i = element "i" -kbd = element "kbd" -mark = element "mark" -q = element "q" -rp = element "rp" -rt = element "rt" -ruby = element "ruby" -s = element "s" -samp = element "samp" -small = element "small" -span = element "span" -strong = element "strong" -sub = element "sub" -sup = element "sup" -time = element "time" -u = element "u" -var = element "var" -wbr = element "wbr" +a = element("a") +abbr = element("abbr") +b = element("b") +bdi = element("bdi") +bdo = element("bdo") +br = element("br") +cite = element("cite") +code = element("code") +data = element("data") +dfn = element("dfn") +em = element("em") +i = element("i") +kbd = element("kbd") +mark = element("mark") +q = element("q") +rp = element("rp") +rt = element("rt") +ruby = element("ruby") +s = element("s") +samp = element("samp") +small = element("small") +span = element("span") +strong = element("strong") +sub = element("sub") +sup = element("sup") +time = element("time") +u = element("u") +var = element("var") +wbr = element("wbr") # Image and multimedia -area = element "area" -audio = element "audio" -img = unclosedElem "img" -map = element "map" -track = element "track" -video = element "video" +area = element("area") +audio = element("audio") +img = unclosed_elem("img") +map = element("map") +track = element("track") +video = element("video") # Embedded content -embed = element "embed" -iframe = element "iframe" -object = element "object" -picture = element "picture" -portal = element "portal" -source = element "source" +embed = element("embed") +iframe = element("iframe") +object = element("object") +picture = element("picture") +portal = element("portal") +source = element("source") # SVG and MathML -svg = element "svg" -math = element "math" +svg = element("svg") +math = element("math") # Scripting -canvas = element "canvas" -noscript = element "noscript" -script = element "script" +canvas = element("canvas") +noscript = element("noscript") +script = element("script") # Demarcating edits -del = element "del" -ins = element "ins" +del = element("del") +ins = element("ins") # Table content -caption = element "caption" -col = element "col" -colgroup = element "colgroup" -table = element "table" -tbody = element "tbody" -td = element "td" -tfoot = element "tfoot" -th = element "th" -thead = element "thead" -tr = element "tr" +caption = element("caption") +col = element("col") +colgroup = element("colgroup") +table = element("table") +tbody = element("tbody") +td = element("td") +tfoot = element("tfoot") +th = element("th") +thead = element("thead") +tr = element("tr") # Forms -button = element "button" -datalist = element "datalist" -fieldset = element "fieldset" -form = element "form" -input = element "input" -label = element "label" -legend = element "legend" -meter = element "meter" -optgroup = element "optgroup" -option = element "option" -output = element "output" -progress = element "progress" -select = element "select" -textarea = element "textarea" +button = element("button") +datalist = element("datalist") +fieldset = element("fieldset") +form = element("form") +input = element("input") +label = element("label") +legend = element("legend") +meter = element("meter") +optgroup = element("optgroup") +option = element("option") +output = element("output") +progress = element("progress") +select = element("select") +textarea = element("textarea") # Interactive elements -details = element "details" -dialog = element "dialog" -summary = element "summary" +details = element("details") +dialog = element("dialog") +summary = element("summary") # Web Components -slot = element "slot" -template = element "template" +slot = element("slot") +template = element("template") diff --git a/platform/Html/Attributes.roc b/platform/Html/Attributes.roc index 6e9c579..ff2fd06 100644 --- a/platform/Html/Attributes.roc +++ b/platform/Html/Attributes.roc @@ -2,15 +2,15 @@ module [ Attribute, attribute, accept, - acceptCharset, + accept_charset, accesskey, action, align, allow, alt, - ariaLabel, - ariaLabelledBy, - ariaHidden, + aria_label, + aria_labelled_by, + aria_hidden, async, autocapitalize, autocomplete, @@ -39,7 +39,7 @@ module [ crossorigin, csp, data, - dataAttr, + data_attr, datetime, decoding, default, @@ -64,7 +64,7 @@ module [ high, href, hreflang, - httpEquiv, + http_equiv, icon, id, importance, @@ -141,141 +141,141 @@ module [ Attribute : [Attribute Str Str] attribute : Str -> (Str -> Attribute) -attribute = \attrName -> - \attrValue -> Attribute attrName attrValue +attribute = \attr_name -> + \attr_value -> Attribute(attr_name, attr_value) -accept = attribute "accept" -acceptCharset = attribute "accept-charset" -accesskey = attribute "accesskey" -action = attribute "action" -align = attribute "align" -allow = attribute "allow" -alt = attribute "alt" -ariaLabel = attribute "aria-label" -ariaLabelledBy = attribute "aria-labelledby" -ariaHidden = attribute "aria-label" -async = attribute "async" -autocapitalize = attribute "autocapitalize" -autocomplete = attribute "autocomplete" -autofocus = attribute "autofocus" -autoplay = attribute "autoplay" -background = attribute "background" -bgcolor = attribute "bgcolor" -border = attribute "border" -buffered = attribute "buffered" -capture = attribute "capture" -challenge = attribute "challenge" -charset = attribute "charset" -checked = attribute "checked" -cite = attribute "cite" -class = attribute "class" -code = attribute "code" -codebase = attribute "codebase" -color = attribute "color" -cols = attribute "cols" -colspan = attribute "colspan" -content = attribute "content" -contenteditable = attribute "contenteditable" -contextmenu = attribute "contextmenu" -controls = attribute "controls" -coords = attribute "coords" -crossorigin = attribute "crossorigin" -csp = attribute "csp" -data = attribute "data" -dataAttr = \dataName, dataVal -> Attribute "data-$(dataName)" dataVal -datetime = attribute "datetime" -decoding = attribute "decoding" -default = attribute "default" -defer = attribute "defer" -dir = attribute "dir" -dirname = attribute "dirname" -disabled = attribute "disabled" -download = attribute "download" -draggable = attribute "draggable" -enctype = attribute "enctype" -enterkeyhint = attribute "enterkeyhint" -for = attribute "for" -form = attribute "form" -formaction = attribute "formaction" -formenctype = attribute "formenctype" -formmethod = attribute "formmethod" -formnovalidate = attribute "formnovalidate" -formtarget = attribute "formtarget" -headers = attribute "headers" -height = attribute "height" -hidden = attribute "hidden" -high = attribute "high" -href = attribute "href" -hreflang = attribute "hreflang" -httpEquiv = attribute "http-equiv" -icon = attribute "icon" -id = attribute "id" -importance = attribute "importance" -integrity = attribute "integrity" -intrinsicsize = attribute "intrinsicsize" -inputmode = attribute "inputmode" -ismap = attribute "ismap" -itemprop = attribute "itemprop" -keytype = attribute "keytype" -kind = attribute "kind" -label = attribute "label" -lang = attribute "lang" -language = attribute "language" -loading = attribute "loading" -list = attribute "list" -loop = attribute "loop" -low = attribute "low" -manifest = attribute "manifest" -max = attribute "max" -maxlength = attribute "maxlength" -minlength = attribute "minlength" -media = attribute "media" -method = attribute "method" -min = attribute "min" -multiple = attribute "multiple" -muted = attribute "muted" -name = attribute "name" -novalidate = attribute "novalidate" -open = attribute "open" -optimum = attribute "optimum" -pattern = attribute "pattern" -ping = attribute "ping" -placeholder = attribute "placeholder" -poster = attribute "poster" -preload = attribute "preload" -radiogroup = attribute "radiogroup" -readonly = attribute "readonly" -referrerpolicy = attribute "referrerpolicy" -rel = attribute "rel" -required = attribute "required" -reversed = attribute "reversed" -role = attribute "role" -rows = attribute "rows" -rowspan = attribute "rowspan" -sandbox = attribute "sandbox" -scope = attribute "scope" -scoped = attribute "scoped" -selected = attribute "selected" -shape = attribute "shape" -size = attribute "size" -sizes = attribute "sizes" -slot = attribute "slot" -span = attribute "span" -spellcheck = attribute "spellcheck" -src = attribute "src" -srcdoc = attribute "srcdoc" -srclang = attribute "srclang" -srcset = attribute "srcset" -start = attribute "start" -step = attribute "step" -style = attribute "style" -summary = attribute "summary" -tabindex = attribute "tabindex" -target = attribute "target" -title = attribute "title" -translate = attribute "translate" -type = attribute "type" -usemap = attribute "usemap" -value = attribute "value" -width = attribute "width" -wrap = attribute "wrap" +accept = attribute("accept") +accept_charset = attribute("accept-charset") +accesskey = attribute("accesskey") +action = attribute("action") +align = attribute("align") +allow = attribute("allow") +alt = attribute("alt") +aria_label = attribute("aria-label") +aria_labelled_by = attribute("aria-labelledby") +aria_hidden = attribute("aria-label") +async = attribute("async") +autocapitalize = attribute("autocapitalize") +autocomplete = attribute("autocomplete") +autofocus = attribute("autofocus") +autoplay = attribute("autoplay") +background = attribute("background") +bgcolor = attribute("bgcolor") +border = attribute("border") +buffered = attribute("buffered") +capture = attribute("capture") +challenge = attribute("challenge") +charset = attribute("charset") +checked = attribute("checked") +cite = attribute("cite") +class = attribute("class") +code = attribute("code") +codebase = attribute("codebase") +color = attribute("color") +cols = attribute("cols") +colspan = attribute("colspan") +content = attribute("content") +contenteditable = attribute("contenteditable") +contextmenu = attribute("contextmenu") +controls = attribute("controls") +coords = attribute("coords") +crossorigin = attribute("crossorigin") +csp = attribute("csp") +data = attribute("data") +data_attr = \data_name, data_val -> Attribute("data-$(data_name)", data_val) +datetime = attribute("datetime") +decoding = attribute("decoding") +default = attribute("default") +defer = attribute("defer") +dir = attribute("dir") +dirname = attribute("dirname") +disabled = attribute("disabled") +download = attribute("download") +draggable = attribute("draggable") +enctype = attribute("enctype") +enterkeyhint = attribute("enterkeyhint") +for = attribute("for") +form = attribute("form") +formaction = attribute("formaction") +formenctype = attribute("formenctype") +formmethod = attribute("formmethod") +formnovalidate = attribute("formnovalidate") +formtarget = attribute("formtarget") +headers = attribute("headers") +height = attribute("height") +hidden = attribute("hidden") +high = attribute("high") +href = attribute("href") +hreflang = attribute("hreflang") +http_equiv = attribute("http-equiv") +icon = attribute("icon") +id = attribute("id") +importance = attribute("importance") +integrity = attribute("integrity") +intrinsicsize = attribute("intrinsicsize") +inputmode = attribute("inputmode") +ismap = attribute("ismap") +itemprop = attribute("itemprop") +keytype = attribute("keytype") +kind = attribute("kind") +label = attribute("label") +lang = attribute("lang") +language = attribute("language") +loading = attribute("loading") +list = attribute("list") +loop = attribute("loop") +low = attribute("low") +manifest = attribute("manifest") +max = attribute("max") +maxlength = attribute("maxlength") +minlength = attribute("minlength") +media = attribute("media") +method = attribute("method") +min = attribute("min") +multiple = attribute("multiple") +muted = attribute("muted") +name = attribute("name") +novalidate = attribute("novalidate") +open = attribute("open") +optimum = attribute("optimum") +pattern = attribute("pattern") +ping = attribute("ping") +placeholder = attribute("placeholder") +poster = attribute("poster") +preload = attribute("preload") +radiogroup = attribute("radiogroup") +readonly = attribute("readonly") +referrerpolicy = attribute("referrerpolicy") +rel = attribute("rel") +required = attribute("required") +reversed = attribute("reversed") +role = attribute("role") +rows = attribute("rows") +rowspan = attribute("rowspan") +sandbox = attribute("sandbox") +scope = attribute("scope") +scoped = attribute("scoped") +selected = attribute("selected") +shape = attribute("shape") +size = attribute("size") +sizes = attribute("sizes") +slot = attribute("slot") +span = attribute("span") +spellcheck = attribute("spellcheck") +src = attribute("src") +srcdoc = attribute("srcdoc") +srclang = attribute("srclang") +srcset = attribute("srcset") +start = attribute("start") +step = attribute("step") +style = attribute("style") +summary = attribute("summary") +tabindex = attribute("tabindex") +target = attribute("target") +title = attribute("title") +translate = attribute("translate") +type = attribute("type") +usemap = attribute("usemap") +value = attribute("value") +width = attribute("width") +wrap = attribute("wrap") diff --git a/platform/Http.roc b/platform/Http.roc deleted file mode 100644 index 750ddee..0000000 --- a/platform/Http.roc +++ /dev/null @@ -1,87 +0,0 @@ -module [ - Request, - Response, - Method, - Header, - header, - default_request, - send!, - get!, -] - -import InternalHttp -import Host - -## Represents an HTTP method. -Method : InternalHttp.Method - -## Represents an HTTP header e.g. `Content-Type: application/json` -Header : InternalHttp.Header - -## Represents an HTTP request. -Request : InternalHttp.Request - -## Represents an HTTP response. -Response : InternalHttp.Response - -## A default [Request] value. -## -## ``` -## # GET "roc-lang.org" -## { Http.default_request & -## url: "https://www.roc-lang.org", -## } -## ``` -## -default_request : Request -default_request = { - method: Get, - headers: [], - uri: "", - body: [], - timeout_ms: NoTimeout, -} - -## An HTTP header for configuring requests. -## -## See common headers [here](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields). -## -header : (Str, Str) -> Header -header = \(name, value) -> { name, value } - -## Send an HTTP request, succeeds with a value of [Str] or fails with an -## [Err]. -## -## ``` -## # Prints out the HTML of the Roc-lang website. -## response = -## { Http.default_request & url: "https://www.roc-lang.org" } -## |> Http.send! -## -## response.body -## |> Str.fromUtf8 -## |> Result.withDefault "Invalid UTF-8" -## |> Stdout.line -## ``` -send! : Request => Response -send! = \request -> - request - |> InternalHttp.to_host_request - |> Host.send_request! - |> InternalHttp.from_host_response - -## Try to perform an HTTP get request and convert (decode) the received bytes into a Roc type. -## Very useful for working with Json. -## -## ``` -## import json.Json -## -## # On the server side we send `Encode.toBytes {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 } - - Decode.fromBytes response.body fmt - |> Result.mapErr \_ -> HttpDecodingFailed diff --git a/platform/InternalCmd.roc b/platform/InternalCmd.roc index 2fe8f9b..7be8a52 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 bde2748..3a8e403 100644 --- a/platform/InternalDateTime.roc +++ b/platform/InternalDateTime.roc @@ -8,49 +8,49 @@ 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 } -> - yearStr = yearWithPaddedZeros year - monthStr = monthWithPaddedZeros month - dayStr = dayWithPaddedZeros day - hourStr = hoursWithPaddedZeros hours - minuteStr = minutesWithPaddedZeros minutes - secondsStr = secondsWithPaddedZeros seconds - - "$(yearStr)-$(monthStr)-$(dayStr)T$(hourStr):$(minuteStr):$(secondsStr)Z" - -yearWithPaddedZeros : I128 -> Str -yearWithPaddedZeros = \year -> - yearStr = Num.toStr year + 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.to_str(year) if year < 10 then - "000$(yearStr)" + "000$(year_str)" else if year < 100 then - "00$(yearStr)" + "00$(year_str)" else if year < 1000 then - "0$(yearStr)" + "0$(year_str)" else - yearStr + year_str -monthWithPaddedZeros : I128 -> Str -monthWithPaddedZeros = \month -> - monthStr = Num.toStr month +month_with_padded_zeros : I128 -> Str +month_with_padded_zeros = \month -> + month_str = Num.to_str(month) if month < 10 then - "0$(monthStr)" + "0$(month_str)" else - monthStr + month_str -dayWithPaddedZeros : I128 -> Str -dayWithPaddedZeros = monthWithPaddedZeros +day_with_padded_zeros : I128 -> Str +day_with_padded_zeros = month_with_padded_zeros -hoursWithPaddedZeros : I128 -> Str -hoursWithPaddedZeros = monthWithPaddedZeros +hours_with_padded_zeros : I128 -> Str +hours_with_padded_zeros = month_with_padded_zeros -minutesWithPaddedZeros : I128 -> Str -minutesWithPaddedZeros = monthWithPaddedZeros +minutes_with_padded_zeros : I128 -> Str +minutes_with_padded_zeros = month_with_padded_zeros -secondsWithPaddedZeros : I128 -> Str -secondsWithPaddedZeros = monthWithPaddedZeros +seconds_with_padded_zeros : I128 -> Str +seconds_with_padded_zeros = month_with_padded_zeros -isLeapYear : I128 -> Bool -isLeapYear = \year -> +is_leap_year : I128 -> Bool +is_leap_year = \year -> (year % 4 == 0) && # divided evenly by 4 unless... ( @@ -59,37 +59,37 @@ isLeapYear = \year -> (year % 400 == 0) # expecpt when also divisible by 400 ) -expect isLeapYear 2000 -expect isLeapYear 2012 -expect !(isLeapYear 1900) -expect !(isLeapYear 2015) -expect List.map [2023, 1988, 1992, 1996] isLeapYear == [Bool.false, Bool.true, Bool.true, Bool.true] -expect List.map [1700, 1800, 1900, 2100, 2200, 2300, 2500, 2600] isLeapYear == [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] -daysInMonth : I128, I128 -> I128 -daysInMonth = \year, month -> - if List.contains [1, 3, 5, 7, 8, 10, 12] month then +days_in_month : I128, I128 -> I128 +days_in_month = \year, month -> + 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 isLeapYear year then 29 else 28) + (if is_leap_year(year) then 29 else 28) else 0 -expect daysInMonth 2023 1 == 31 # January -expect daysInMonth 2023 2 == 28 # February -expect daysInMonth 1996 2 == 29 # February in a leap year -expect daysInMonth 2023 3 == 31 # March -expect daysInMonth 2023 4 == 30 # April -expect daysInMonth 2023 5 == 31 # May -expect daysInMonth 2023 6 == 30 # June -expect daysInMonth 2023 7 == 31 # July -expect daysInMonth 2023 8 == 31 # August -expect daysInMonth 2023 9 == 30 # September -expect daysInMonth 2023 10 == 31 # October -expect daysInMonth 2023 11 == 30 # November -expect daysInMonth 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,61 @@ epoch_millis_to_datetime = \millis -> month = 1 year = 1970 - epoch_millis_to_datetimeHelp { + 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 -> - countDaysInMonth = daysInMonth current.year current.month - countDaysInPrevMonth = + count_days_in_month = days_in_month(current.year, current.month) + count_days_in_prev_month = if current.month == 1 then - daysInMonth (current.year - 1) 12 + days_in_month((current.year - 1), 12) else - daysInMonth 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 + countDaysInPrevMonth, - } + 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 > countDaysInMonth then - epoch_millis_to_datetimeHelp + }, + ) + else if current.day > count_days_in_month then + 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 - countDaysInMonth, - } + day: current.day - count_days_in_month, + }, + ) else current diff --git a/platform/InternalHttp.roc b/platform/InternalHttp.roc deleted file mode 100644 index 54a7a2a..0000000 --- a/platform/InternalHttp.roc +++ /dev/null @@ -1,139 +0,0 @@ -# TODO we should be able to pull this out into a cross-platform package so multiple -# platforms can use it. -# -# I haven't tried that here because I just want to get the implementation working on -# both basic-cli and basic-webserver. Copy-pase is fine for now. -module [ - Request, - Response, - RequestToAndFromHost, - ResponseToAndFromHost, - Method, - Header, - to_host_request, - to_host_response, - from_host_request, - from_host_response, -] - -# FOR ROC - -# https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods -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 } - -Request : { - method : Method, - headers : List Header, - uri : Str, - body : List U8, - timeout_ms : [TimeoutMilliseconds U64, NoTimeout], -} - -Response : { - status : U16, - headers : List Header, - body : List U8, -} - -# FOR HOST - -RequestToAndFromHost : { - method : U64, - method_ext : Str, - headers : List Header, - uri : Str, - body : List U8, - timeout_ms : U64, -} - -ResponseToAndFromHost : { - status : U16, - headers : List Header, - body : List U8, -} - -to_host_response : Response -> ResponseToAndFromHost -to_host_response = \{ status, headers, body } -> { - 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, - headers, - uri, - body, - 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 - -to_host_method_ext : Method -> Str -to_host_method_ext = \method -> - when method is - Extension ext -> ext - _ -> "" - -to_host_timeout : _ -> U64 -to_host_timeout = \timeout -> - when timeout is - 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, - headers, - uri, - body, - 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" - -from_host_timeout : U64 -> [TimeoutMilliseconds U64, NoTimeout] -from_host_timeout = \timeout -> - when timeout is - 0 -> NoTimeout - _ -> TimeoutMilliseconds timeout - -expect from_host_timeout 0 == NoTimeout -expect from_host_timeout 1 == TimeoutMilliseconds 1 - -from_host_response : ResponseToAndFromHost -> Response -from_host_response = \{ status, headers, body } -> { - status, - headers, - body, -} diff --git a/platform/InternalIOErr.roc b/platform/InternalIOErr.roc index ef95d76..5d5f20e 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/Locale.roc b/platform/Locale.roc index 57a9b51..3ffddfb 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/SSG.roc b/platform/SSG.roc index 1ecc1da..e9a6e72 100644 --- a/platform/SSG.roc +++ b/platform/SSG.roc @@ -9,15 +9,15 @@ import Types exposing [Path, RelPath, Files] files! : Path => Result (List Files) [FilesError Str]_ files! = \path -> - Host.find_files! (Types.path_to_str path) - |> Result.mapErr FilesError + Host.find_files!(Types.path_to_str(path)) + |> Result.map_err(FilesError) parse_markdown! : Path => Result Str [ParseError Str]_ parse_markdown! = \path -> - Host.parse_markdown! (Types.path_to_str path) - |> Result.mapErr ParseError + Host.parse_markdown!(Types.path_to_str(path)) + |> Result.map_err(ParseError) -write_file! : { outputDir : Path, relpath : RelPath, content : Str } => Result {} [WriteError Str]_ -write_file! = \{ outputDir, relpath, content } -> - Host.write_file! (Types.path_to_str outputDir) (Types.rel_path_to_str relpath) content - |> Result.mapErr WriteError +write_file! : { output_dir : Path, relpath : RelPath, content : Str } => Result {} [WriteError Str]_ +write_file! = \{ output_dir, relpath, content } -> + Host.write_file!(Types.path_to_str(output_dir), Types.rel_path_to_str(relpath), content) + |> Result.map_err(WriteError) diff --git a/platform/Stderr.roc b/platform/Stderr.roc index b87eb15..b42312c 100644 --- a/platform/Stderr.roc +++ b/platform/Stderr.roc @@ -33,17 +33,17 @@ Err : [ Other Str, ] -handleErr : InternalIOErr.IOErrFromHost -> [StderrErr Err] -handleErr = \{ tag, msg } -> +handle_err : InternalIOErr.IOErrFromHost -> [StderrErr Err] +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 @@ handleErr = \{ tag, msg } -> ## > To write to `stderr` without the newline, see [Stderr.write!]. line! : Str => Result {} [StderrErr Err] line! = \str -> - Host.stderr_line! str - |> Result.mapErr handleErr + 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 Err] write! = \str -> - Host.stderr_write! str - |> Result.mapErr handleErr + Host.stderr_write!(str) + |> Result.map_err(handle_err) diff --git a/platform/Stdout.roc b/platform/Stdout.roc index 0e6e81c..d656df3 100644 --- a/platform/Stdout.roc +++ b/platform/Stdout.roc @@ -36,14 +36,14 @@ Err : [ handle_err : InternalIOErr.IOErrFromHost -> [StdoutErr Err] 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 Err] 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 Err] 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 deleted file mode 100644 index 2209dc5..0000000 --- a/platform/Tcp.roc +++ /dev/null @@ -1,224 +0,0 @@ -module [ - Stream, - ConnectErr, - StreamErr, - connect!, - read_up_to!, - read_exactly!, - read_until!, - read_line!, - write!, - write_utf8!, - connect_err_to_str, - stream_err_to_str, -] - -import Host - -unexpectedEofErrorMessage = "UnexpectedEof" - -## Represents a TCP stream. -Stream := Host.TcpStream - -## Represents errors that can occur when connecting to a remote host. -ConnectErr : [ - PermissionDenied, - AddrInUse, - AddrNotAvailable, - ConnectionRefused, - Interrupted, - TimedOut, - Unsupported, - Unrecognized Str, -] - -parseConnectErr : Str -> ConnectErr -parseConnectErr = \err -> - when err is - "ErrorKind::PermissionDenied" -> PermissionDenied - "ErrorKind::AddrInUse" -> AddrInUse - "ErrorKind::AddrNotAvailable" -> AddrNotAvailable - "ErrorKind::ConnectionRefused" -> ConnectionRefused - "ErrorKind::Interrupted" -> Interrupted - "ErrorKind::TimedOut" -> TimedOut - "ErrorKind::Unsupported" -> Unsupported - other -> Unrecognized other - -## Represents errors that can occur when performing a [Task] with a [Stream]. -StreamErr : [ - StreamNotFound, - PermissionDenied, - ConnectionRefused, - ConnectionReset, - Interrupted, - OutOfMemory, - BrokenPipe, - Unrecognized Str, -] - -parseStreamErr : Str -> StreamErr -parseStreamErr = \err -> - when err is - "StreamNotFound" -> StreamNotFound - "ErrorKind::PermissionDenied" -> PermissionDenied - "ErrorKind::ConnectionRefused" -> ConnectionRefused - "ErrorKind::ConnectionReset" -> ConnectionReset - "ErrorKind::Interrupted" -> Interrupted - "ErrorKind::OutOfMemory" -> OutOfMemory - "ErrorKind::BrokenPipe" -> BrokenPipe - other -> Unrecognized other - -## Opens a TCP connection to a remote host. -## -## ``` -## # Connect to localhost:8080 -## stream = Tcp.connect! "localhost" 8080 -## ``` -## -## The connection is automatically closed when the last reference to the stream is dropped. -## Examples of -## valid hostnames: -## - `127.0.0.1` -## - `::1` -## - `localhost` -## - `roc-lang.org` -## -connect! : Str, U16 => Result Stream ConnectErr -connect! = \host, port -> - Host.tcp_connect! host port - |> Result.map @Stream - |> Result.mapErr parseConnectErr - -## 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 -## ``` -## -## > 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, bytesToRead -> - Host.tcp_read_up_to! stream bytesToRead - |> Result.mapErr \err -> TcpReadErr (parseStreamErr err) - -## Read an exact number of bytes or fail. -## -## ``` -## 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, bytesToRead -> - Host.tcp_read_exactly! stream bytesToRead - |> Result.mapErr \err -> - if err == unexpectedEofErrorMessage then - TcpUnexpectedEOF - else - TcpReadErr (parseStreamErr err) - -## Read until a delimiter or EOF is reached. -## -## ``` -## # Read until null terminator -## File.read_until! stream 0 -## ``` -## -## If found, the delimiter is included as the last byte. -## -## > 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 (parseStreamErr 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 -## ``` -## -## 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' - - Str.fromUtf8 bytes - |> Result.mapErr TcpReadBadUtf8 - -## Writes bytes to a TCP stream. -## -## ``` -## # Writes the bytes 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 (parseStreamErr 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!" -## ``` -## -## > 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) - -## Convert a [ConnectErr] to a [Str] you can print. -## -## ``` -## when err is -## TcpPerfomErr (TcpConnectErr connectErr) -> -## Stderr.line (Tcp.connect_err_to_str connectErr) -## ``` -## -connect_err_to_str : ConnectErr -> Str -connect_err_to_str = \err -> - when err is - PermissionDenied -> "PermissionDenied" - AddrInUse -> "AddrInUse" - AddrNotAvailable -> "AddrNotAvailable" - ConnectionRefused -> "ConnectionRefused" - Interrupted -> "Interrupted" - TimedOut -> "TimedOut" - Unsupported -> "Unsupported" - 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 (TcpWriteErr err) -> -## errStr = Tcp.stream_err_to_str err -## Stderr.line "Error while writing: $(errStr)" -## ``` -## -stream_err_to_str : StreamErr -> Str -stream_err_to_str = \err -> - when err is - StreamNotFound -> "StreamNotFound" - PermissionDenied -> "PermissionDenied" - ConnectionRefused -> "ConnectionRefused" - ConnectionReset -> "ConnectionReset" - Interrupted -> "Interrupted" - OutOfMemory -> "OutOfMemory" - BrokenPipe -> "BrokenPipe" - Unrecognized message -> "Unrecognized Error: $(message)" diff --git a/platform/Types.roc b/platform/Types.roc index c129a46..e4d8e98 100644 --- a/platform/Types.roc +++ b/platform/Types.roc @@ -11,19 +11,19 @@ module [ Path := Str implements [Inspect] path_to_str : Path -> Str -path_to_str = \@Path str -> str +path_to_str = \@Path(str) -> str RelPath := Str implements [Inspect] rel_path_to_str : RelPath -> Str -rel_path_to_str = \@RelPath str -> str +rel_path_to_str = \@RelPath(str) -> str to_rel_path : Str -> RelPath to_rel_path = @RelPath Args : { - inputDir : Path, - outputDir : Path, + input_dir : Path, + output_dir : Path, } Files : { diff --git a/platform/Utc.roc b/platform/Utc.roc index 3b0d682..7703d19 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 @@ -45,35 +45,35 @@ from_nanos_since_epoch = @Utc ## Calculate milliseconds between two Utc timestamps delta_as_millis : Utc, Utc -> U128 -delta_as_millis = \utcA, utcB -> - (delta_as_nanos utcA utcB) // nanos_per_milli +delta_as_millis = \utc_a, utc_b -> + (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 nanosA, @Utc nanosB -> +delta_as_nanos = \@Utc(nanos_a), @Utc(nanos_b) -> # bitwiseXor for best performance - nanos_a_shifted = Num.bitwiseXor (Num.toU128 nanosA) (Num.shiftLeftBy 1 127) - nanos_b_shifted = Num.bitwiseXor (Num.toU128 nanosB) (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/main.roc b/platform/main.roc index 65d95d9..667d68e 100644 --- a/platform/main.roc +++ b/platform/main.roc @@ -9,8 +9,6 @@ platform "roc-ssg" Env, Locale, Utc, - Tcp, - Http, ] packages {} imports [] @@ -21,23 +19,23 @@ import Stderr main_for_host! : Types.Args => I32 main_for_host! = \args -> - 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 -> - helpMsg = + 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! helpMsg + _ = Stderr.line!(help_msg) 1