From eef68e3b428406a741dfb12e461c6ef06952bbab Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Sun, 22 Dec 2024 15:15:26 +1100 Subject: [PATCH 1/6] move platform-switching into cli tests --- crates/cli/tests/cli_tests.rs | 11 +++++++---- .../cli/tests}/platform-switching/README.md | 0 .../tests}/platform-switching/c-platform/host.c | 0 .../platform-switching/c-platform/main.roc | 0 .../cli/tests}/platform-switching/rocLovesC.roc | 0 .../tests}/platform-switching/rocLovesRust.roc | 0 .../platform-switching/rocLovesWebAssembly.roc | 0 .../tests}/platform-switching/rocLovesZig.roc | 0 .../platform-switching/rust-platform/Cargo.toml | 0 .../platform-switching/rust-platform/build.rs | 0 .../platform-switching/rust-platform/build.sh | 0 .../platform-switching/rust-platform/main.roc | 0 .../rust-platform/rust-toolchain.toml | 16 ++++++++-------- .../platform-switching/rust-platform/src/lib.rs | 0 .../web-assembly-platform/README.md | 0 .../web-assembly-platform/host.js | 0 .../web-assembly-platform/host.test.js | 0 .../web-assembly-platform/host.zig | 0 .../web-assembly-platform/index.html | 0 .../web-assembly-platform/main.roc | 0 .../platform-switching/zig-platform/host.zig | 0 .../platform-switching/zig-platform/main.roc | 0 22 files changed, 15 insertions(+), 12 deletions(-) rename {examples => crates/cli/tests}/platform-switching/README.md (100%) rename {examples => crates/cli/tests}/platform-switching/c-platform/host.c (100%) rename {examples => crates/cli/tests}/platform-switching/c-platform/main.roc (100%) rename {examples => crates/cli/tests}/platform-switching/rocLovesC.roc (100%) rename {examples => crates/cli/tests}/platform-switching/rocLovesRust.roc (100%) rename {examples => crates/cli/tests}/platform-switching/rocLovesWebAssembly.roc (100%) rename {examples => crates/cli/tests}/platform-switching/rocLovesZig.roc (100%) rename {examples => crates/cli/tests}/platform-switching/rust-platform/Cargo.toml (100%) rename {examples => crates/cli/tests}/platform-switching/rust-platform/build.rs (100%) rename {examples => crates/cli/tests}/platform-switching/rust-platform/build.sh (100%) rename {examples => crates/cli/tests}/platform-switching/rust-platform/main.roc (100%) rename {examples => crates/cli/tests}/platform-switching/rust-platform/rust-toolchain.toml (95%) rename {examples => crates/cli/tests}/platform-switching/rust-platform/src/lib.rs (100%) rename {examples => crates/cli/tests}/platform-switching/web-assembly-platform/README.md (100%) rename {examples => crates/cli/tests}/platform-switching/web-assembly-platform/host.js (100%) rename {examples => crates/cli/tests}/platform-switching/web-assembly-platform/host.test.js (100%) rename {examples => crates/cli/tests}/platform-switching/web-assembly-platform/host.zig (100%) rename {examples => crates/cli/tests}/platform-switching/web-assembly-platform/index.html (100%) rename {examples => crates/cli/tests}/platform-switching/web-assembly-platform/main.roc (100%) rename {examples => crates/cli/tests}/platform-switching/zig-platform/host.zig (100%) rename {examples => crates/cli/tests}/platform-switching/zig-platform/main.roc (100%) diff --git a/crates/cli/tests/cli_tests.rs b/crates/cli/tests/cli_tests.rs index 5d0217d4bfc..1da6e68c365 100644 --- a/crates/cli/tests/cli_tests.rs +++ b/crates/cli/tests/cli_tests.rs @@ -55,7 +55,7 @@ mod cli_tests { // pre-build the platform std::process::Command::new("bash") .arg(file_from_root( - "examples/platform-switching/rust-platform", + "crates/cli/tests/platform-switching/rust-platform", "build.sh", )) .status() @@ -63,7 +63,7 @@ mod cli_tests { let cli_build = ExecCli::new( roc_cli::CMD_DEV, - file_from_root("examples/platform-switching", "rocLovesRust.roc"), + file_from_root("crates/cli/tests/platform-switching", "rocLovesRust.roc"), ); let expected_output = "Roc <3 Rust!\n"; @@ -80,7 +80,7 @@ mod cli_tests { let cli_build = ExecCli::new( CMD_BUILD, - file_from_root("examples/platform-switching", "rocLovesZig.roc"), + file_from_root("crates/cli/tests/platform-switching", "rocLovesZig.roc"), ) .arg(BUILD_HOST_FLAG) .arg(SUPPRESS_BUILD_HOST_WARNING_FLAG); @@ -104,7 +104,10 @@ mod cli_tests { // so let's just check it for now let cli_check = ExecCli::new( CMD_CHECK, - file_from_root("examples/platform-switching", "rocLovesWebAssembly.roc"), + file_from_root( + "crates/cli/tests/platform-switching", + "rocLovesWebAssembly.roc", + ), ); let cli_check_out = cli_check.run(); diff --git a/examples/platform-switching/README.md b/crates/cli/tests/platform-switching/README.md similarity index 100% rename from examples/platform-switching/README.md rename to crates/cli/tests/platform-switching/README.md diff --git a/examples/platform-switching/c-platform/host.c b/crates/cli/tests/platform-switching/c-platform/host.c similarity index 100% rename from examples/platform-switching/c-platform/host.c rename to crates/cli/tests/platform-switching/c-platform/host.c diff --git a/examples/platform-switching/c-platform/main.roc b/crates/cli/tests/platform-switching/c-platform/main.roc similarity index 100% rename from examples/platform-switching/c-platform/main.roc rename to crates/cli/tests/platform-switching/c-platform/main.roc diff --git a/examples/platform-switching/rocLovesC.roc b/crates/cli/tests/platform-switching/rocLovesC.roc similarity index 100% rename from examples/platform-switching/rocLovesC.roc rename to crates/cli/tests/platform-switching/rocLovesC.roc diff --git a/examples/platform-switching/rocLovesRust.roc b/crates/cli/tests/platform-switching/rocLovesRust.roc similarity index 100% rename from examples/platform-switching/rocLovesRust.roc rename to crates/cli/tests/platform-switching/rocLovesRust.roc diff --git a/examples/platform-switching/rocLovesWebAssembly.roc b/crates/cli/tests/platform-switching/rocLovesWebAssembly.roc similarity index 100% rename from examples/platform-switching/rocLovesWebAssembly.roc rename to crates/cli/tests/platform-switching/rocLovesWebAssembly.roc diff --git a/examples/platform-switching/rocLovesZig.roc b/crates/cli/tests/platform-switching/rocLovesZig.roc similarity index 100% rename from examples/platform-switching/rocLovesZig.roc rename to crates/cli/tests/platform-switching/rocLovesZig.roc diff --git a/examples/platform-switching/rust-platform/Cargo.toml b/crates/cli/tests/platform-switching/rust-platform/Cargo.toml similarity index 100% rename from examples/platform-switching/rust-platform/Cargo.toml rename to crates/cli/tests/platform-switching/rust-platform/Cargo.toml diff --git a/examples/platform-switching/rust-platform/build.rs b/crates/cli/tests/platform-switching/rust-platform/build.rs similarity index 100% rename from examples/platform-switching/rust-platform/build.rs rename to crates/cli/tests/platform-switching/rust-platform/build.rs diff --git a/examples/platform-switching/rust-platform/build.sh b/crates/cli/tests/platform-switching/rust-platform/build.sh similarity index 100% rename from examples/platform-switching/rust-platform/build.sh rename to crates/cli/tests/platform-switching/rust-platform/build.sh diff --git a/examples/platform-switching/rust-platform/main.roc b/crates/cli/tests/platform-switching/rust-platform/main.roc similarity index 100% rename from examples/platform-switching/rust-platform/main.roc rename to crates/cli/tests/platform-switching/rust-platform/main.roc diff --git a/examples/platform-switching/rust-platform/rust-toolchain.toml b/crates/cli/tests/platform-switching/rust-platform/rust-toolchain.toml similarity index 95% rename from examples/platform-switching/rust-platform/rust-toolchain.toml rename to crates/cli/tests/platform-switching/rust-platform/rust-toolchain.toml index 0abb9617ed3..d67979c6af2 100644 --- a/examples/platform-switching/rust-platform/rust-toolchain.toml +++ b/crates/cli/tests/platform-switching/rust-platform/rust-toolchain.toml @@ -1,9 +1,9 @@ -[toolchain] -channel = "1.77.2" - -profile = "default" - -components = [ - # for usages of rust-analyzer or similar tools inside `nix develop` - "rust-src" +[toolchain] +channel = "1.77.2" + +profile = "default" + +components = [ + # for usages of rust-analyzer or similar tools inside `nix develop` + "rust-src" ] \ No newline at end of file diff --git a/examples/platform-switching/rust-platform/src/lib.rs b/crates/cli/tests/platform-switching/rust-platform/src/lib.rs similarity index 100% rename from examples/platform-switching/rust-platform/src/lib.rs rename to crates/cli/tests/platform-switching/rust-platform/src/lib.rs diff --git a/examples/platform-switching/web-assembly-platform/README.md b/crates/cli/tests/platform-switching/web-assembly-platform/README.md similarity index 100% rename from examples/platform-switching/web-assembly-platform/README.md rename to crates/cli/tests/platform-switching/web-assembly-platform/README.md diff --git a/examples/platform-switching/web-assembly-platform/host.js b/crates/cli/tests/platform-switching/web-assembly-platform/host.js similarity index 100% rename from examples/platform-switching/web-assembly-platform/host.js rename to crates/cli/tests/platform-switching/web-assembly-platform/host.js diff --git a/examples/platform-switching/web-assembly-platform/host.test.js b/crates/cli/tests/platform-switching/web-assembly-platform/host.test.js similarity index 100% rename from examples/platform-switching/web-assembly-platform/host.test.js rename to crates/cli/tests/platform-switching/web-assembly-platform/host.test.js diff --git a/examples/platform-switching/web-assembly-platform/host.zig b/crates/cli/tests/platform-switching/web-assembly-platform/host.zig similarity index 100% rename from examples/platform-switching/web-assembly-platform/host.zig rename to crates/cli/tests/platform-switching/web-assembly-platform/host.zig diff --git a/examples/platform-switching/web-assembly-platform/index.html b/crates/cli/tests/platform-switching/web-assembly-platform/index.html similarity index 100% rename from examples/platform-switching/web-assembly-platform/index.html rename to crates/cli/tests/platform-switching/web-assembly-platform/index.html diff --git a/examples/platform-switching/web-assembly-platform/main.roc b/crates/cli/tests/platform-switching/web-assembly-platform/main.roc similarity index 100% rename from examples/platform-switching/web-assembly-platform/main.roc rename to crates/cli/tests/platform-switching/web-assembly-platform/main.roc diff --git a/examples/platform-switching/zig-platform/host.zig b/crates/cli/tests/platform-switching/zig-platform/host.zig similarity index 100% rename from examples/platform-switching/zig-platform/host.zig rename to crates/cli/tests/platform-switching/zig-platform/host.zig diff --git a/examples/platform-switching/zig-platform/main.roc b/crates/cli/tests/platform-switching/zig-platform/main.roc similarity index 100% rename from examples/platform-switching/zig-platform/main.roc rename to crates/cli/tests/platform-switching/zig-platform/main.roc From a3fecaad73d5922c37c8281cbd454610ea7e538f Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Sun, 22 Dec 2024 15:25:26 +1100 Subject: [PATCH 2/6] Move all interop examples to roc-lang/examples --- examples/README.md | 8 +- examples/glue/glue.roc | 7 - .../glue/rust-platform/.cargo/config.toml | 2 - examples/glue/rust-platform/Cargo.toml | 23 - examples/glue/rust-platform/build.rs | 9 - examples/glue/rust-platform/host.c | 3 - examples/glue/rust-platform/main.roc | 17 - .../glue/rust-platform/rust-toolchain.toml | 9 - examples/glue/rust-platform/src/glue.rs | 744 ---------- examples/glue/rust-platform/src/lib.rs | 123 -- examples/glue/rust-platform/src/main.rs | 3 - examples/jvm-interop/README.md | 210 --- examples/jvm-interop/bridge.c | 384 ----- examples/jvm-interop/build.sh | 42 - examples/jvm-interop/impl.roc | 23 - examples/jvm-interop/javaSource/Demo.java | 39 - examples/jvm-interop/platform.roc | 13 - .../nodejs-interop/native-c-api/README.md | 64 - .../nodejs-interop/native-c-api/addon.d.ts | 1 - .../nodejs-interop/native-c-api/binding.gyp | 12 - examples/nodejs-interop/native-c-api/demo.c | 418 ------ examples/nodejs-interop/native-c-api/hello.ts | 3 - examples/nodejs-interop/native-c-api/main.roc | 5 - .../native-c-api/package-lock.json | 1246 ---------------- .../nodejs-interop/native-c-api/package.json | 8 - .../native-c-api/platform/main.roc | 10 - examples/nodejs-interop/wasm/README.md | 12 - examples/nodejs-interop/wasm/hello.js | 71 - examples/nodejs-interop/wasm/main.roc | 4 - examples/nodejs-interop/wasm/platform/host.js | 65 - .../nodejs-interop/wasm/platform/host.zig | 53 - .../nodejs-interop/wasm/platform/main.roc | 9 - examples/python-interop/.gitignore | 3 - examples/python-interop/README.md | 82 -- examples/python-interop/build.sh | 27 - examples/python-interop/demo.c | 253 ---- examples/python-interop/libhello.roc | 10 - examples/python-interop/platform/host.c | 115 -- examples/python-interop/platform/main.roc | 16 - examples/python-interop/setup.py | 12 - examples/ruby-interop/.gitignore | 2 - examples/ruby-interop/README.md | 71 - examples/ruby-interop/demo.c | 225 --- examples/ruby-interop/extconf.rb | 10 - examples/ruby-interop/libhello.roc | 10 - examples/ruby-interop/platform/host.c | 119 -- examples/ruby-interop/platform/main.roc | 16 - examples/virtual-dom-wip/ExampleApp.roc | 36 - examples/virtual-dom-wip/example-client.roc | 5 - examples/virtual-dom-wip/example-server.roc | 5 - examples/virtual-dom-wip/platform/Action.roc | 15 - examples/virtual-dom-wip/platform/Html.roc | 271 ---- .../platform/Html/Attributes.roc | 273 ---- .../virtual-dom-wip/platform/Html/Event.roc | 77 - .../platform/Html/Internal/Client.roc | 797 ---------- .../platform/Html/Internal/Server.roc | 121 -- .../platform/Html/Internal/Shared.roc | 154 -- examples/virtual-dom-wip/platform/Json.roc | 1312 ----------------- .../platform/PlatformTasks.roc | 86 -- .../virtual-dom-wip/platform/client-side.roc | 44 - .../virtual-dom-wip/platform/server-side.roc | 29 - .../platform/src/client-side/host.js | 319 ---- .../platform/src/client-side/host.zig | 109 -- .../platform/src/server-side/host.zig | 78 - examples/virtual-dom-wip/readme.md | 97 -- 65 files changed, 1 insertion(+), 8438 deletions(-) delete mode 100644 examples/glue/glue.roc delete mode 100644 examples/glue/rust-platform/.cargo/config.toml delete mode 100644 examples/glue/rust-platform/Cargo.toml delete mode 100644 examples/glue/rust-platform/build.rs delete mode 100644 examples/glue/rust-platform/host.c delete mode 100644 examples/glue/rust-platform/main.roc delete mode 100644 examples/glue/rust-platform/rust-toolchain.toml delete mode 100644 examples/glue/rust-platform/src/glue.rs delete mode 100644 examples/glue/rust-platform/src/lib.rs delete mode 100644 examples/glue/rust-platform/src/main.rs delete mode 100644 examples/jvm-interop/README.md delete mode 100644 examples/jvm-interop/bridge.c delete mode 100755 examples/jvm-interop/build.sh delete mode 100644 examples/jvm-interop/impl.roc delete mode 100644 examples/jvm-interop/javaSource/Demo.java delete mode 100644 examples/jvm-interop/platform.roc delete mode 100644 examples/nodejs-interop/native-c-api/README.md delete mode 100644 examples/nodejs-interop/native-c-api/addon.d.ts delete mode 100644 examples/nodejs-interop/native-c-api/binding.gyp delete mode 100644 examples/nodejs-interop/native-c-api/demo.c delete mode 100644 examples/nodejs-interop/native-c-api/hello.ts delete mode 100644 examples/nodejs-interop/native-c-api/main.roc delete mode 100644 examples/nodejs-interop/native-c-api/package-lock.json delete mode 100644 examples/nodejs-interop/native-c-api/package.json delete mode 100644 examples/nodejs-interop/native-c-api/platform/main.roc delete mode 100644 examples/nodejs-interop/wasm/README.md delete mode 100644 examples/nodejs-interop/wasm/hello.js delete mode 100644 examples/nodejs-interop/wasm/main.roc delete mode 100644 examples/nodejs-interop/wasm/platform/host.js delete mode 100644 examples/nodejs-interop/wasm/platform/host.zig delete mode 100644 examples/nodejs-interop/wasm/platform/main.roc delete mode 100644 examples/python-interop/.gitignore delete mode 100644 examples/python-interop/README.md delete mode 100755 examples/python-interop/build.sh delete mode 100644 examples/python-interop/demo.c delete mode 100644 examples/python-interop/libhello.roc delete mode 100644 examples/python-interop/platform/host.c delete mode 100644 examples/python-interop/platform/main.roc delete mode 100644 examples/python-interop/setup.py delete mode 100644 examples/ruby-interop/.gitignore delete mode 100644 examples/ruby-interop/README.md delete mode 100644 examples/ruby-interop/demo.c delete mode 100644 examples/ruby-interop/extconf.rb delete mode 100644 examples/ruby-interop/libhello.roc delete mode 100644 examples/ruby-interop/platform/host.c delete mode 100644 examples/ruby-interop/platform/main.roc delete mode 100644 examples/virtual-dom-wip/ExampleApp.roc delete mode 100644 examples/virtual-dom-wip/example-client.roc delete mode 100644 examples/virtual-dom-wip/example-server.roc delete mode 100644 examples/virtual-dom-wip/platform/Action.roc delete mode 100644 examples/virtual-dom-wip/platform/Html.roc delete mode 100644 examples/virtual-dom-wip/platform/Html/Attributes.roc delete mode 100644 examples/virtual-dom-wip/platform/Html/Event.roc delete mode 100644 examples/virtual-dom-wip/platform/Html/Internal/Client.roc delete mode 100644 examples/virtual-dom-wip/platform/Html/Internal/Server.roc delete mode 100644 examples/virtual-dom-wip/platform/Html/Internal/Shared.roc delete mode 100644 examples/virtual-dom-wip/platform/Json.roc delete mode 100644 examples/virtual-dom-wip/platform/PlatformTasks.roc delete mode 100644 examples/virtual-dom-wip/platform/client-side.roc delete mode 100644 examples/virtual-dom-wip/platform/server-side.roc delete mode 100644 examples/virtual-dom-wip/platform/src/client-side/host.js delete mode 100644 examples/virtual-dom-wip/platform/src/client-side/host.zig delete mode 100644 examples/virtual-dom-wip/platform/src/server-side/host.zig delete mode 100644 examples/virtual-dom-wip/readme.md diff --git a/examples/README.md b/examples/README.md index 6f2c426009c..d4defa36ca2 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,9 +1,3 @@ # Examples -To run examples: - -```bash -roc run examples/hello-world/main.roc -``` - -[More examples](https://github.com/roc-lang/examples) +Checkout the [roc examples site](https://github.com/roc-lang/examples) to see examples of using roc. diff --git a/examples/glue/glue.roc b/examples/glue/glue.roc deleted file mode 100644 index c988fa87e23..00000000000 --- a/examples/glue/glue.roc +++ /dev/null @@ -1,7 +0,0 @@ -app [main] { pf: platform "rust-platform/main.roc" } - -main = - msg = "Roc <3 Rust, also on stderr!\n" - StdoutWrite "Roc <3 Rust!\n" \{} -> - StderrWrite msg \{} -> - Done diff --git a/examples/glue/rust-platform/.cargo/config.toml b/examples/glue/rust-platform/.cargo/config.toml deleted file mode 100644 index 91cf6cf3f9e..00000000000 --- a/examples/glue/rust-platform/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.x86_64-pc-windows-gnu] -linker = "zig-cc" diff --git a/examples/glue/rust-platform/Cargo.toml b/examples/glue/rust-platform/Cargo.toml deleted file mode 100644 index de0c75b4ff7..00000000000 --- a/examples/glue/rust-platform/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "host" -version = "0.0.1" -authors = ["The Roc Contributors"] -license = "UPL-1.0" -edition = "2021" -links = "app" - -[lib] -name = "host" -path = "src/lib.rs" -crate-type = ["staticlib", "lib"] - -[[bin]] -name = "host" -path = "src/main.rs" - -[dependencies] -roc_app = { path = "roc_app" } -roc_std = { path = "roc_std" } -libc = "0.2" - -[workspace] diff --git a/examples/glue/rust-platform/build.rs b/examples/glue/rust-platform/build.rs deleted file mode 100644 index 47763b34c39..00000000000 --- a/examples/glue/rust-platform/build.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - #[cfg(not(windows))] - println!("cargo:rustc-link-lib=dylib=app"); - - #[cfg(windows)] - println!("cargo:rustc-link-lib=dylib=libapp"); - - println!("cargo:rustc-link-search=."); -} diff --git a/examples/glue/rust-platform/host.c b/examples/glue/rust-platform/host.c deleted file mode 100644 index b9214bcf335..00000000000 --- a/examples/glue/rust-platform/host.c +++ /dev/null @@ -1,3 +0,0 @@ -extern int rust_main(); - -int main() { return rust_main(); } \ No newline at end of file diff --git a/examples/glue/rust-platform/main.roc b/examples/glue/rust-platform/main.roc deleted file mode 100644 index 47017d926ca..00000000000 --- a/examples/glue/rust-platform/main.roc +++ /dev/null @@ -1,17 +0,0 @@ -platform "echo-in-rust" - requires {} { main : _ } - exposes [] - packages {} - imports [] - provides [mainForHost] - -# mainForHost : [StdoutWrite Str (({} -> Op) as Fx0), StderrWrite Str (({} -> Op) as Fx1), Done] as Op -mainForHost : [StdoutWrite Str ({} -> Op), StderrWrite Str ({} -> Op), Done] as Op -mainForHost = main - -# mainForHost : { x: Str, y: {} -> Str } -# mainForHost = -# y = "foo" -# -# when main is -# _ -> { x: "bar", y: \{} -> y } diff --git a/examples/glue/rust-platform/rust-toolchain.toml b/examples/glue/rust-platform/rust-toolchain.toml deleted file mode 100644 index 0abb9617ed3..00000000000 --- a/examples/glue/rust-platform/rust-toolchain.toml +++ /dev/null @@ -1,9 +0,0 @@ -[toolchain] -channel = "1.77.2" - -profile = "default" - -components = [ - # for usages of rust-analyzer or similar tools inside `nix develop` - "rust-src" -] \ No newline at end of file diff --git a/examples/glue/rust-platform/src/glue.rs b/examples/glue/rust-platform/src/glue.rs deleted file mode 100644 index e3e2e524b7e..00000000000 --- a/examples/glue/rust-platform/src/glue.rs +++ /dev/null @@ -1,744 +0,0 @@ -// ⚠️ GENERATED CODE ⚠️ - this entire file was generated by the `roc glue` CLI command - -#![allow(unused_unsafe)] -#![allow(unused_variables)] -#![allow(dead_code)] -#![allow(unused_mut)] -#![allow(non_snake_case)] -#![allow(non_camel_case_types)] -#![allow(non_upper_case_globals)] -#![allow(clippy::undocumented_unsafe_blocks)] -#![allow(clippy::redundant_static_lifetimes)] -#![allow(clippy::unused_unit)] -#![allow(clippy::missing_safety_doc)] -#![allow(clippy::let_and_return)] -#![allow(clippy::missing_safety_doc)] -#![allow(clippy::redundant_static_lifetimes)] -#![allow(clippy::needless_borrow)] -#![allow(clippy::clone_on_copy)] - -type Op_StderrWrite = roc_std::RocStr; -type Op_StdoutWrite = roc_std::RocStr; -type TODO_roc_function_69 = roc_std::RocStr; -type TODO_roc_function_70 = roc_std::RocStr; - -#[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" -))] -#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)] -#[repr(u8)] -pub enum discriminant_Op { - Done = 0, - StderrWrite = 1, - StdoutWrite = 2, -} - -impl core::fmt::Debug for discriminant_Op { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::Done => f.write_str("discriminant_Op::Done"), - Self::StderrWrite => f.write_str("discriminant_Op::StderrWrite"), - Self::StdoutWrite => f.write_str("discriminant_Op::StdoutWrite"), - } - } -} - -#[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" -))] -#[repr(transparent)] -pub struct Op { - pointer: *mut union_Op, -} - -#[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" -))] -#[repr(C)] -union union_Op { - StderrWrite: core::mem::ManuallyDrop, - StdoutWrite: core::mem::ManuallyDrop, - _sizer: [u8; 8], -} - -#[cfg(any( - target_arch = "arm", - target_arch = "arm", - target_arch = "aarch64", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86", - target_arch = "x86_64", - target_arch = "x86_64" -))] -//TODO HAS CLOSURE 2 -#[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" -))] -#[repr(C)] -pub struct RocFunction_66 { - pub closure_data: roc_std::RocList, -} - -impl RocFunction_66 { - pub fn force_thunk(mut self, arg_0: ()) -> Op { - extern "C" { - fn roc__mainForHost_0_caller(arg_0: &(), closure_data: *mut u8, output: *mut Op); - } - - let mut output = std::mem::MaybeUninit::uninit(); - let ptr = self.closure_data.as_mut_ptr(); - unsafe { roc__mainForHost_0_caller(&arg_0, ptr, output.as_mut_ptr()) }; - unsafe { output.assume_init() } - } -} - -#[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" -))] -#[repr(C)] -pub struct RocFunction_67 { - pub closure_data: roc_std::RocList, -} - -impl RocFunction_67 { - pub fn force_thunk(mut self, arg_0: ()) -> Op { - extern "C" { - fn roc__mainForHost_1_caller(arg_0: &(), closure_data: *mut u8, output: *mut Op); - } - - let mut output = std::mem::MaybeUninit::uninit(); - let ptr = self.closure_data.as_mut_ptr(); - unsafe { roc__mainForHost_1_caller(&arg_0, ptr, output.as_mut_ptr()) }; - unsafe { output.assume_init() } - } -} - -impl Op { - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - #[inline(always)] - fn storage(&self) -> Option<&core::cell::Cell> { - let mask = match std::mem::size_of::() { - 4 => 0b11, - 8 => 0b111, - _ => unreachable!(), - }; - - // NOTE: pointer provenance is probably lost here - let unmasked_address = (self.pointer as usize) & !mask; - let untagged = unmasked_address as *const core::cell::Cell; - - if untagged.is_null() { - None - } else { - unsafe { Some(&*untagged.sub(1)) } - } - } - - #[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] - /// Returns which variant this tag union holds. Note that this never includes a payload! - pub fn discriminant(&self) -> discriminant_Op { - // The discriminant is stored in the unused bytes at the end of the recursive pointer - unsafe { core::mem::transmute::((self.pointer as u8) & 0b11) } - } - - #[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] - /// Internal helper - fn tag_discriminant(pointer: *mut union_Op, discriminant: discriminant_Op) -> *mut union_Op { - // The discriminant is stored in the unused bytes at the end of the union pointer - let untagged = (pointer as usize) & (!0b11 as usize); - let tagged = untagged | (discriminant as usize); - - tagged as *mut union_Op - } - - #[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] - /// Internal helper - fn union_pointer(&self) -> *mut union_Op { - // The discriminant is stored in the unused bytes at the end of the union pointer - ((self.pointer as usize) & (!0b11 as usize)) as *mut union_Op - } - - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - /// A tag named Done, which has no payload. - pub const Done: Self = Self { - pointer: core::ptr::null_mut(), - }; - - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload at index 0. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`. - pub unsafe fn get_StderrWrite_0(&self) -> roc_std::RocStr { - debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite); - - extern "C" { - #[link_name = "roc__getter__2_generic"] - fn getter(_: *mut roc_std::RocStr, _: *const Op); - } - - let mut ret = core::mem::MaybeUninit::uninit(); - getter(ret.as_mut_ptr(), self); - ret.assume_init() - } - - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload at index 1. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`. - pub unsafe fn get_StderrWrite_1(&self) -> RocFunction_67 { - debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite); - - extern "C" { - #[link_name = "roc__getter__3_size"] - fn size() -> usize; - - #[link_name = "roc__getter__3_generic"] - fn getter(_: *mut u8, _: *const Op); - } - - // allocate memory to store this variably-sized value - // allocates with roc_alloc, but that likely still uses the heap - let it = std::iter::repeat(0xAAu8).take(size()); - let mut bytes = roc_std::RocList::from_iter(it); - - getter(bytes.as_mut_ptr(), self); - - RocFunction_67 { - closure_data: bytes, - } - } - - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - /// Construct a tag named `StderrWrite`, with the appropriate payload - pub fn StderrWrite(arg: Op_StderrWrite) -> Self { - let size = core::mem::size_of::(); - let align = core::mem::align_of::() as u32; - - unsafe { - let ptr = roc_std::roc_alloc_refcounted::(); - - *ptr = union_Op { - StderrWrite: core::mem::ManuallyDrop::new(arg), - }; - - Self { - pointer: Self::tag_discriminant(ptr, discriminant_Op::StderrWrite), - } - } - } - - #[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and convert it to `StderrWrite`'s payload. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`. - pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite { - debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite); - let payload = { - let ptr = (self.pointer as usize & !0b11) as *mut union_Op; - let mut uninitialized = core::mem::MaybeUninit::uninit(); - let swapped = unsafe { - core::mem::replace( - &mut (*ptr).StderrWrite, - core::mem::ManuallyDrop::new(uninitialized.assume_init()), - ) - }; - - core::mem::forget(self); - - core::mem::ManuallyDrop::into_inner(swapped) - }; - - payload - } - - #[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`. - pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite { - debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite); - let payload = { - let ptr = (self.pointer as usize & !0b11) as *mut union_Op; - - unsafe { &(*ptr).StderrWrite } - }; - - &payload - } - - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload at index 0. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`. - pub unsafe fn get_StdoutWrite_0(&self) -> roc_std::RocStr { - debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite); - - extern "C" { - #[link_name = "roc__getter__2_generic"] - fn getter(_: *mut roc_std::RocStr, _: *const Op); - } - - let mut ret = core::mem::MaybeUninit::uninit(); - getter(ret.as_mut_ptr(), self); - ret.assume_init() - } - - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload at index 1. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`. - pub unsafe fn get_StdoutWrite_1(&self) -> RocFunction_66 { - debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite); - - extern "C" { - #[link_name = "roc__getter__3_size"] - fn size() -> usize; - - #[link_name = "roc__getter__3_generic"] - fn getter(_: *mut u8, _: *const Op); - } - - // allocate memory to store this variably-sized value - // allocates with roc_alloc, but that likely still uses the heap - let it = std::iter::repeat(0xAAu8).take(size()); - let mut bytes = roc_std::RocList::from_iter(it); - - getter(bytes.as_mut_ptr(), self); - - RocFunction_66 { - closure_data: bytes, - } - } - - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - /// Construct a tag named `StdoutWrite`, with the appropriate payload - pub fn StdoutWrite(arg: Op_StdoutWrite) -> Self { - let size = core::mem::size_of::(); - let align = core::mem::align_of::() as u32; - - unsafe { - let ptr = roc_std::roc_alloc_refcounted::(); - - *ptr = union_Op { - StdoutWrite: core::mem::ManuallyDrop::new(arg), - }; - - Self { - pointer: Self::tag_discriminant(ptr, discriminant_Op::StdoutWrite), - } - } - } - - #[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and convert it to `StdoutWrite`'s payload. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`. - pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite { - debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite); - let payload = { - let ptr = (self.pointer as usize & !0b11) as *mut union_Op; - let mut uninitialized = core::mem::MaybeUninit::uninit(); - let swapped = unsafe { - core::mem::replace( - &mut (*ptr).StdoutWrite, - core::mem::ManuallyDrop::new(uninitialized.assume_init()), - ) - }; - - core::mem::forget(self); - - core::mem::ManuallyDrop::into_inner(swapped) - }; - - payload - } - - #[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`. - pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite { - debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite); - let payload = { - let ptr = (self.pointer as usize & !0b11) as *mut union_Op; - - unsafe { &(*ptr).StdoutWrite } - }; - - &payload - } - - #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] - /// Returns which variant this tag union holds. Note that this never includes a payload! - pub fn discriminant(&self) -> discriminant_Op { - // The discriminant is stored in the unused bytes at the end of the recursive pointer - unsafe { core::mem::transmute::((self.pointer as u8) & 0b111) } - } - - #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] - /// Internal helper - fn tag_discriminant(pointer: *mut union_Op, discriminant: discriminant_Op) -> *mut union_Op { - // The discriminant is stored in the unused bytes at the end of the union pointer - let untagged = (pointer as usize) & (!0b111 as usize); - let tagged = untagged | (discriminant as usize); - - tagged as *mut union_Op - } - - #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] - /// Internal helper - fn union_pointer(&self) -> *mut union_Op { - // The discriminant is stored in the unused bytes at the end of the union pointer - ((self.pointer as usize) & (!0b111 as usize)) as *mut union_Op - } - - #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and convert it to `StderrWrite`'s payload. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`. - pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite { - debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite); - let payload = { - let ptr = (self.pointer as usize & !0b111) as *mut union_Op; - let mut uninitialized = core::mem::MaybeUninit::uninit(); - let swapped = unsafe { - core::mem::replace( - &mut (*ptr).StderrWrite, - core::mem::ManuallyDrop::new(uninitialized.assume_init()), - ) - }; - - core::mem::forget(self); - - core::mem::ManuallyDrop::into_inner(swapped) - }; - - payload - } - - #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`. - pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite { - debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite); - let payload = { - let ptr = (self.pointer as usize & !0b111) as *mut union_Op; - - unsafe { &(*ptr).StderrWrite } - }; - - &payload - } - - #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and convert it to `StdoutWrite`'s payload. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`. - pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite { - debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite); - let payload = { - let ptr = (self.pointer as usize & !0b111) as *mut union_Op; - let mut uninitialized = core::mem::MaybeUninit::uninit(); - let swapped = unsafe { - core::mem::replace( - &mut (*ptr).StdoutWrite, - core::mem::ManuallyDrop::new(uninitialized.assume_init()), - ) - }; - - core::mem::forget(self); - - core::mem::ManuallyDrop::into_inner(swapped) - }; - - payload - } - - #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] - /// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload. - /// (Always examine `.discriminant()` first to make sure this is the correct variant!) - /// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`. - pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite { - debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite); - let payload = { - let ptr = (self.pointer as usize & !0b111) as *mut union_Op; - - unsafe { &(*ptr).StdoutWrite } - }; - - &payload - } -} - -impl Drop for Op { - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - fn drop(&mut self) { - // We only need to do any work if there's actually a heap-allocated payload. - if let Some(storage) = self.storage() { - let mut new_storage = storage.get(); - - // Decrement the refcount - let needs_dealloc = !new_storage.is_readonly() && new_storage.decrease(); - - if needs_dealloc { - // Drop the payload first. - match self.discriminant() { - discriminant_Op::Done => {} - discriminant_Op::StderrWrite => unsafe { - core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StderrWrite) - }, - discriminant_Op::StdoutWrite => unsafe { - core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StdoutWrite) - }, - } - - // Dealloc the pointer - let alignment = - core::mem::align_of::().max(core::mem::align_of::()); - - unsafe { - crate::roc_dealloc(storage.as_ptr().cast(), alignment as u32); - } - } else { - // Write the storage back. - storage.set(new_storage); - } - } - } -} - -impl Eq for Op {} - -impl PartialEq for Op { - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - fn eq(&self, other: &Self) -> bool { - if self.discriminant() != other.discriminant() { - return false; - } - - unsafe { - match self.discriminant() { - discriminant_Op::Done => true, - discriminant_Op::StderrWrite => { - (&*self.union_pointer()).StderrWrite == (&*other.union_pointer()).StderrWrite - } - discriminant_Op::StdoutWrite => { - (&*self.union_pointer()).StdoutWrite == (&*other.union_pointer()).StdoutWrite - } - } - } - } -} - -impl PartialOrd for Op { - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - fn partial_cmp(&self, other: &Self) -> Option { - match self.discriminant().partial_cmp(&other.discriminant()) { - Some(core::cmp::Ordering::Equal) => {} - not_eq => return not_eq, - } - - unsafe { - match self.discriminant() { - discriminant_Op::Done => Some(core::cmp::Ordering::Equal), - discriminant_Op::StderrWrite => (&*self.union_pointer()) - .StderrWrite - .partial_cmp(&(&*other.union_pointer()).StderrWrite), - discriminant_Op::StdoutWrite => (&*self.union_pointer()) - .StdoutWrite - .partial_cmp(&(&*other.union_pointer()).StdoutWrite), - } - } - } -} - -impl Ord for Op { - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - match self.discriminant().cmp(&other.discriminant()) { - core::cmp::Ordering::Equal => {} - not_eq => return not_eq, - } - - unsafe { - match self.discriminant() { - discriminant_Op::Done => core::cmp::Ordering::Equal, - discriminant_Op::StderrWrite => (&*self.union_pointer()) - .StderrWrite - .cmp(&(&*other.union_pointer()).StderrWrite), - discriminant_Op::StdoutWrite => (&*self.union_pointer()) - .StdoutWrite - .cmp(&(&*other.union_pointer()).StdoutWrite), - } - } - } -} - -impl Clone for Op { - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - fn clone(&self) -> Self { - if let Some(storage) = self.storage() { - let mut new_storage = storage.get(); - if !new_storage.is_readonly() { - new_storage.increment_reference_count(); - storage.set(new_storage); - } - } - - Self { - pointer: self.pointer, - } - } -} - -impl core::hash::Hash for Op { - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - fn hash(&self, state: &mut H) { - match self.discriminant() { - discriminant_Op::Done => discriminant_Op::Done.hash(state), - discriminant_Op::StderrWrite => unsafe { - discriminant_Op::StderrWrite.hash(state); - (&*self.union_pointer()).StderrWrite.hash(state); - }, - discriminant_Op::StdoutWrite => unsafe { - discriminant_Op::StdoutWrite.hash(state); - (&*self.union_pointer()).StdoutWrite.hash(state); - }, - } - } -} - -impl core::fmt::Debug for Op { - #[cfg(any( - target_arch = "arm", - target_arch = "aarch64", - target_arch = "wasm32", - target_arch = "x86", - target_arch = "x86_64" - ))] - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str("Op::")?; - - unsafe { - match self.discriminant() { - discriminant_Op::Done => f.write_str("Done"), - discriminant_Op::StderrWrite => f - .debug_tuple("StderrWrite") - // TODO HAS CLOSURE - .finish(), - discriminant_Op::StdoutWrite => f - .debug_tuple("StdoutWrite") - // TODO HAS CLOSURE - .finish(), - } - } - } -} diff --git a/examples/glue/rust-platform/src/lib.rs b/examples/glue/rust-platform/src/lib.rs deleted file mode 100644 index 022ea94a18e..00000000000 --- a/examples/glue/rust-platform/src/lib.rs +++ /dev/null @@ -1,123 +0,0 @@ -#![allow(non_snake_case)] - -use core::ffi::c_void; -use roc_app::Op; -use roc_std::RocStr; -use std::ffi::CStr; -use std::io::Write; -use std::os::raw::c_char; - -use roc_app::mainForHost as roc_main; - -#[no_mangle] -pub unsafe extern "C" fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void { - return libc::malloc(size); -} - -#[no_mangle] -pub unsafe extern "C" fn roc_realloc( - c_ptr: *mut c_void, - new_size: usize, - _old_size: usize, - _alignment: u32, -) -> *mut c_void { - return libc::realloc(c_ptr, new_size); -} - -#[no_mangle] -pub unsafe extern "C" fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) { - return libc::free(c_ptr); -} - -#[no_mangle] -pub unsafe extern "C" fn roc_panic(msg: *mut RocStr, tag_id: u32) { - match tag_id { - 0 => { - eprintln!("Roc standard library hit a panic: {}", &*msg); - } - 1 => { - eprintln!("Application hit a panic: {}", &*msg); - } - _ => unreachable!(), - } - std::process::exit(1); -} - -#[no_mangle] -pub unsafe extern "C" fn roc_dbg(loc: *mut RocStr, msg: *mut RocStr, src: *mut RocStr) { - eprintln!("[{}] {} = {}", &*loc, &*src, &*msg); -} - -#[no_mangle] -pub unsafe extern "C" fn roc_memset(dst: *mut c_void, c: i32, n: usize) -> *mut c_void { - libc::memset(dst, c, n) -} - -#[cfg(unix)] -#[no_mangle] -pub unsafe extern "C" fn roc_getppid() -> libc::pid_t { - libc::getppid() -} - -#[cfg(unix)] -#[no_mangle] -pub unsafe extern "C" fn roc_mmap( - addr: *mut libc::c_void, - len: libc::size_t, - prot: libc::c_int, - flags: libc::c_int, - fd: libc::c_int, - offset: libc::off_t, -) -> *mut libc::c_void { - libc::mmap(addr, len, prot, flags, fd, offset) -} - -#[cfg(unix)] -#[no_mangle] -pub unsafe extern "C" fn roc_shm_open( - name: *const libc::c_char, - oflag: libc::c_int, - mode: libc::mode_t, -) -> libc::c_int { - libc::shm_open(name, oflag, mode as libc::c_uint) -} - -#[no_mangle] -pub extern "C" fn rust_main() -> i32 { - use roc_app::discriminant_Op::*; - - println!("Let's do things!"); - - let mut op: Op = roc_main(); - - loop { - match op.discriminant() { - StdoutWrite => { - let stdout_write = op.get_StdoutWrite(); - let output: RocStr = stdout_write.f0; - op = unsafe { stdout_write.f1.force_thunk() }; - - if let Err(e) = std::io::stdout().write_all(output.as_bytes()) { - panic!("Writing to stdout failed! {:?}", e); - } - } - StderrWrite => { - let stderr_write = op.get_StderrWrite(); - let output: RocStr = stderr_write.f0; - op = unsafe { stderr_write.f1.force_thunk() }; - - if let Err(e) = std::io::stderr().write_all(output.as_bytes()) { - panic!("Writing to stdout failed! {:?}", e); - } - } - Done => { - break; - } - } - } - - println!("Done!"); - - // Exit code - 0 -} diff --git a/examples/glue/rust-platform/src/main.rs b/examples/glue/rust-platform/src/main.rs deleted file mode 100644 index 0765384f29f..00000000000 --- a/examples/glue/rust-platform/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - std::process::exit(host::rust_main() as _); -} diff --git a/examples/jvm-interop/README.md b/examples/jvm-interop/README.md deleted file mode 100644 index 9df6610ded1..00000000000 --- a/examples/jvm-interop/README.md +++ /dev/null @@ -1,210 +0,0 @@ -# JVM interop -This is a demo for calling Roc code from Java, and some other JVM languages. - - -## Prerequisites - -The following was tested on NixOS, with `openjdk 17.0.5` and `clang 13.0.1` but should work with most recent versions of those (jdk>=10) on most modern Linux and MacOS.\ -You're welcome to test on your machine and tell me (via [Zulip](https://roc.zulipchat.com/#narrow/pm-with/583319-dank)) if you ran into any issues or limitations. - -## Goal -We'll make a few examples, showing basic data type convertions and function calls between Roc and Java (and later some other JVM languages): -- A string formatter. -- A Function that multiples an array by a scalar. -- A factorial function that, for the sake of demonstration, throws a RuntimeException for negative integers. - -This will be done with the help of [Java Native Interface](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/). -We will be using C to bridge between Java and Roc. - -## Structure -As the time of writing this post, the following is the current bare bones tree of a jvm-interop: - -``` console -. -├── impl.roc -├── platform.roc -├── bridge.c -└── javaSource - └── Demo.java -``` - -impl.roc is the application where we actually implement our native Roc functions.\ -platform.roc as the name suggests contains platform logic, (but doesn't really have much here, mostly just) exposes functions to the host - bridge.c\ -bridge.c is the JNI bridge, it's the host that implements the Roc functions (e.g roc_alloc) and the JNI functions that act like the bridge between Roc and Java (bridge as in, doing type conversions between the languages, needed jvm boilerplate, etc). - -For each of our native Roc functions, in the application (impl.roc), we have a corresponding `Java_javaSource_Demo_FUNC` C function that handles the "behind the scenes", this includes type conversions between the languages, transforming roc panics into java exceptions and basically all the glue code necessary. - - -Just so you know what to expect, our Roc functions look like this; -``` coffee -interpolateString : Str -> Str -interpolateString = \name -> - "Hello from Roc $(name)!!!🤘🤘🤘" - - -mulArrByScalar : List I32, I32 -> List I32 -mulArrByScalar = \arr, scalar -> - List.map arr \x -> x * scalar - - -factorial : I64 -> I64 -factorial = \n -> - if n < 0 then - # while we get the chance, examplify a roc panic in an interop - crash "No negatives here!!!" - else if n == 0 then - 1 - else - n * (factorial (n - 1)) -``` - -Nothing too crazy. Again, do note how we crash if n < 0, see how this would play out from the Java side. - -Now let's take a quick look on the Java side of things; - -``` java -public class Demo { - - static { - System.loadLibrary("interop"); - } - - public static native String sayHello(String num); - - public static native int[] mulArrByScalar(int[] arr, int scalar); - - public static native long factorial(long n) throws RuntimeException; - - - public static void main(String[] args) { - - // string demo - System.out.println(sayHello("Brendan") + "\n"); - - // array demo - int[] arr = {10, 20, 30, 40}; - int x = 3; - System.out.println(Arrays.toString(arr) + - " multiplied by " + x + - " results in " + Arrays.toString(mulArrByScalar(arr, x)) + - "\n"); - - // number + panic demo - long n = 5; - System.out.println("Factorial of " + n + " is " + factorial(n)); - - } -} -``` -First we load our library - "interop", which is a shared library (`.so` file) that our Roc+C code compiles to.\ -Then, we declare our native functions with suitable types and throws annotation.\ -Finally in main we test it out with some inputs. - -## See it in action -##### For brevity's sake we'll run the build script and omit some of its (intentionally) verbose output: - -```console -[nix-shell:~/dev/roc/examples/jvm-interop]$ ./build.sh && java javaSource.Greeter -Hello from Roc Brendan!!!🤘🤘🤘 - -[10, 20, 30, 40] multiplied by 3 results in [30, 60, 90, 120] - -Factorial of 5 is 120 -``` -That's pretty cool!\ -Let's also see what happens if in the code above we define n to be -1: -``` console -[nix-shell:~/dev/roc/examples/jvm-interop]$ ./build.sh && java javaSource.Greeter -Hello from Roc Brendan!!!🤘🤘🤘 - -[10, 20, 30, 40] multiplied by 3 results in [30, 60, 90, 120] - -Exception in thread "main" java.lang.RuntimeException: No negatives here!!! - at javaSource.Demo.factorial(Native Method) - at javaSource.Demo.main(Demo.java:36) -``` -And as we expected, it runs the first two examples fine, throws a RuntimeException on the third. - -Since we're talking JVM Bytecode, we can pretty much call our native function from any language that speaks JVM Bytecode. - -Note: The JNI code depends on a dynamic lib, containing our native implementation, that now resides in our working directory.\ -So in the following examples, we'll make sure that our working directory is in LD_LIBRARY_PATH.\ -Generally speaking, you'd paobably add your dynamic library to a spot that's already on your path, for convenience sake.\ -So first, we run: - -```console -[nix-shell:~/dev/roc/examples/jvm-interop]$ export LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH -``` - -Now, let's try Kotlin! -```console -[nix-shell:~/dev/roc/examples/jvm-interop]$ kotlin -Welcome to Kotlin version 1.7.20 (JRE 17.0.5+8-nixos) -Type :help for help, :quit for quit - ->>> import javaSource.Demo - ->>> Demo.sayHello("Kotlin Users") -res1: kotlin.String = Hello from Roc Kotlin Users!!!🤘🤘🤘 - ->>> Demo.mulArrByScalar(intArrayOf(10, 20, 30, 40), 101).contentToString() -res2: kotlin.String = [1010, 2020, 3030, 4040] - ->>> Demo.factorial(10) -res3: kotlin.Long = 3628800 -``` -And it just works, out of the box! - -Now let's do Scala - -```console -[nix-shell:~/dev/roc/examples/jvm-interop]$ scala -Welcome to Scala 2.13.10 (OpenJDK 64-Bit Server VM, Java 17.0.5). -Type in expressions for evaluation. Or try :help. - -scala> import javaSource.Demo -import javaSource.Demo - -scala> Demo.sayHello("Scala Users") -val res0: String = Hello from Roc Scala Users!!!🤘🤘🤘 - -scala> Demo.mulArrByScalar(Array(10, 20, 30, 40), 1001) -val res1: Array[Int] = Array(10010, 20020, 30030, 40040) - -scala> Demo.factorial(-2023) -java.lang.RuntimeException: No negatives here!!! - at javaSource.Demo.factorial(Native Method) - ... 32 elided -``` -And it also works beautifully. - -Last one - Clojure -Do note that in Clojure you need to add a `-Sdeps '{:paths ["."]}'` flag to add the working directory to paths. -``` console -[nix-shell:~/dev/roc/examples/jvm-interop]$ clj -Sdeps '{:paths ["."]}' -Clojure 1.11.1 -user=> (import 'javaSource.Demo) -javaSource.Demo - -user=> (Demo/sayHello "Clojure Users") -"Hello from Roc Clojure Users!!!🤘🤘🤘" - -user=> (seq (Demo/mulArrByScalar (int-array [10 20 30]) 9)) ; seq to pretty-print -(90 180 270) - -user=> (Demo/factorial 15) -1307674368000 -``` - -Test it out on your favorite JVM lang!\ -And again, if anything goes not according to plan, tell me in the link above and we'll figure it out. - -## Notes on building -The process is basically the following: -1. Build our application + platform .roc files with (`roc build impl.roc --no-link`) into an object file -2. Generate a C header file (for bridge.c's) using java. -3. Bundle up the C bridge together with our object file into a shared object. - -And that's it, use that shared object from your JVM language. Note every JVM language has its own way to declare that native library so you may want to look at it, or do like in the demo and declare it in java and use the binding from anywhere. - -I suggest reading the build script (build.sh) and adjusting according to your setup. diff --git a/examples/jvm-interop/bridge.c b/examples/jvm-interop/bridge.c deleted file mode 100644 index 4bd4aafc278..00000000000 --- a/examples/jvm-interop/bridge.c +++ /dev/null @@ -1,384 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "javaSource_Demo.h" - -JavaVM* vm; - -#define ERR_MSG_MAX_SIZE 256 - -jmp_buf exception_buffer; -char* err_msg[ERR_MSG_MAX_SIZE] = {0}; - -jint JNI_OnLoad(JavaVM *loadedVM, void *reserved) -{ - // https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html - vm = loadedVM; - return JNI_VERSION_1_2; -} - -void *roc_alloc(size_t size, unsigned int alignment) -{ - return malloc(size); -} - -void *roc_realloc(void *ptr, size_t new_size, size_t old_size, - unsigned int alignment) -{ - return realloc(ptr, new_size); -} - -void roc_dealloc(void *ptr, unsigned int alignment) -{ - free(ptr); -} - -void *roc_memset(void *str, int c, size_t n) -{ - return memset(str, c, n); -} - -// Reference counting - -// If the refcount is set to this, that means the allocation is -// stored in readonly memory in the binary, and we must not -// attempt to increment or decrement it; if we do, we'll segfault! -const ssize_t REFCOUNT_READONLY = 0; -const ssize_t REFCOUNT_ONE = (ssize_t)PTRDIFF_MIN; -const size_t MASK = (size_t)PTRDIFF_MIN; - -// Increment reference count, given a pointer to the first element in a collection. -// We don't need to check for overflow because in order to overflow a usize worth of refcounts, -// you'd need to somehow have more pointers in memory than the OS's virtual address space can hold. -void incref(uint8_t* bytes, uint32_t alignment) -{ - ssize_t *refcount_ptr = ((ssize_t *)bytes) - 1; - ssize_t refcount = *refcount_ptr; - - if (refcount != REFCOUNT_READONLY) { - *refcount_ptr = refcount + 1; - } -} - -// Decrement reference count, given a pointer to the first element in a collection. -// Then call roc_dealloc if nothing is referencing this collection anymore. -void decref(uint8_t* bytes, uint32_t alignment) -{ - if (bytes == NULL) { - return; - } - - size_t extra_bytes = (sizeof(size_t) >= (size_t)alignment) ? sizeof(size_t) : (size_t)alignment; - ssize_t *refcount_ptr = ((ssize_t *)bytes) - 1; - ssize_t refcount = *refcount_ptr; - - if (refcount != REFCOUNT_READONLY) { - *refcount_ptr = refcount - 1; - - if (refcount == REFCOUNT_ONE) { - void *original_allocation = (void *)(refcount_ptr - (extra_bytes - sizeof(size_t))); - - roc_dealloc(original_allocation, alignment); - } - } -} - -struct RocListI32 -{ - int32_t *bytes; - size_t len; - size_t capacity; -}; - -struct RocListI32 init_roclist_i32(int32_t *bytes, size_t len) -{ - if (len == 0) - { - struct RocListI32 ret = { - .len = 0, - .bytes = NULL, - .capacity = 0, - }; - - return ret; - } - else - { - size_t refcount_size = sizeof(size_t); - ssize_t* data = (ssize_t*)roc_alloc(len + refcount_size, alignof(size_t)); - data[0] = REFCOUNT_ONE; - int32_t *new_content = (int32_t *)(data + 1); - - struct RocListI32 ret; - - memcpy(new_content, bytes, len * sizeof(int32_t)); - - ret.bytes = new_content; - ret.len = len; - ret.capacity = len; - - return ret; - } -} -// RocListU8 (List U8) - -struct RocListU8 -{ - uint8_t *bytes; - size_t len; - size_t capacity; -}; - -struct RocListU8 init_roclist_u8(uint8_t *bytes, size_t len) -{ - if (len == 0) - { - struct RocListU8 ret = { - .len = 0, - .bytes = NULL, - .capacity = 0, - }; - - return ret; - } - else - { - - size_t refcount_size = sizeof(size_t); - ssize_t* data = (ssize_t*)roc_alloc(len + refcount_size, alignof(size_t)); - data[0] = REFCOUNT_ONE; - uint8_t *new_content = (uint8_t *)(data + 1); - - struct RocListU8 ret; - - memcpy(new_content, bytes, len * sizeof(uint8_t)); - - ret.bytes = new_content; - ret.len = len; - ret.capacity = len; - - return ret; - } -} - -// RocStr - -struct RocStr -{ - uint8_t *bytes; - size_t len; - size_t capacity; -}; - -struct RocStr init_rocstr(uint8_t *bytes, size_t len) -{ - if (len < sizeof(struct RocStr)) - { - // Start out with zeroed memory, so that - // if we end up comparing two small RocStr values - // for equality, we won't risk memory garbage resulting - // in two equal strings appearing unequal. - struct RocStr ret = { - .len = 0, - .bytes = NULL, - .capacity = 0, - }; - - // Copy the bytes into the stack allocation - memcpy(&ret, bytes, len); - - // Record the string's len in the last byte of the stack allocation - ((uint8_t *)&ret)[sizeof(struct RocStr) - 1] = (uint8_t)len | 0b10000000; - - return ret; - } - else - { - // A large RocStr is the same as a List U8 (aka RocListU8) in memory. - struct RocListU8 roc_bytes = init_roclist_u8(bytes, len); - - struct RocStr ret = { - .len = roc_bytes.len, - .bytes = roc_bytes.bytes, - .capacity = roc_bytes.capacity, - }; - - return ret; - } -} - -bool is_small_str(struct RocStr str) -{ - return ((ssize_t)str.capacity) < 0; -} - -bool is_seamless_str_slice(struct RocStr str) -{ - return ((ssize_t)str.len) < 0; -} - -bool is_seamless_listi32_slice(struct RocListI32 list) -{ - return ((ssize_t)list.capacity) < 0; -} - -// Determine the len of the string, taking into -// account the small string optimization -size_t roc_str_len(struct RocStr str) -{ - uint8_t *bytes = (uint8_t *)&str; - uint8_t last_byte = bytes[sizeof(str) - 1]; - uint8_t last_byte_xored = last_byte ^ 0b10000000; - size_t small_len = (size_t)(last_byte_xored); - size_t big_len = str.len; - - // Avoid branch misprediction costs by always - // determining both small_len and big_len, - // so this compiles to a cmov instruction. - if (is_small_str(str)) - { - return small_len; - } - else - { - return big_len; - } -} - -__attribute__((noreturn)) void roc_panic(struct RocStr *msg, unsigned int tag_id) -{ - char* bytes = is_small_str(*msg) ? (char*)msg : (char*)msg->bytes; - const size_t str_len = roc_str_len(*msg); - - int len = str_len > ERR_MSG_MAX_SIZE ? ERR_MSG_MAX_SIZE : str_len; - strncpy((char*)err_msg, bytes, len); - - // Free the underlying allocation if needed. - if (!is_small_str(*msg)) { - if (is_seamless_str_slice(*msg)){ - decref((uint8_t *)(msg->capacity << 1), alignof(uint8_t *)); - } - else { - decref(msg->bytes, alignof(uint8_t *)); - } - } - - longjmp(exception_buffer, 1); -} - -void roc_dbg(struct RocStr *loc, struct RocStr *msg, struct RocStr *src) { - char* loc_bytes = is_small_str(*loc) ? (char*)loc : (char*)loc->bytes; - char* src_bytes = is_small_str(*src) ? (char*)src : (char*)src->bytes; - char* msg_bytes = is_small_str(*msg) ? (char*)msg : (char*)msg->bytes; - fprintf(stderr, "[%s] %s = %s\n", loc_bytes, src_bytes, msg_bytes); -} - -extern void roc__programForHost_1__InterpolateString_caller(struct RocStr *name, char *closure_data, struct RocStr *ret); - -extern void roc__programForHost_1__MulArrByScalar_caller(struct RocListI32 *arr, int32_t *scalar, char *closure_data, struct RocListI32 *ret); - -extern void roc__programForHost_1__Factorial_caller(int64_t *scalar, char *closure_data, int64_t *ret); - - -JNIEXPORT jstring JNICALL Java_javaSource_Demo_sayHello - (JNIEnv *env, jobject thisObj, jstring name) -{ - const char *jnameChars = (*env)->GetStringUTFChars(env, name, 0); - // we copy just in case the jvm would try to reclaim that mem - uint8_t *cnameChars = (uint8_t *)strdup(jnameChars); - size_t nameLength = (size_t) (*env)->GetStringLength(env, name); - (*env)->ReleaseStringUTFChars(env, name, jnameChars); - - - struct RocStr rocName = init_rocstr(cnameChars, nameLength); - struct RocStr ret = {0}; - - // Call the Roc function to populate `ret`'s bytes. - roc__programForHost_1__InterpolateString_caller(&rocName, 0, &ret); - jbyte *bytes = (jbyte*)(is_small_str(ret) ? (uint8_t*)&ret : ret.bytes); - - // java being java making this a lot harder than it needs to be - // https://stackoverflow.com/questions/32205446/getting-true-utf-8-characters-in-java-jni - // https://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html#wp16542 - // but as i refuse converting those manually to their correct form, we just let the jvm handle the conversion - // by first making a java byte array then converting the byte array to our final jstring - jbyteArray byteArray = (*env)->NewByteArray(env, ret.len); - (*env)->SetByteArrayRegion(env, byteArray, 0, ret.len, bytes); - - jstring charsetName = (*env)->NewStringUTF(env, "UTF-8"); - jclass stringClass = (*env)->FindClass(env, "java/lang/String"); - // https://docs.oracle.com/javase/7/docs/jdk/api/jpda/jdi/com/sun/jdi/doc-files/signature.html - jmethodID stringConstructor = (*env)->GetMethodID(env, stringClass, "", "([BLjava/lang/String;)V"); - jstring result = (*env)->NewObject(env, stringClass, stringConstructor, byteArray, charsetName); - - // cleanup - if (!is_seamless_str_slice(ret)) { - decref(ret.bytes, alignof(uint8_t *)); - } - - (*env)->DeleteLocalRef(env, charsetName); - (*env)->DeleteLocalRef(env, byteArray); - - free(cnameChars); - - return result; -} - - -JNIEXPORT jintArray JNICALL Java_javaSource_Demo_mulArrByScalar - (JNIEnv *env, jobject thisObj, jintArray arr, jint scalar) -{ - // extract data from jvm types - jint* jarr = (*env)->GetIntArrayElements(env, arr, NULL); - jsize len = (*env)->GetArrayLength(env, arr); - - // pass data to platform - struct RocListI32 originalArray = init_roclist_i32(jarr, len); - incref((void *)&originalArray, alignof(int32_t*)); - struct RocListI32 ret = {0}; - - roc__programForHost_1__MulArrByScalar_caller(&originalArray, &scalar, 0, &ret); - - // create jvm constructs - jintArray multiplied = (*env)->NewIntArray(env, ret.len); - (*env)->SetIntArrayRegion(env, multiplied, 0, ret.len, (jint*) ret.bytes); - - // cleanup - (*env)->ReleaseIntArrayElements(env, arr, jarr, 0); - - if (is_seamless_listi32_slice(ret)) { - decref((void *)(ret.capacity << 1), alignof(uint8_t *)); - } - else { - decref((void *)ret.bytes, alignof(uint8_t *)); - } - - return multiplied; -} - -JNIEXPORT jlong JNICALL Java_javaSource_Demo_factorial - (JNIEnv *env, jobject thisObj, jlong num) -{ - int64_t ret; - // can crash - meaning call roc_panic, so we set a jump here - if (setjmp(exception_buffer)) { - // exception was thrown, handle it - jclass exClass = (*env)->FindClass(env, "java/lang/RuntimeException"); - const char *msg = (const char *)err_msg; - return (*env)->ThrowNew(env, exClass, msg); - } - else { - int64_t n = (int64_t)num; - roc__programForHost_1__Factorial_caller(&n, 0, &ret); - return ret; - } -} diff --git a/examples/jvm-interop/build.sh b/examples/jvm-interop/build.sh deleted file mode 100755 index 08feb805c4b..00000000000 --- a/examples/jvm-interop/build.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ -set -euxo pipefail - -# don't forget to validate that $JAVA_HOME is defined, the following would not work without it! -# set it either globally or here -# export JAVA_HOME=/your/java/installed/dir -# in nixos, to set it globally, i needed to say `programs.java.enable = true;` in `/etc/nixos/configuration.nix` - - -# if roc is in your path, you could -# roc build impl.roc --no-link -# else, assuming in roc repo and that you ran `cargo run --release` -../../target/release/roc build impl.roc --no-link - - -# make jvm look here to see libinterop.so -export LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH - -# needs jdk10 + -# "-h ." is for placing the jni.h header in the cwd. -# the "javaSource" directory may seem redundant (why not just a plain java file), -# but this is the way of java packaging -# we could go without it with an "implicit" package, but that would ache later on, -# especially with other JVM langs -javac -h . javaSource/Demo.java - - -clang \ - -g -Wall \ - -fPIC \ - -I"$JAVA_HOME/include" \ - # -I"$JAVA_HOME/include/darwin" # for macos - -I"$JAVA_HOME/include/linux" \ - # -shared -o libinterop.dylib \ # for macos - -shared -o libinterop.so \ - rocdemo.o bridge.c - - -# then run -java javaSource.Demo diff --git a/examples/jvm-interop/impl.roc b/examples/jvm-interop/impl.roc deleted file mode 100644 index 137525a97b5..00000000000 --- a/examples/jvm-interop/impl.roc +++ /dev/null @@ -1,23 +0,0 @@ -app [program] { pf: platform "platform.roc" } - -interpolateString : Str -> Str -interpolateString = \name -> - "Hello from Roc $(name)!!!🤘🤘🤘" - -# jint is i32 -mulArrByScalar : List I32, I32 -> List I32 -mulArrByScalar = \arr, scalar -> - List.map arr \x -> x * scalar - -# java doesn't have unsigned numbers so we cope with long -# factorial : I64 -> I64 -factorial = \n -> - if n < 0 then - # while we get the chance, exemplify a roc panic in an interop - crash "No negatives here!!!" - else if n == 0 then - 1 - else - n * (factorial (n - 1)) - -program = { interpolateString, factorial, mulArrByScalar } diff --git a/examples/jvm-interop/javaSource/Demo.java b/examples/jvm-interop/javaSource/Demo.java deleted file mode 100644 index 2b5184e0e79..00000000000 --- a/examples/jvm-interop/javaSource/Demo.java +++ /dev/null @@ -1,39 +0,0 @@ -package javaSource; - -import java.util.Arrays; - -public class Demo { - - static { - System.loadLibrary("interop"); - } - - public static native String sayHello(String num); - - public static native int[] mulArrByScalar(int[] arr, int scalar); - - public static native long factorial(long n) throws RuntimeException; - - - public static void main(String[] args) { - - // string demo - System.out.println(sayHello("Brendan") + "\n"); - - // array demo - int[] arr = {10, 20, 30, 40}; - int x = 3; - System.out.println(Arrays.toString(arr) + - " multiplied by " + x + - " results in " + Arrays.toString(mulArrByScalar(arr, x)) + - "\n"); - - // number + panic demo - // This can be implemented more peacefully but for sake of demonstration- - // this will panic from the roc side if n is negative - // and in turn will throw a JVM RuntimeException - long n = -1; - System.out.println("Factorial of " + n + " is " + factorial(n)); - - } -} diff --git a/examples/jvm-interop/platform.roc b/examples/jvm-interop/platform.roc deleted file mode 100644 index 8931752ff03..00000000000 --- a/examples/jvm-interop/platform.roc +++ /dev/null @@ -1,13 +0,0 @@ -platform "jvm-interop" - requires {} { program : _ } - exposes [] - packages {} - imports [] - provides [programForHost] - -programForHost : { - interpolateString : (Str -> Str) as InterpolateString, - mulArrByScalar : (List I32, I32 -> List I32) as MulArrByScalar, - factorial : (I64 -> I64) as Factorial, -} -programForHost = program diff --git a/examples/nodejs-interop/native-c-api/README.md b/examples/nodejs-interop/native-c-api/README.md deleted file mode 100644 index c6afd426f23..00000000000 --- a/examples/nodejs-interop/native-c-api/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# TypeScript Interop - -This is an example of calling Roc code from [TypeScript](https://www.typescriptlang.org/) on [Node.js](https://nodejs.org/en/). - -## Installation - -You'll need to have a C compiler installed, but most operating systems will have one already. -(e.g. macOS has `clang` installed by default, Linux usually has `gcc` by default, etc.) -All of these commands should be run from the same directory as this README file. - - -First, run this to install Node dependencies and generate the Makefile that will be -used by future commands. (You should only need to run this once.) - -``` -npm install -npx node-gyp configure -``` - -## Building the Roc library - -First, `cd` into this directory and run this in your terminal: - -``` -roc build --lib -``` - -This compiles your Roc code into a shared library in the current directory. The library's filename will be libhello plus an OS-specific extension (e.g. libhello.dylib on macOS). - -Next, run this to rebuild the C sources. - -``` -npx node-gyp build -``` - -Finally, run this to copy the generated TypeScript type definitions into the build directory: - -``` -cp addon.d.ts build/Release/ -``` - -You can verify that TypeScript sees the correct types with: - -``` -npx tsc hello.ts -``` - -### Try it out! - -Now that everything is built, you should be able to run the example with: - -``` -npx ts-node hello.ts -``` - -To rebuild after changing either the `demo.c` file or any `.roc` files, run: - -``` -roc build --lib && npx node-gyp build -``` - -## About this example - -This was created by following the [NodeJS addons](https://nodejs.org/dist/latest/docs/api/addons.html) tutorial and switching from C++ to C, then creating the `addon.d.ts` file to add types to the generated native Node module. \ No newline at end of file diff --git a/examples/nodejs-interop/native-c-api/addon.d.ts b/examples/nodejs-interop/native-c-api/addon.d.ts deleted file mode 100644 index 513846bfad3..00000000000 --- a/examples/nodejs-interop/native-c-api/addon.d.ts +++ /dev/null @@ -1 +0,0 @@ -export function hello(arg: string): string; diff --git a/examples/nodejs-interop/native-c-api/binding.gyp b/examples/nodejs-interop/native-c-api/binding.gyp deleted file mode 100644 index 12882559cdc..00000000000 --- a/examples/nodejs-interop/native-c-api/binding.gyp +++ /dev/null @@ -1,12 +0,0 @@ -{ - "targets": [ - { - "target_name": "addon", - "sources": [ "demo.c" ], - "libraries": [ - "-lhello", - "-L<(module_root_dir)" - ] - } - ] -} diff --git a/examples/nodejs-interop/native-c-api/demo.c b/examples/nodejs-interop/native-c-api/demo.c deleted file mode 100644 index 5d20082fcbf..00000000000 --- a/examples/nodejs-interop/native-c-api/demo.c +++ /dev/null @@ -1,418 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -napi_env napi_global_env; - -void *roc_alloc(size_t size, unsigned int alignment) { return malloc(size); } - -void *roc_realloc(void *ptr, size_t new_size, size_t old_size, - unsigned int alignment) -{ - return realloc(ptr, new_size); -} - -void roc_dealloc(void *ptr, unsigned int alignment) { free(ptr); } - -void roc_panic(void *ptr, unsigned int alignment) -{ - // WARNING: If roc_panic is called before napi_global_env is set, - // the result will be undefined behavior. So never call any Roc - // functions before setting napi_global_env! - napi_throw_error(napi_global_env, NULL, (char *)ptr); -} - -void roc_dbg(char* loc, char* msg, char* src) { - fprintf(stderr, "[%s] %s = %s\n", loc, src, msg); -} - -void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); } - -// Reference counting - -// If the refcount is set to this, that means the allocation is -// stored in readonly memory in the binary, and we must not -// attempt to increment or decrement it; if we do, we'll segfault! -const ssize_t REFCOUNT_READONLY = 0; -const ssize_t REFCOUNT_ONE = (ssize_t)PTRDIFF_MIN; -const size_t MASK = (size_t)PTRDIFF_MIN; - -// Increment reference count, given a pointer to the first element in a collection. -// We don't need to check for overflow because in order to overflow a usize worth of refcounts, -// you'd need to somehow have more pointers in memory than the OS's virtual address space can hold. -void incref(uint8_t* bytes, uint32_t alignment) -{ - ssize_t *refcount_ptr = ((ssize_t *)bytes) - 1; - ssize_t refcount = *refcount_ptr; - - if (refcount != REFCOUNT_READONLY) { - *refcount_ptr = refcount + 1; - } -} - -// Decrement reference count, given a pointer to the first byte of a collection's elements. -// Then call roc_dealloc if nothing is referencing this collection anymore. -void decref_heap_bytes(uint8_t* bytes, uint32_t alignment) -{ - size_t extra_bytes = (sizeof(size_t) >= (size_t)alignment) ? sizeof(size_t) : (size_t)alignment; - ssize_t *refcount_ptr = ((ssize_t *)bytes) - 1; - ssize_t refcount = *refcount_ptr; - - if (refcount != REFCOUNT_READONLY) { - *refcount_ptr = refcount - 1; - - if (refcount == REFCOUNT_ONE) { - void *original_allocation = (void *)(refcount_ptr - (extra_bytes - sizeof(size_t))); - - roc_dealloc(original_allocation, alignment); - } - } -} - -// RocBytes (List U8) - -struct RocBytes -{ - uint8_t *bytes; - size_t len; - size_t capacity; -}; - -struct RocBytes empty_rocbytes() -{ - struct RocBytes ret = { - .len = 0, - .bytes = NULL, - .capacity = 0, - }; - - return ret; -} - -struct RocBytes init_rocbytes(uint8_t *bytes, size_t len) -{ - if (len == 0) - { - return empty_rocbytes(); - } - else - { - struct RocBytes ret; - size_t refcount_size = sizeof(size_t); - uint8_t *new_refcount = (uint8_t *)roc_alloc(len + refcount_size, __alignof__(size_t)); - uint8_t *new_content = new_refcount + refcount_size; - - ((ssize_t *)new_refcount)[0] = REFCOUNT_ONE; - - memcpy(new_content, bytes, len); - - ret.bytes = new_content; - ret.len = len; - ret.capacity = len; - - return ret; - } -} - -// RocStr - -struct RocStr -{ - uint8_t *bytes; - size_t len; - size_t capacity; -}; - -struct RocStr empty_roc_str() -{ - struct RocStr ret = { - .len = 0, - .bytes = NULL, - .capacity = MASK, - }; - - return ret; -} - -// Record the small string's length in the last byte of the given stack allocation -void write_small_str_len(size_t len, struct RocStr *str) { - ((uint8_t *)str)[sizeof(struct RocStr) - 1] = (uint8_t)len | 0b10000000; -} - -struct RocStr roc_str_init_small(uint8_t *bytes, size_t len) -{ - // Start out with zeroed memory, so that - // if we end up comparing two small RocStr values - // for equality, we won't risk memory garbage resulting - // in two equal strings appearing unequal. - struct RocStr ret = empty_roc_str(); - - // Copy the bytes into the stack allocation - memcpy(&ret, bytes, len); - - write_small_str_len(len, &ret); - - return ret; -} - -struct RocStr roc_str_init_large(uint8_t *bytes, size_t len, size_t capacity) -{ - // A large RocStr is the same as a List U8 (aka RocBytes) in memory. - struct RocBytes roc_bytes = init_rocbytes(bytes, len); - - struct RocStr ret = { - .len = roc_bytes.len, - .bytes = roc_bytes.bytes, - .capacity = roc_bytes.capacity, - }; - - return ret; -} - -bool is_small_str(struct RocStr str) { return ((ssize_t)str.capacity) < 0; } - -// Determine the length of the string, taking into -// account the small string optimization -size_t roc_str_len(struct RocStr str) -{ - uint8_t *bytes = (uint8_t *)&str; - uint8_t last_byte = bytes[sizeof(str) - 1]; - uint8_t last_byte_xored = last_byte ^ 0b10000000; - size_t small_len = (size_t)(last_byte_xored); - size_t big_len = str.len & PTRDIFF_MAX; // Account for seamless slices - - // Avoid branch misprediction costs by always - // determining both small_len and big_len, - // so this compiles to a cmov instruction. - if (is_small_str(str)) - { - return small_len; - } - else - { - return big_len; - } -} - -void decref_large_str(struct RocStr str) -{ - uint8_t* bytes; - - if ((ssize_t)str.len < 0) - { - // This is a seamless slice, so the bytes are located in the capacity slot. - bytes = (uint8_t*)(str.capacity << 1); - } - else - { - bytes = str.bytes; - } - - decref_heap_bytes(bytes, __alignof__(uint8_t)); -} - - -// Turn the given Node string into a RocStr and return it -napi_status node_string_into_roc_str(napi_env env, napi_value node_string, struct RocStr *roc_str) { - size_t len; - napi_status status; - - // Passing NULL for a buffer (and size 0) will make it write the length of the string into `len`. - // https://nodejs.org/api/n-api.html#napi_get_value_string_utf8 - status = napi_get_value_string_utf8(env, node_string, NULL, 0, &len); - - if (status != napi_ok) - { - return status; - } - - // Node's "write a string into this buffer" function always writes a null terminator, - // so capacity will need to be length + 1. - // https://nodejs.org/api/n-api.html#napi_get_value_string_utf8 - size_t capacity = len + 1; - - // Create a RocStr and write it into the out param - if (capacity < sizeof(struct RocStr)) - { - // If it can fit in a small string, use the string itself as the buffer. - // First, zero out those bytes; small strings need to have zeroes for any bytes - // that are not part of the string, or else comparisons between small strings might fail. - *roc_str = empty_roc_str(); - - // This writes the actual number of bytes copied into len. Theoretically they should be the same, - // but it could be different if the buffer was somehow smaller. This way we guarantee that - // the RocStr does not present any memory garbage to the user. - status = napi_get_value_string_utf8(env, node_string, (char*)roc_str, sizeof(struct RocStr), &len); - - if (status != napi_ok) - { - return status; - } - - // We have to write the length into the buffer *after* Node copies its bytes in, - // because Node will have written a null terminator, which we may need to overwrite. - write_small_str_len(len, roc_str); - } - else - { - // capacity was too big for a small string, so make a heap allocation and write into that. - uint8_t *buf = (uint8_t*)roc_alloc(capacity, __alignof__(char)); - - // This writes the actual number of bytes copied into len. Theoretically they should be the same, - // but it could be different if the buffer was somehow smaller. This way we guarantee that - // the RocStr does not present any memory garbage to the user. - status = napi_get_value_string_utf8(env, node_string, (char*)buf, capacity, &len); - - if (status != napi_ok) - { - // Something went wrong, so free the bytes we just allocated before returning. - roc_dealloc((void *)&buf, __alignof__(char *)); - - return status; - } - - *roc_str = roc_str_init_large(buf, len, capacity); - } - - return status; -} - -// Consume the given RocStr (decrement its refcount) after creating a Node string from it. -napi_value roc_str_into_node_string(napi_env env, struct RocStr roc_str) { - bool is_small = is_small_str(roc_str); - char* roc_str_contents; - - if (is_small) - { - // In a small string, the string itself contains its contents. - roc_str_contents = (char*)&roc_str; - } - else - { - roc_str_contents = (char*)roc_str.bytes; - } - - napi_status status; - napi_value answer; - - status = napi_create_string_utf8(env, roc_str_contents, roc_str_len(roc_str), &answer); - - if (status != napi_ok) - { - answer = NULL; - } - - // Decrement the RocStr because we consumed it. - if (!is_small) - { - decref_large_str(roc_str); - } - - return answer; -} - -// Create a Node string from the given RocStr. -// Don't decrement the RocStr's refcount. (To decrement it, use roc_str_into_node_string instead.) -napi_value roc_str_as_node_string(napi_env env, struct RocStr roc_str) { - bool is_small = is_small_str(roc_str); - char* roc_str_contents; - - if (is_small) - { - // In a small string, the string itself contains its contents. - roc_str_contents = (char*)&roc_str; - } - else - { - roc_str_contents = (char*)roc_str.bytes; - } - - napi_status status; - napi_value answer; - - status = napi_create_string_utf8(env, roc_str_contents, roc_str_len(roc_str), &answer); - - if (status != napi_ok) - { - return NULL; - } - - // Do not decrement the RocStr's refcount because we did not consume it. - - return answer; -} - -extern void roc__mainForHost_1_exposed_generic(struct RocStr *ret, struct RocStr *arg); - -// Receive a string value from Node and pass it to Roc as a RocStr, then get a RocStr -// back from Roc and convert it into a Node string. -napi_value call_roc(napi_env env, napi_callback_info info) { - napi_status status; - - // roc_panic needs a napi_env in order to throw a Node exception, so we provide this - // one globally in case roc_panic gets called during the execution of our Roc function. - // - // According to the docs - https://nodejs.org/api/n-api.html#napi_env - - // it's very important that the napi_env that was passed into "the initial - // native function" is the one that's "passed to any subsequent nested Node-API calls," - // so we must override this every time we call this function (as opposed to, say, - // setting it once during init). - napi_global_env = env; - - // Get the argument passed to the Node function - size_t argc = 1; - napi_value argv[1]; - - status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); - - if (status != napi_ok) - { - return NULL; - } - - napi_value node_arg = argv[0]; - - struct RocStr roc_arg; - - status = node_string_into_roc_str(env, node_arg, &roc_arg); - - if (status != napi_ok) - { - return NULL; - } - - struct RocStr roc_ret; - // Call the Roc function to populate `roc_ret`'s bytes. - roc__mainForHost_1_exposed_generic(&roc_ret, &roc_arg); - - // Consume the RocStr to create the Node string. - return roc_str_into_node_string(env, roc_ret); -} - -napi_value init(napi_env env, napi_value exports) { - napi_status status; - napi_value fn; - - status = napi_create_function(env, NULL, 0, call_roc, NULL, &fn); - - if (status != napi_ok) - { - return NULL; - } - - status = napi_set_named_property(env, exports, "hello", fn); - - if (status != napi_ok) - { - return NULL; - } - - return exports; -} - -NAPI_MODULE(NODE_GYP_MODULE_NAME, init) diff --git a/examples/nodejs-interop/native-c-api/hello.ts b/examples/nodejs-interop/native-c-api/hello.ts deleted file mode 100644 index 5156435002c..00000000000 --- a/examples/nodejs-interop/native-c-api/hello.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { hello } from './build/Release/addon' - -console.log("Roc says the following:", hello("Hello from TypeScript")); diff --git a/examples/nodejs-interop/native-c-api/main.roc b/examples/nodejs-interop/native-c-api/main.roc deleted file mode 100644 index 4add8af5b1c..00000000000 --- a/examples/nodejs-interop/native-c-api/main.roc +++ /dev/null @@ -1,5 +0,0 @@ -app [main] { pf: platform "platform/main.roc" } - -main : Str -> Str -main = \message -> - "TypeScript said to Roc: $(message)! 🎉" diff --git a/examples/nodejs-interop/native-c-api/package-lock.json b/examples/nodejs-interop/native-c-api/package-lock.json deleted file mode 100644 index 32924d0d839..00000000000 --- a/examples/nodejs-interop/native-c-api/package-lock.json +++ /dev/null @@ -1,1246 +0,0 @@ -{ - "name": "node", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "devDependencies": { - "@types/node": "^18.15.3", - "node-gyp": "^9.3.1", - "ts-node": "^10.9.1", - "typescript": "^4.9.5" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.15.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz", - "integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==", - "dev": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", - "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "depd": "^2.0.0", - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", - "dev": true - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-gyp": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", - "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dev": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "optional": true - }, - "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "dev": true, - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar": { - "version": "6.1.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", - "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^4.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - } - } -} diff --git a/examples/nodejs-interop/native-c-api/package.json b/examples/nodejs-interop/native-c-api/package.json deleted file mode 100644 index 1ef892e6b8d..00000000000 --- a/examples/nodejs-interop/native-c-api/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "devDependencies": { - "@types/node": "^18.15.3", - "node-gyp": "^9.3.1", - "ts-node": "^10.9.1", - "typescript": "^4.9.5" - } -} diff --git a/examples/nodejs-interop/native-c-api/platform/main.roc b/examples/nodejs-interop/native-c-api/platform/main.roc deleted file mode 100644 index 43294c9d6d7..00000000000 --- a/examples/nodejs-interop/native-c-api/platform/main.roc +++ /dev/null @@ -1,10 +0,0 @@ -platform "nodejs-interop" - requires {} { main : Str -> Str } - exposes [] - packages {} - imports [] - provides [mainForHost] - -mainForHost : Str -> Str -mainForHost = \message -> - main message diff --git a/examples/nodejs-interop/wasm/README.md b/examples/nodejs-interop/wasm/README.md deleted file mode 100644 index 9c0b5120a4b..00000000000 --- a/examples/nodejs-interop/wasm/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# NodeJS Interop - -This is an example of calling Roc code from [Node.js](https://nodejs.org/en/). - -You'll need to have [Zig](https://ziglang.org/) installed. Run this from the current directory: - -``` -roc build --target=wasm32 -node hello.js -``` - -That's it! diff --git a/examples/nodejs-interop/wasm/hello.js b/examples/nodejs-interop/wasm/hello.js deleted file mode 100644 index a603bfbc8dc..00000000000 --- a/examples/nodejs-interop/wasm/hello.js +++ /dev/null @@ -1,71 +0,0 @@ -const fs = require('fs'); -const { TextDecoder } = require('util'); - -const wasmFilename = './main.wasm'; -const moduleBytes = fs.readFileSync(wasmFilename); -const wasmModule = new WebAssembly.Module(moduleBytes); - -function hello() { - const decoder = new TextDecoder(); - let wasmMemoryBuffer; - let exitCode; - let returnVal; - - function js_display_roc_string(strBytes, strLen) { - const utf8Bytes = wasmMemoryBuffer.subarray(strBytes, strBytes + strLen); - - returnVal = decoder.decode(utf8Bytes); - } - - const importObj = { - wasi_snapshot_preview1: { - proc_exit: (code) => { - if (code !== 0) { - console.error(`Exited with code ${code}`); - } - exitCode = code; - }, - random_get: (bufPtr, bufLen) => { - const buf = wasmMemoryBuffer.subarray(bufPtr, bufPtr + bufLen); - crypto.getRandomValues(buf); - return 0; - }, - fd_write: (x) => { - console.error(`fd_write not supported: ${x}`); - }, - }, - env: { - js_display_roc_string, - roc_panic: (_pointer, _tag_id) => { - throw "Roc panicked!"; - }, - roc_dbg: (_loc, _msg) => { - // TODO write a proper impl. - throw "Roc dbg not supported!"; - }, - }, - }; - - const instance = new WebAssembly.Instance(wasmModule, importObj); - - wasmMemoryBuffer = new Uint8Array(instance.exports.memory.buffer); - - try { - instance.exports._start(); - } catch (e) { - const isOk = e.message === "unreachable" && exitCode === 0; - - if (!isOk) { - throw e; - } - } - - return returnVal; -} - -if (typeof module === "object") { - module.exports = { hello }; -} - -// As an example, run hello() from Roc and print the string it returns -console.log(hello()); diff --git a/examples/nodejs-interop/wasm/main.roc b/examples/nodejs-interop/wasm/main.roc deleted file mode 100644 index 05c103128d4..00000000000 --- a/examples/nodejs-interop/wasm/main.roc +++ /dev/null @@ -1,4 +0,0 @@ -app [main] { pf: platform "platform/main.roc" } - -main : Str -main = "Hello from Roc!" diff --git a/examples/nodejs-interop/wasm/platform/host.js b/examples/nodejs-interop/wasm/platform/host.js deleted file mode 100644 index 486776fc664..00000000000 --- a/examples/nodejs-interop/wasm/platform/host.js +++ /dev/null @@ -1,65 +0,0 @@ -async function roc_web_platform_run(wasm_filename, callback) { - const decoder = new TextDecoder(); - let memory_bytes; - let exit_code; - - function js_display_roc_string(str_bytes, str_len) { - const utf8_bytes = memory_bytes.subarray(str_bytes, str_bytes + str_len); - const js_string = decoder.decode(utf8_bytes); - callback(js_string); - } - - const importObj = { - wasi_snapshot_preview1: { - proc_exit: (code) => { - if (code !== 0) { - console.error(`Exited with code ${code}`); - } - exit_code = code; - }, - fd_write: (x) => { - console.error(`fd_write not supported: ${x}`); - }, - }, - env: { - js_display_roc_string, - roc_panic: (_pointer, _tag_id) => { - throw "Roc panicked!"; - }, - roc_dbg: (_loc, _msg) => { - // TODO write a proper impl. - throw "Roc dbg not supported!"; - }, - }, - }; - - const fetchPromise = fetch(wasm_filename); - - let wasm; - if (WebAssembly.instantiateStreaming) { - // streaming API has better performance if available - // It can start compiling Wasm before it has fetched all of the bytes, so we don't `await` the request! - wasm = await WebAssembly.instantiateStreaming(fetchPromise, importObj); - } else { - const response = await fetchPromise; - const module_bytes = await response.arrayBuffer(); - wasm = await WebAssembly.instantiate(module_bytes, importObj); - } - - memory_bytes = new Uint8Array(wasm.instance.exports.memory.buffer); - - try { - wasm.instance.exports._start(); - } catch (e) { - const is_ok = e.message === "unreachable" && exit_code === 0; - if (!is_ok) { - console.error(e); - } - } -} - -if (typeof module !== "undefined") { - module.exports = { - roc_web_platform_run, - }; -} diff --git a/examples/nodejs-interop/wasm/platform/host.zig b/examples/nodejs-interop/wasm/platform/host.zig deleted file mode 100644 index 5f830fabdd9..00000000000 --- a/examples/nodejs-interop/wasm/platform/host.zig +++ /dev/null @@ -1,53 +0,0 @@ -const str = @import("glue").str; -const builtin = @import("builtin"); -const RocStr = str.RocStr; - -comptime { - if (builtin.target.cpu.arch != .wasm32) { - @compileError("This platform is for WebAssembly only. You need to pass `--target wasm32` to the Roc compiler."); - } -} - -const Align = extern struct { a: usize, b: usize }; -extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) anyopaque; -extern fn realloc(c_ptr: [*]align(@alignOf(Align)) u8, size: usize) callconv(.C) ?*anyopaque; -extern fn free(c_ptr: [*]align(@alignOf(Align)) u8) callconv(.C) void; -extern fn memcpy(dest: *anyopaque, src: *anyopaque, count: usize) *anyopaque; - -export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque { - _ = alignment; - - return malloc(size); -} - -export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque { - _ = old_size; - _ = alignment; - - return realloc(@as([*]align(@alignOf(Align)) u8, @alignCast(@ptrCast(c_ptr))), new_size); -} - -export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void { - _ = alignment; - - free(@as([*]align(@alignOf(Align)) u8, @alignCast(@ptrCast(c_ptr)))); -} - -// NOTE roc_panic and roc_dbg is provided in the JS file, so it can throw an exception - -extern fn roc__mainForHost_1_exposed(*RocStr) void; - -extern fn js_display_roc_string(str_bytes: ?[*]u8, str_len: usize) void; - -pub export fn main() u8 { - // actually call roc to populate the callresult - var callresult = RocStr.empty(); - roc__mainForHost_1_exposed(&callresult); - - // display the result using JavaScript - js_display_roc_string(callresult.asU8ptrMut(), callresult.len()); - - callresult.decref(); - - return 0; -} diff --git a/examples/nodejs-interop/wasm/platform/main.roc b/examples/nodejs-interop/wasm/platform/main.roc deleted file mode 100644 index 231cfb4fecb..00000000000 --- a/examples/nodejs-interop/wasm/platform/main.roc +++ /dev/null @@ -1,9 +0,0 @@ -platform "wasm-nodejs-example-platform" - requires {} { main : Str } - exposes [] - packages {} - imports [] - provides [mainForHost] - -mainForHost : Str -mainForHost = main diff --git a/examples/python-interop/.gitignore b/examples/python-interop/.gitignore deleted file mode 100644 index 3bbb2128c94..00000000000 --- a/examples/python-interop/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.interop_env -demo.egg-info -dist diff --git a/examples/python-interop/README.md b/examples/python-interop/README.md deleted file mode 100644 index 4dbbed8f3e5..00000000000 --- a/examples/python-interop/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# Python Interop - -This is a demo for calling Roc code from [Python](https://www.python.org/). - -## Installation - -The following was tested on NixOS, with `Python 3.10`, `clang 13.0.1`, `gcc 11.3.0` but should work with most recent versions of those on most modern Linux and MacOS.\ -Of course you're welcome to test on your machine and tell me (via [Zulip](https://roc.zulipchat.com/#narrow/pm-with/583319-dank)) if you ran into any issues or limitations. - -> Because of some rough edges, the linux installation may be a bit more involved (nothing too bad, mostly stuff like renames), so for your convenience I made a small shell script to help out. - -Now in favor of users of all OSs, let's first do a step by step walkthrough on how the build process works, and later, a few key notes on the implementation. - -## Building the Roc library - -First, `cd` into this directory and run this in your terminal: - -```sh -roc build --lib -``` - -This compiles your Roc code into a binary library in the current directory. The library's filename will be `libhello` plus an OS-specific extension (e.g. `libhello.dylib` on macOS). - -## Some Linux Specific Prep Work -As of the time of writing this document, `roc build --lib` generates a shared object with the suffix `.so.1.0`.\ -This `.0` suffix is not needed by neither the application nor Python, so we can simply rename it. - -``` sh -mv libhello.so.1.0 libhello.so.1 -``` -But, one of which does expect plain libhello.so, so we symlink it: - -```sh -ln -sf libhello.so.1 libhello.so -``` - -Also, one thing about dynamically linked applications like this one, is that they need to know where to look for its shared object dependencies, so we need to let CPython know that we hold libhello in this directory, so: - -``` sh -export LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH -``` - -That wasn't so bad and we're already done with prep work, all that's left it to build our C extension. -## Building the C Extension -``` sh -# If you want, you can set the environment variable cc, to compile with clang instead of gcc -python -m venv .interop_env -source .interop_env/bin/activate # activate.fish if you like fish -python setup.py install -``` -For cleanness sake, we make virtual environment here, but do note you don't have to if you don't want to. -You can also run `python setup.py build` and grab the output shared object from the `build/lib.*` directory.\ -Shared objects are simply importable in CPython (which is great!), so you can just start up an interpreter in the same directory as your new `demo.so` and get the same result. - -**Note -** after all is said and done, for prolonged use, you may want to move your shared library (lib hello) to somewhere permanent on your `LD_LIBRARY_PATH`, or add your desired directory to `LD_LIBRARY_PATH` in some way (e.g put it in your shell .rc). - -## Try it out! - -Now we can see our work by entering an interactive shell and calling our function! - -```py -❯ python -q ->>> import demo ->>> demo.call_roc(21) -'The number was 21, OH YEAH!!! 🤘🤘' -``` - -## Notes on implementation -The structure of python-interop is very similar to a C-Extension, in fact, it is one.\ -We have: -- [`PyModuleDef demoModule`](https://docs.python.org/3/c-api/module.html#c.PyModuleDef) struct which declares the `demo` python module, -- [`PyMethodDef DemoMethods`](https://docs.python.org/3/c-api/structures.html#c.PyMethodDef) struct which declares `demo`'s methods, -- [`PyMODINIT_FUNC PyInit_demo`](https://docs.python.org/3/extending/extending.html) which is `demo`’s initialization function, and of course, -- [`PyObject * call_roc`] which is our demo function! Getting args and returning our string to the interpreter. The Roc-Python bridge lives here, all the above are merely CPython boilerplate to wrap up a C implementation into a valid Python module. - -The first three are basically the backbone of any C-API extension.\ -In addition, a couple more functions and notes you may want to pay attention to: -- [`void roc_panic`] - When creating such interpreter-dependent code, it is reasonable to make the implementation of this function fire up an interpreter Exception (e.g `RuntimeError` or whatever suits). -- When I first came across another implementation, I was a bit confused about `extern void roc__mainForHost_1_exposed_generic`, so let me clarify - this is an external function, implemented by the application, that goes (on the application side-) by the name `mainForHost`. - -And one last thing - -- When writing such the C glue (here, `demo.c`), you need to pay attention to not only Python's reference counting, but also Roc's, so remember to wear seatbelts and decrement your ref counts. diff --git a/examples/python-interop/build.sh b/examples/python-interop/build.sh deleted file mode 100755 index 181260fe3c7..00000000000 --- a/examples/python-interop/build.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ -set -euxo pipefail - -# Could assume roc binary on path but this may be preferable -cargo build --release -../../target/release/roc build --lib libhello.roc - -# For Python to find libhello, it needs it to be in a known library path, so we export -export LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH - -# Optional. Flag to indicate CPython which compiler to use -export cc=clang - -# And we're done, now just pack it all together with python's build system -# setup.py will compile our demo.c to a shared library that depends on libhello. -# One of the nice things about CPython is that this demo shared library is simply importable in CPython -python -m venv .interop_env -source .interop_env/bin/activate -python setup.py install -set +x -echo "You may now enter your virtual environment. -In bash/zsh, run: source .interop_env/bin/activate -In fish, run: source .interop_env/bin/activate.fish -In csh/tcsh (really?), run: source .interop_env/bin/activate.csh -Then, try entring an interactive python shell, import demo and call demo.call_roc with your number of choice." diff --git a/examples/python-interop/demo.c b/examples/python-interop/demo.c deleted file mode 100644 index 566d43dcd83..00000000000 --- a/examples/python-interop/demo.c +++ /dev/null @@ -1,253 +0,0 @@ -#define PY_SSIZE_T_CLEAN -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void *roc_alloc(size_t size, unsigned int alignment) -{ - return malloc(size); -} - -void *roc_realloc(void *ptr, size_t new_size, size_t old_size, - unsigned int alignment) -{ - return realloc(ptr, new_size); -} - -void roc_dealloc(void *ptr, unsigned int alignment) { free(ptr); } - -__attribute__((noreturn)) void roc_panic(void *ptr, unsigned int alignment) -{ - PyErr_SetString(PyExc_RuntimeError, (char *)ptr); -} - -void roc_dbg(char* loc, char* msg, char* src) { - fprintf(stderr, "[%s] %s = %s\n", loc, src, msg); -} - -void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); } - -// Reference counting - -// If the refcount is set to this, that means the allocation is -// stored in readonly memory in the binary, and we must not -// attempt to increment or decrement it; if we do, we'll segfault! -const ssize_t REFCOUNT_READONLY = 0; -const ssize_t REFCOUNT_ONE = (ssize_t)PTRDIFF_MIN; -const size_t MASK = (size_t)PTRDIFF_MIN; - -// Increment reference count, given a pointer to the first element in a collection. -// We don't need to check for overflow because in order to overflow a usize worth of refcounts, -// you'd need to somehow have more pointers in memory than the OS's virtual address space can hold. -void incref(uint8_t* bytes, uint32_t alignment) -{ - ssize_t *refcount_ptr = ((ssize_t *)bytes) - 1; - ssize_t refcount = *refcount_ptr; - - if (refcount != REFCOUNT_READONLY) { - *refcount_ptr = refcount + 1; - } -} - -// Decrement reference count, given a pointer to the first element in a collection. -// Then call roc_dealloc if nothing is referencing this collection anymore. -void decref(uint8_t* bytes, uint32_t alignment) -{ - if (bytes == NULL) { - return; - } - - size_t extra_bytes = (sizeof(size_t) >= (size_t)alignment) ? sizeof(size_t) : (size_t)alignment; - ssize_t *refcount_ptr = ((ssize_t *)bytes) - 1; - ssize_t refcount = *refcount_ptr; - - if (refcount != REFCOUNT_READONLY) { - *refcount_ptr = refcount - 1; - - if (refcount == REFCOUNT_ONE) { - void *original_allocation = (void *)(refcount_ptr - (extra_bytes - sizeof(size_t))); - - roc_dealloc(original_allocation, alignment); - } - } -} - -// RocBytes (List U8) - -struct RocBytes -{ - uint8_t *bytes; - size_t len; - size_t capacity; -}; - -struct RocBytes init_rocbytes(uint8_t *bytes, size_t len) -{ - if (len == 0) - { - struct RocBytes ret = { - .len = 0, - .bytes = NULL, - .capacity = 0, - }; - - return ret; - } - else - { - struct RocBytes ret; - size_t refcount_size = sizeof(size_t); - uint8_t *new_content = ((uint8_t *)roc_alloc(len + refcount_size, alignof(size_t))) + refcount_size; - - memcpy(new_content, bytes, len); - - ret.bytes = new_content; - ret.len = len; - ret.capacity = len; - - return ret; - } -} - -// RocStr - -struct RocStr -{ - uint8_t *bytes; - size_t len; - size_t capacity; -}; - -struct RocStr init_rocstr(uint8_t *bytes, size_t len) -{ - if (len == 0) - { - struct RocStr ret = { - .len = 0, - .bytes = NULL, - .capacity = MASK, - }; - - return ret; - } - else if (len < sizeof(struct RocStr)) - { - // Start out with zeroed memory, so that - // if we end up comparing two small RocStr values - // for equality, we won't risk memory garbage resulting - // in two equal strings appearing unequal. - struct RocStr ret = { - .len = 0, - .bytes = NULL, - .capacity = MASK, - }; - - // Copy the bytes into the stack allocation - memcpy(&ret, bytes, len); - - // Record the string's length in the last byte of the stack allocation - ((uint8_t *)&ret)[sizeof(struct RocStr) - 1] = (uint8_t)len | 0b10000000; - - return ret; - } - else - { - // A large RocStr is the same as a List U8 (aka RocBytes) in memory. - struct RocBytes roc_bytes = init_rocbytes(bytes, len); - - struct RocStr ret = { - .len = roc_bytes.len, - .bytes = roc_bytes.bytes, - .capacity = roc_bytes.capacity, - }; - - return ret; - } -} - -bool is_small_str(struct RocStr str) { return ((ssize_t)str.capacity) < 0; } - -// Determine the length of the string, taking into -// account the small string optimization -size_t roc_str_len(struct RocStr str) -{ - uint8_t *bytes = (uint8_t *)&str; - uint8_t last_byte = bytes[sizeof(str) - 1]; - uint8_t last_byte_xored = last_byte ^ 0b10000000; - size_t small_len = (size_t)(last_byte_xored); - size_t big_len = str.len; - - // Avoid branch misprediction costs by always - // determining both small_len and big_len, - // so this compiles to a cmov instruction. - if (is_small_str(str)) - { - return small_len; - } - else - { - return big_len; - } -} - -extern void roc__mainForHost_1_exposed_generic(struct RocBytes *ret, struct RocBytes *arg); - -// Receive a value from Python, JSON serialized it and pass it to Roc as a List U8 -// (at which point the Roc platform will decode it and crash if it's invalid, -// which roc_panic will translate into a Python exception), then get some JSON back from Roc -// - also as a List U8 - and have Python JSON.parse it into a plain Python value to return. -PyObject * call_roc(PyObject *self, PyObject *args) -{ - int num; - - if(!PyArg_ParseTuple(args, "i", &num)) { - return NULL; - } - - char str_num[256] = {0}; - sprintf(str_num, "%d", num); - - // can also be done with python objects but im not sure what would be the benefit here - // PyObject* py_num_str = PyUnicode_FromFormat("%d", num); - // const char* c_str = PyUnicode_AsUTF8(py_num_str); - // size_t length = (size_t *)PyUnicode_GetLength(py_num_str); - // ...init_rocbytes((uint8_t *)c_str, length); - - // Turn the given Python number into a JSON string. - struct RocBytes arg = init_rocbytes((uint8_t *)str_num, strlen(str_num)); - struct RocBytes ret; - - // Call the Roc function to populate `ret`'s bytes. - roc__mainForHost_1_exposed_generic(&ret, &arg); - - // Create a Python string from the heap-allocated JSON bytes the Roc function returned. - PyObject* py_obj = PyUnicode_FromStringAndSize((char*)ret.bytes, ret.len); - - // Now that we've created py_str, we're no longer referencing the RocBytes. - decref((void *)&ret, alignof(uint8_t *)); - - return py_obj; -} - -static PyMethodDef DemoMethods[] = { - {"call_roc", call_roc, METH_VARARGS, "Calls a Roc function with a number, returns a string interpolated with the number"}, - {NULL, NULL, 0, NULL} -}; - -static struct PyModuleDef demoModule = { - PyModuleDef_HEAD_INIT, - "call_roc", - "demo roc call", - -1, - DemoMethods -}; - -PyMODINIT_FUNC PyInit_demo(void) { - return PyModule_Create(&demoModule); -} diff --git a/examples/python-interop/libhello.roc b/examples/python-interop/libhello.roc deleted file mode 100644 index a804afad7ab..00000000000 --- a/examples/python-interop/libhello.roc +++ /dev/null @@ -1,10 +0,0 @@ -app [main] { pf: platform "platform/main.roc" } - -main : U64 -> Str -main = \num -> - if num == 0 then - "I need a positive number here!" - else - str = Num.toStr num - - "The number was $(str), OH YEAH!!! 🤘🤘" diff --git a/examples/python-interop/platform/host.c b/examples/python-interop/platform/host.c deleted file mode 100644 index 8d3ab3c39f4..00000000000 --- a/examples/python-interop/platform/host.c +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include // shm_open -#include // for mmap -#include // for kill - -void* roc_alloc(size_t size, unsigned int alignment) { return malloc(size); } - -void* roc_realloc(void* ptr, size_t new_size, size_t old_size, - unsigned int alignment) { - return realloc(ptr, new_size); -} - -void roc_dealloc(void* ptr, unsigned int alignment) { free(ptr); } - -void roc_panic(void* ptr, unsigned int alignment) { - char* msg = (char*)ptr; - fprintf(stderr, - "Application crashed with message\n\n %s\n\nShutting down\n", msg); - exit(1); -} - -void roc_dbg(char* loc, char* msg, char* src) { - fprintf(stderr, "[%s] %s = %s\n", loc, src, msg); -} - -void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); } - -int roc_shm_open(char* name, int oflag, int mode) { -#ifdef _WIN32 - return 0; -#else - return shm_open(name, oflag, mode); -#endif -} -void* roc_mmap(void* addr, int length, int prot, int flags, int fd, int offset) { -#ifdef _WIN32 - return addr; -#else - return mmap(addr, length, prot, flags, fd, offset); -#endif -} - -int roc_getppid() { -#ifdef _WIN32 - return 0; -#else - return getppid(); -#endif -} - -struct RocStr { - char* bytes; - size_t len; - size_t capacity; -}; - -bool is_small_str(struct RocStr str) { return ((ssize_t)str.capacity) < 0; } - -// Determine the length of the string, taking into -// account the small string optimization -size_t roc_str_len(struct RocStr str) { - char* bytes = (char*)&str; - char last_byte = bytes[sizeof(str) - 1]; - char last_byte_xored = last_byte ^ 0b10000000; - size_t small_len = (size_t)(last_byte_xored); - size_t big_len = str.len; - - // Avoid branch misprediction costs by always - // determining both small_len and big_len, - // so this compiles to a cmov instruction. - if (is_small_str(str)) { - return small_len; - } else { - return big_len; - } -} - -extern void roc__mainForHost_1_exposed_generic(struct RocStr *string); - -int main() { - - struct RocStr str; - roc__mainForHost_1_exposed_generic(&str); - - // Determine str_len and the str_bytes pointer, - // taking into account the small string optimization. - size_t str_len = roc_str_len(str); - char* str_bytes; - - if (is_small_str(str)) { - str_bytes = (char*)&str; - } else { - str_bytes = str.bytes; - } - - // Write to stdout - if (write(1, str_bytes, str_len) >= 0) { - // Writing succeeded! - - // NOTE: the string is a static string, read from in the binary - // if you make it a heap-allocated string, it'll be leaked here - return 0; - } else { - printf("Error writing to stdout: %s\n", strerror(errno)); - - // NOTE: the string is a static string, read from in the binary - // if you make it a heap-allocated string, it'll be leaked here - return 1; - } -} diff --git a/examples/python-interop/platform/main.roc b/examples/python-interop/platform/main.roc deleted file mode 100644 index 7162c931fc3..00000000000 --- a/examples/python-interop/platform/main.roc +++ /dev/null @@ -1,16 +0,0 @@ -platform "python-interop" - requires {} { main : U64 -> Str } - exposes [] - packages {} - imports [] - provides [mainForHost] - -mainForHost : List U8 -> List U8 -mainForHost = \input -> - when Str.fromUtf8 input is - Ok arg -> - when Str.toU64 arg is - Ok num -> main num |> Str.toUtf8 - Err _ -> [] - - Err _ -> [] diff --git a/examples/python-interop/setup.py b/examples/python-interop/setup.py deleted file mode 100644 index d825c8414b8..00000000000 --- a/examples/python-interop/setup.py +++ /dev/null @@ -1,12 +0,0 @@ -import os -from setuptools import setup, Extension - -def main(): - setup(name="demo", - description="Demo testing Roc function calls from Python", - ext_modules=[ - Extension("demo", sources=["demo.c"], - libraries=["hello"], library_dirs=[os.getcwd()])]) - -if __name__ == "__main__": - main() diff --git a/examples/ruby-interop/.gitignore b/examples/ruby-interop/.gitignore deleted file mode 100644 index 7d7b7f76d62..00000000000 --- a/examples/ruby-interop/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -extconf.h -mkmf.log diff --git a/examples/ruby-interop/README.md b/examples/ruby-interop/README.md deleted file mode 100644 index 8a866378778..00000000000 --- a/examples/ruby-interop/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# Ruby Interop - -This is an example of calling Roc code from [Ruby](https://www.ruby-lang.org). - -## Installation - -To run this example, you will need these to be installed already (in addition to Roc): - -- [`ruby`](https://www.ruby-lang.org/en/downloads) version 2.7.6 or later -- [`clang`](https://clang.llvm.org/) version 11.0.0 or later -- [`make`](https://www.gnu.org/software/make/) version 4.0 or later - -Make sure you have the right versions of Ruby and Clang especially! This example won't work with earlier versions. - -## Building the Roc library - -First, `cd` into this directory and run this in your terminal: - -```sh -roc build --lib libhello.roc -``` - -This compiles your Roc code into a binary library in the current directory. The library's filename will be `libhello` plus an OS-specific extension (e.g. `libhello.dylib` on macOS). - -## Generating the Makefile - -Next, run this: (remember that you need Ruby 2.7.6 or higher - otherwise later steps will fail!) - -```sh -ruby extconf.rb -``` - -This generates a `Makefile`. (There are only two Roc-specific lines in `extconf.rb`; they are both commented.) You only need to do this step once; now that you have the `Makefile`, you can use it along with `roc build` to rebuild from now. - -## Building the Ruby Library from the Roc Library - -Finally, run this: - -```sh -make -``` - -This uses the `Makefile` generated earlier to take the compiled Roc library and combine it with `demo.c` to generate a Ruby library. - -## Try it out! - -You can now try this out in Ruby's REPL (`irb`), like so: - -```sh -$ LD_LIBRARY_PATH="$PWD" irb -irb(main):001:0> require_relative 'demo' -=> true -irb(main):002:0> RocApp::call_roc 42 -=> "The number was 42, OH YEAH!!! 🤘🤘" -``` - -## Rebuilding after Changes - -To rebuild after changing either the `demo.c` file or any `.roc` files, run: - -```sh -roc build --lib && make -B -``` - -The `-B` flag is necessary when you only change .roc files, because otherwise `make` thinks there's no work to do and doesn't bother rebuilding. - -## About this example - -This was created by following a [tutorial on Ruby C extensions](https://silverhammermba.github.io/emberb/c/) and [some documentation](https://github.com/ruby/ruby/blob/master/doc/extension.rdoc#label-Prepare+extconf.rb) (along with [more nicely formatted, but potentially out-of-date docs](https://docs.ruby-lang.org/en/2.4.0/extension_rdoc.html)). - -The [mkmf](https://ruby-doc.org/stdlib-2.5.1/libdoc/mkmf/rdoc/MakeMakefile.html) ("make makefile") method in `extconf.rb` generates a Makefile, which can then be run (using `make` with no arguments) to generate a compiled library that Ruby knows how to import via `require` or `require_relative`. diff --git a/examples/ruby-interop/demo.c b/examples/ruby-interop/demo.c deleted file mode 100644 index 5e76d3377e3..00000000000 --- a/examples/ruby-interop/demo.c +++ /dev/null @@ -1,225 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "extconf.h" - -void *roc_alloc(size_t size, unsigned int alignment) { return malloc(size); } - -void *roc_realloc(void *ptr, size_t new_size, size_t old_size, - unsigned int alignment) -{ - return realloc(ptr, new_size); -} - -void roc_dealloc(void *ptr, unsigned int alignment) { free(ptr); } - -__attribute__((noreturn)) void roc_panic(void *ptr, unsigned int alignment) -{ - rb_raise(rb_eException, "%s", (char *)ptr); -} - -void roc_dbg(char* loc, char* msg, char* src) { - fprintf(stderr, "[%s] %s = %s\n", loc, src, msg); -} - -void *roc_memset(void *str, int c, size_t n) { return memset(str, c, n); } - -// Reference counting - -// If the refcount is set to this, that means the allocation is -// stored in readonly memory in the binary, and we must not -// attempt to increment or decrement it; if we do, we'll segfault! -const ssize_t REFCOUNT_READONLY = 0; -const ssize_t REFCOUNT_ONE = (ssize_t)PTRDIFF_MIN; -const size_t MASK = (size_t)PTRDIFF_MIN; - -// Increment reference count, given a pointer to the first element in a collection. -// We don't need to check for overflow because in order to overflow a usize worth of refcounts, -// you'd need to somehow have more pointers in memory than the OS's virtual address space can hold. -void incref(uint8_t* bytes, uint32_t alignment) -{ - ssize_t *refcount_ptr = ((ssize_t *)bytes) - 1; - ssize_t refcount = *refcount_ptr; - - if (refcount != REFCOUNT_READONLY) { - *refcount_ptr = refcount + 1; - } -} - -// Decrement reference count, given a pointer to the first element in a collection. -// Then call roc_dealloc if nothing is referencing this collection anymore. -void decref(uint8_t* bytes, uint32_t alignment) -{ - if (bytes == NULL) { - return; - } - - size_t extra_bytes = (sizeof(size_t) >= (size_t)alignment) ? sizeof(size_t) : (size_t)alignment; - ssize_t *refcount_ptr = ((ssize_t *)bytes) - 1; - ssize_t refcount = *refcount_ptr; - - if (refcount != REFCOUNT_READONLY) { - *refcount_ptr = refcount - 1; - - if (refcount == REFCOUNT_ONE) { - void *original_allocation = (void *)(refcount_ptr - (extra_bytes - sizeof(size_t))); - - roc_dealloc(original_allocation, alignment); - } - } -} - -// RocBytes (List U8) - -struct RocBytes -{ - uint8_t *bytes; - size_t len; - size_t capacity; -}; - -struct RocBytes init_rocbytes(uint8_t *bytes, size_t len) -{ - if (len == 0) - { - struct RocBytes ret = { - .len = 0, - .bytes = NULL, - .capacity = 0, - }; - - return ret; - } - else - { - struct RocBytes ret; - size_t refcount_size = sizeof(size_t); - uint8_t *new_content = (uint8_t *)roc_alloc(len + refcount_size, alignof(size_t)) + refcount_size; - - memcpy(new_content, bytes, len); - - ret.bytes = new_content; - ret.len = len; - ret.capacity = len; - - return ret; - } -} - -// RocStr - -struct RocStr -{ - uint8_t *bytes; - size_t len; - size_t capacity; -}; - -struct RocStr init_rocstr(uint8_t *bytes, size_t len) -{ - if (len == 0) - { - struct RocStr ret = { - .len = 0, - .bytes = NULL, - .capacity = MASK, - }; - - return ret; - } - else if (len < sizeof(struct RocStr)) - { - // Start out with zeroed memory, so that - // if we end up comparing two small RocStr values - // for equality, we won't risk memory garbage resulting - // in two equal strings appearing unequal. - struct RocStr ret = { - .len = 0, - .bytes = NULL, - .capacity = MASK, - }; - - // Copy the bytes into the stack allocation - memcpy(&ret, bytes, len); - - // Record the string's length in the last byte of the stack allocation - ((uint8_t *)&ret)[sizeof(struct RocStr) - 1] = (uint8_t)len | 0b10000000; - - return ret; - } - else - { - // A large RocStr is the same as a List U8 (aka RocBytes) in memory. - struct RocBytes roc_bytes = init_rocbytes(bytes, len); - - struct RocStr ret = { - .len = roc_bytes.len, - .bytes = roc_bytes.bytes, - .capacity = roc_bytes.capacity, - }; - - return ret; - } -} - -bool is_small_str(struct RocStr str) { return ((ssize_t)str.capacity) < 0; } - -// Determine the length of the string, taking into -// account the small string optimization -size_t roc_str_len(struct RocStr str) -{ - uint8_t *bytes = (uint8_t *)&str; - uint8_t last_byte = bytes[sizeof(str) - 1]; - uint8_t last_byte_xored = last_byte ^ 0b10000000; - size_t small_len = (size_t)(last_byte_xored); - size_t big_len = str.len; - - // Avoid branch misprediction costs by always - // determining both small_len and big_len, - // so this compiles to a cmov instruction. - if (is_small_str(str)) - { - return small_len; - } - else - { - return big_len; - } -} - -extern void roc__mainForHost_1_exposed_generic(struct RocBytes *ret, struct RocBytes *arg); - -// Receive a value from Ruby, serialize it and pass it to Roc as a List U8 -// (at which point the Roc platform will decode it and crash if it's invalid, -// which roc_panic will translate into a Ruby exception), then get some utf-8 string back from Roc -// - also as a List U8 - and have Ruby decode it into a plain Ruby value to return. -VALUE call_roc(VALUE self, VALUE rb_arg) -{ - VALUE str_arg = rb_funcall(rb_arg, rb_intern("to_s"), 0); - VALUE str_utf8_arg = rb_funcall(str_arg, rb_intern("force_encoding"), 1, rb_str_new_cstr("utf-8")); - - struct RocBytes arg = init_rocbytes((uint8_t *)RSTRING_PTR(str_utf8_arg), RSTRING_LEN(str_utf8_arg)); - struct RocBytes ret; - - // Call the Roc function to populate `ret`'s bytes. - roc__mainForHost_1_exposed_generic(&ret, &arg); - - // Create a rb_utf8_str from the heap-allocated utf-8 bytes the Roc function returned. - VALUE returned_str = rb_utf8_str_new((char *)ret.bytes, ret.len); - - // Now that we've created our Ruby string, we're no longer referencing the RocBytes. - decref((void *)&ret, alignof(uint8_t *)); - - return returned_str; -} - -void Init_demo() -{ - VALUE roc_app = rb_define_module("RocApp"); - rb_define_module_function(roc_app, "call_roc", &call_roc, 1); -} diff --git a/examples/ruby-interop/extconf.rb b/examples/ruby-interop/extconf.rb deleted file mode 100644 index a3a10ebf325..00000000000 --- a/examples/ruby-interop/extconf.rb +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env ruby -require 'mkmf' - -# preparation for compilation goes here -# HACK: pass 'demo.c' as a header because otherwise ruby complains that roc_*alloc are not defined -have_library('hello', nil, 'demo.c') - -create_header -create_makefile 'demo' - diff --git a/examples/ruby-interop/libhello.roc b/examples/ruby-interop/libhello.roc deleted file mode 100644 index a804afad7ab..00000000000 --- a/examples/ruby-interop/libhello.roc +++ /dev/null @@ -1,10 +0,0 @@ -app [main] { pf: platform "platform/main.roc" } - -main : U64 -> Str -main = \num -> - if num == 0 then - "I need a positive number here!" - else - str = Num.toStr num - - "The number was $(str), OH YEAH!!! 🤘🤘" diff --git a/examples/ruby-interop/platform/host.c b/examples/ruby-interop/platform/host.c deleted file mode 100644 index 10267c6eaac..00000000000 --- a/examples/ruby-interop/platform/host.c +++ /dev/null @@ -1,119 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include // shm_open -#include // for mmap -#include // for kill - -void* roc_alloc(size_t size, unsigned int alignment) { return malloc(size); } - -void* roc_realloc(void* ptr, size_t new_size, size_t old_size, - unsigned int alignment) { - return realloc(ptr, new_size); -} - -void roc_dealloc(void* ptr, unsigned int alignment) { free(ptr); } - -void roc_panic(void* ptr, unsigned int alignment) { - char* msg = (char*)ptr; - fprintf(stderr, - "Application crashed with message\n\n %s\n\nShutting down\n", msg); - exit(1); -} - -void roc_dbg(char* loc, char* msg, char* src) { - fprintf(stderr, "[%s] %s = %s\n", loc, src, msg); -} - -void* roc_memmove(void* dest, const void* src, size_t n){ - return memmove(dest, src, n); -} - -void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); } - -int roc_shm_open(char* name, int oflag, int mode) { -#ifdef _WIN32 - return 0; -#else - return shm_open(name, oflag, mode); -#endif -} -void* roc_mmap(void* addr, int length, int prot, int flags, int fd, int offset) { -#ifdef _WIN32 - return addr; -#else - return mmap(addr, length, prot, flags, fd, offset); -#endif -} - -int roc_getppid() { -#ifdef _WIN32 - return 0; -#else - return getppid(); -#endif -} - -struct RocStr { - char* bytes; - size_t len; - size_t capacity; -}; - -bool is_small_str(struct RocStr str) { return ((ssize_t)str.capacity) < 0; } - -// Determine the length of the string, taking into -// account the small string optimization -size_t roc_str_len(struct RocStr str) { - char* bytes = (char*)&str; - char last_byte = bytes[sizeof(str) - 1]; - char last_byte_xored = last_byte ^ 0b10000000; - size_t small_len = (size_t)(last_byte_xored); - size_t big_len = str.len; - - // Avoid branch misprediction costs by always - // determining both small_len and big_len, - // so this compiles to a cmov instruction. - if (is_small_str(str)) { - return small_len; - } else { - return big_len; - } -} - -extern void roc__mainForHost_1_exposed_generic(struct RocStr *string); - -int main() { - - struct RocStr str; - roc__mainForHost_1_exposed_generic(&str); - - // Determine str_len and the str_bytes pointer, - // taking into account the small string optimization. - size_t str_len = roc_str_len(str); - char* str_bytes; - - if (is_small_str(str)) { - str_bytes = (char*)&str; - } else { - str_bytes = str.bytes; - } - - // Write to stdout - if (write(1, str_bytes, str_len) >= 0) { - // Writing succeeded! - - // NOTE: the string is a static string, read from in the binary - // if you make it a heap-allocated string, it'll be leaked here - return 0; - } else { - printf("Error writing to stdout: %s\n", strerror(errno)); - - // NOTE: the string is a static string, read from in the binary - // if you make it a heap-allocated string, it'll be leaked here - return 1; - } -} diff --git a/examples/ruby-interop/platform/main.roc b/examples/ruby-interop/platform/main.roc deleted file mode 100644 index c4a7379a3a9..00000000000 --- a/examples/ruby-interop/platform/main.roc +++ /dev/null @@ -1,16 +0,0 @@ -platform "ruby-interop" - requires {} { main : U64 -> Str } - exposes [] - packages {} - imports [] - provides [mainForHost] - -mainForHost : List U8 -> List U8 -mainForHost = \input -> - when Str.fromUtf8 input is - Ok arg -> - when Str.toU64 arg is - Ok num -> main num |> Str.toUtf8 - Err _ -> [] - - Err _ -> [] # TODO panic so that Ruby raises an exception diff --git a/examples/virtual-dom-wip/ExampleApp.roc b/examples/virtual-dom-wip/ExampleApp.roc deleted file mode 100644 index acfad07efa7..00000000000 --- a/examples/virtual-dom-wip/ExampleApp.roc +++ /dev/null @@ -1,36 +0,0 @@ -module [exampleApp, State] - -import pf.Html exposing [App, Html, html, head, body, div, text, h1] - -State : { - answer : U32, -} - -exampleApp : App State State -exampleApp = { - init, - render, - wasmUrl: "assets/example-client.wasm", -} - -init = \result -> - when result is - Ok state -> state - Err _ -> { answer: 0 } - -render : State -> Html State -render = \state -> - num = Num.toStr state.answer - - html [] [ - head [] [], - body [] [ - h1 [] [text "The app"], - div [] [text "The answer is $(num)"], - ], - ] - -expect - Html.renderStatic (Html.translateStatic (render { answer: 42 })) - == - "

The app

The answer is 42
" diff --git a/examples/virtual-dom-wip/example-client.roc b/examples/virtual-dom-wip/example-client.roc deleted file mode 100644 index 947930620a0..00000000000 --- a/examples/virtual-dom-wip/example-client.roc +++ /dev/null @@ -1,5 +0,0 @@ -app [app] { pf: platform "platform/client-side.roc" } - -import ExampleApp exposing [exampleApp] - -app = exampleApp diff --git a/examples/virtual-dom-wip/example-server.roc b/examples/virtual-dom-wip/example-server.roc deleted file mode 100644 index 23e98bd4874..00000000000 --- a/examples/virtual-dom-wip/example-server.roc +++ /dev/null @@ -1,5 +0,0 @@ -app [app] { pf: platform "platform/server-side.roc" } - -import ExampleApp exposing [exampleApp] - -app = exampleApp diff --git a/examples/virtual-dom-wip/platform/Action.roc b/examples/virtual-dom-wip/platform/Action.roc deleted file mode 100644 index 073c517f589..00000000000 --- a/examples/virtual-dom-wip/platform/Action.roc +++ /dev/null @@ -1,15 +0,0 @@ -module [Action, none, update, map] - -Action state : [None, Update state] - -none : Action * -none = None - -update : state -> Action state -update = Update - -map : Action a, (a -> b) -> Action b -map = \action, transform -> - when action is - None -> None - Update state -> Update (transform state) diff --git a/examples/virtual-dom-wip/platform/Html.roc b/examples/virtual-dom-wip/platform/Html.roc deleted file mode 100644 index f06da92d3b4..00000000000 --- a/examples/virtual-dom-wip/platform/Html.roc +++ /dev/null @@ -1,271 +0,0 @@ -module [ - App, - Html, - Attribute, - renderStatic, - renderStaticWithoutDocType, - translate, - translateStatic, - text, - none, - html, - base, - head, - link, - meta, - style, - title, - body, - address, - article, - aside, - footer, - header, - h1, - h2, - h3, - h4, - h5, - h6, - main, - nav, - section, - blockquote, - dd, - div, - dl, - dt, - figcaption, - figure, - hr, - li, - menu, - ol, - p, - pre, - ul, - a, - abbr, - b, - bdi, - bdo, - br, - cite, - code, - data, - dfn, - em, - i, - kbd, - mark, - q, - rp, - rt, - ruby, - s, - samp, - small, - span, - strong, - sub, - sup, - time, - u, - var, - wbr, - area, - audio, - img, - map, - track, - video, - embed, - iframe, - object, - picture, - portal, - source, - svg, - math, - canvas, - noscript, - script, - del, - ins, - caption, - col, - colgroup, - table, - tbody, - td, - tfoot, - th, - thead, - tr, - button, - datalist, - fieldset, - form, - input, - label, - legend, - meter, - optgroup, - option, - output, - progress, - select, - textarea, - details, - dialog, - summary, - slot, - template, -] - -import Html.Internal.Shared -import Html.Internal.Server - -App state initData : Html.Internal.Shared.App state initData -Html state : Html.Internal.Shared.Html state -Attribute state : Html.Internal.Shared.Attribute state - -element = Html.Internal.Shared.element -text = Html.Internal.Shared.text -none = Html.Internal.Shared.none - -translate = Html.Internal.Shared.translate -translateStatic = Html.Internal.Shared.translateStatic - -## Render a static Html node to a string, for saving to disk or sending over a network -## -## The output has no whitespace between nodes, to make it small. -## This is intended for generating full HTML documents, so it -## automatically adds `` to the start of the string. -## See also `renderStaticWithoutDocType`. -renderStatic : Html [] -> Str -renderStatic = \node -> - buffer = Str.reserve "" (Html.Internal.Shared.nodeSize node) - - Html.Internal.Server.appendRenderedStatic buffer node - -## Render a Html node to a static string, without a DOCTYPE -renderStaticWithoutDocType : Html [] -> Str -renderStaticWithoutDocType = \node -> - buffer = Str.reserve "" (Html.Internal.Shared.nodeSize node) - - Html.Internal.Server.appendRenderedStatic buffer node - -html = element "html" -base = element "base" -head = element "head" -link = element "link" -meta = element "meta" -style = element "style" -title = element "title" -body = element "body" -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" -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" -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" -area = element "area" -audio = element "audio" -img = element "img" -map = element "map" -track = element "track" -video = element "video" -embed = element "embed" -iframe = element "iframe" -object = element "object" -picture = element "picture" -portal = element "portal" -source = element "source" -svg = element "svg" -math = element "math" -canvas = element "canvas" -noscript = element "noscript" -script = element "script" -del = element "del" -ins = element "ins" -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" -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" -details = element "details" -dialog = element "dialog" -summary = element "summary" -slot = element "slot" -template = element "template" diff --git a/examples/virtual-dom-wip/platform/Html/Attributes.roc b/examples/virtual-dom-wip/platform/Html/Attributes.roc deleted file mode 100644 index 0d9cda74cb9..00000000000 --- a/examples/virtual-dom-wip/platform/Html/Attributes.roc +++ /dev/null @@ -1,273 +0,0 @@ -module [ - attribute, - accept, - acceptCharset, - accesskey, - action, - align, - allow, - alt, - async, - autocapitalize, - autocomplete, - autofocus, - autoplay, - background, - bgcolor, - border, - buffered, - capture, - challenge, - charset, - checked, - cite, - class, - code, - codebase, - color, - cols, - colspan, - content, - contenteditable, - contextmenu, - controls, - coords, - crossorigin, - csp, - data, - # dataAttr, TODO - datetime, - decoding, - default, - defer, - dir, - dirname, - disabled, - download, - draggable, - enctype, - enterkeyhint, - for, - form, - formaction, - formenctype, - formmethod, - formnovalidate, - formtarget, - headers, - height, - hidden, - high, - href, - hreflang, - httpEquiv, - icon, - id, - importance, - integrity, - intrinsicsize, - inputmode, - ismap, - itemprop, - keytype, - kind, - label, - lang, - language, - loading, - list, - loop, - low, - manifest, - max, - maxlength, - minlength, - media, - method, - min, - multiple, - muted, - name, - novalidate, - open, - optimum, - pattern, - ping, - placeholder, - poster, - preload, - radiogroup, - readonly, - referrerpolicy, - rel, - required, - reversed, - role, - rows, - rowspan, - sandbox, - scope, - scoped, - selected, - shape, - size, - sizes, - slot, - span, - spellcheck, - src, - srcdoc, - srclang, - srcset, - start, - step, - style, - summary, - tabindex, - target, - title, - translate, - type, - usemap, - value, - width, - wrap, -] - -import Html.Internal.Shared exposing [Attribute] - -attribute : Str -> (Str -> Attribute state) -attribute = \attrType -> - \attrValue -> HtmlAttr attrType attrValue - -accept = attribute "accept" -acceptCharset = attribute "acceptCharset" -accesskey = attribute "accesskey" -action = attribute "action" -align = attribute "align" -allow = attribute "allow" -alt = attribute "alt" -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" -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 "httpEquiv" -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/examples/virtual-dom-wip/platform/Html/Event.roc b/examples/virtual-dom-wip/platform/Html/Event.roc deleted file mode 100644 index 513e0499344..00000000000 --- a/examples/virtual-dom-wip/platform/Html/Event.roc +++ /dev/null @@ -1,77 +0,0 @@ -module [ - Handler, - CyclicStructureAccessor, - on, - custom, - onClick, - onDoubleClick, - onMouseDown, - onMouseUp, - onMouseEnter, - onMouseLeave, - onMouseOver, - onMouseOut, - onCheck, - onBlur, - onFocus, - onInput, - onSubmit, -] - -import Action exposing [Action] -import Html.Internal.Shared exposing [Attribute] - -Handler state : Html.Internal.Shared.Handler state -CyclicStructureAccessor : Html.Internal.Shared.CyclicStructureAccessor - -custom : Str, List CyclicStructureAccessor, (state, List (List U8) -> { action : Action state, stopPropagation : Bool, preventDefault : Bool }) -> Attribute state -custom = \eventName, accessors, callback -> - EventListener eventName accessors (Custom callback) - -on : Str, List CyclicStructureAccessor, (state, List (List U8) -> Action state) -> Attribute state -on = \eventName, accessors, callback -> - EventListener eventName accessors (Normal callback) - -# Internal helper -curriedOn : Str -> (List CyclicStructureAccessor, (state, List (List U8) -> Action state) -> Attribute state) -curriedOn = \eventName -> - \accessors, callback -> - EventListener eventName accessors (Normal callback) - -onClick = curriedOn "click" -onDoubleClick = curriedOn "dblclick" -onMouseDown = curriedOn "mousedown" -onMouseUp = curriedOn "mouseup" -onMouseEnter = curriedOn "mouseenter" -onMouseLeave = curriedOn "mouseleave" -onMouseOver = curriedOn "mouseover" -onMouseOut = curriedOn "mouseout" -onCheck = curriedOn "check" -onBlur = curriedOn "blur" -onFocus = curriedOn "focus" - -onInput : List CyclicStructureAccessor, (state, List (List U8) -> Action state) -> Attribute state -onInput = \accessors, callback -> - customCallback : state, List (List U8) -> { action : Action state, stopPropagation : Bool, preventDefault : Bool } - customCallback = \state, jsons -> { - action: callback state jsons, - stopPropagation: Bool.true, - preventDefault: Bool.false, - } - - EventListener "input" accessors (Custom customCallback) - -onSubmit : List CyclicStructureAccessor, (state, List (List U8) -> Action state) -> Attribute state -onSubmit = \accessors, callback -> - customCallback = \state, jsons -> { - action: callback state jsons, - stopPropagation: Bool.false, - preventDefault: Bool.true, - } - - EventListener "submit" accessors (Custom customCallback) - -# Notes from Elm: -# - stopPropagation causes immediate view update, without waiting for animationFrame, -# to prevent input state getting out of sync with model state when typing fast. -# - Security-sensitive events trigger an immediate update within the same user-instigated tick diff --git a/examples/virtual-dom-wip/platform/Html/Internal/Client.roc b/examples/virtual-dom-wip/platform/Html/Internal/Client.roc deleted file mode 100644 index 36b566a6f90..00000000000 --- a/examples/virtual-dom-wip/platform/Html/Internal/Client.roc +++ /dev/null @@ -1,797 +0,0 @@ -module [ - PlatformState, - initClientApp, - dispatchEvent, -] - -import PlatformTasks exposing [ - NodeId, - HandlerId, - TagName, - AttrType, - EventType, -] -import Html.Internal.Shared exposing [ - App, - Html, - Attribute, - CyclicStructureAccessor, - Handler, - translateStatic, -] -import Json -import Action - -PlatformState state initData : { - app : App state initData, - state, - rendered : RenderedTree state, -} - -# The rendered tree uses indices rather than pointers -# This makes it easier to communicate with JS using integer indices. -# There is a JavaScript `nodes` array that matches the Roc `nodes` List -RenderedTree state : { - root : NodeId, - nodes : List (Result RenderedNode [DeletedNode]), - deletedNodeCache : List NodeId, - handlers : List (Result (Handler state) [DeletedHandler]), - deletedHandlerCache : List HandlerId, -} - -RenderedNode : [ - RenderedNone, - RenderedText Str, - RenderedElement Str RenderedAttributes (List NodeId), -] - -RenderedAttributes : { - eventListeners : Dict Str { accessors : List CyclicStructureAccessor, handlerId : HandlerId }, - htmlAttrs : Dict Str Str, - domProps : Dict Str (List U8), - styles : Dict Str Str, -} - -emptyRenderedAttrs = { - eventListeners: Dict.empty {}, - htmlAttrs: Dict.empty {}, - domProps: Dict.empty {}, - styles: Dict.empty {}, -} - -Patch : [ - CreateElement NodeId TagName, - CreateTextNode NodeId Str, - UpdateTextNode NodeId Str, - AppendChild NodeId NodeId, - RemoveNode NodeId, - ReplaceNode NodeId NodeId, - SetAttribute NodeId AttrType Str, - RemoveAttribute NodeId AttrType, - SetProperty NodeId Str (List U8), - RemoveProperty NodeId Str, - SetStyle NodeId Str Str, - SetListener NodeId EventType (List U8) HandlerId, - RemoveListener NodeId HandlerId, -] - -DiffState state : { rendered : RenderedTree state, patches : List Patch } - -# ------------------------------- -# INITIALISATION -# ------------------------------- -initClientApp : List U8, App state initData -> Task (PlatformState state initData) * where initData implements Decoding -initClientApp = \json, app -> - # Initialise the Roc representation of the rendered DOM, and calculate patches (for event listeners) - { state, rendered, patches } = - initClientAppHelp json app - - # Call out to JS to patch the DOM, attaching the event listeners - applyPatches! patches - - Task.ok { - app, - state, - rendered, - } - -# Testable helper function to initialise the app -initClientAppHelp : List U8, App state initData -> { state, rendered : RenderedTree state, patches : List Patch } where initData implements Decoding -initClientAppHelp = \json, app -> - state = - json - |> Decode.fromBytes Json.json - |> app.init - dynamicView = - app.render state - staticUnindexed = - translateStatic dynamicView - { nodes: staticNodes } = - indexNodes { nodes: [], siblingIds: [] } staticUnindexed - staticRendered = { - root: List.len staticNodes - 1, - nodes: List.map staticNodes Ok, - deletedNodeCache: [], - handlers: [], - deletedHandlerCache: [], - } - - # Run our first diff. The only differences will be event listeners, so we will generate patches to attach those. - { rendered, patches } = - diff { rendered: staticRendered, patches: [] } dynamicView - - { state, rendered, patches } - -# Assign an index to each (virtual) DOM node. -# In JavaScript, we maintain an array of references to real DOM nodes. -# In Roc, we maintain a matching List of virtual DOM nodes with the same indices. -# They are both initialised separately, but use the same indexing algorithm. -# (We *could* pass this data in as JSON from the HTML file, but it would roughly double the size of that HTML file!) -indexNodes : { nodes : List RenderedNode, siblingIds : List U64 }, Html state -> { nodes : List RenderedNode, siblingIds : List U64 } -indexNodes = \{ nodes, siblingIds }, unrendered -> - when unrendered is - Text content -> - { - nodes: List.append nodes (RenderedText content), - siblingIds: List.append siblingIds (List.len nodes), - } - - Element name _ attrs children -> - { nodes: listWithChildren, siblingIds: childIds } = - List.walk children { nodes, siblingIds: [] } indexNodes - renderedAttrs = - List.walk attrs emptyRenderedAttrs \walkedAttrs, attr -> - when attr is - EventListener _ _ _ -> walkedAttrs # Dropped! Server-rendered HTML has no listeners - HtmlAttr k v -> { walkedAttrs & htmlAttrs: Dict.insert walkedAttrs.htmlAttrs k v } - DomProp k v -> { walkedAttrs & domProps: Dict.insert walkedAttrs.domProps k v } - Style k v -> { walkedAttrs & styles: Dict.insert walkedAttrs.styles k v } - - { - nodes: List.append listWithChildren (RenderedElement name renderedAttrs childIds), - siblingIds: List.append siblingIds (List.len listWithChildren), - } - - None -> - { - nodes: List.append nodes RenderedNone, - siblingIds: List.append siblingIds (List.len nodes), - } - -# ------------------------------- -# Patches -# ------------------------------- -applyPatch : Patch -> Task {} * -applyPatch = \patch -> - when patch is - CreateElement nodeId tagName -> PlatformTasks.createElement nodeId tagName - CreateTextNode nodeId content -> PlatformTasks.createTextNode nodeId content - UpdateTextNode nodeId content -> PlatformTasks.updateTextNode nodeId content - AppendChild parentId childId -> PlatformTasks.appendChild parentId childId - RemoveNode id -> PlatformTasks.removeNode id - ReplaceNode oldId newId -> PlatformTasks.replaceNode oldId newId - SetAttribute nodeId attrName value -> PlatformTasks.setAttribute nodeId attrName value - RemoveAttribute nodeId attrName -> PlatformTasks.removeAttribute nodeId attrName - SetProperty nodeId propName json -> PlatformTasks.setProperty nodeId propName json - RemoveProperty nodeId propName -> PlatformTasks.removeProperty nodeId propName - SetStyle nodeId key value -> PlatformTasks.setStyle nodeId key value - SetListener nodeId eventType accessorsJson handlerId -> PlatformTasks.setListener nodeId eventType accessorsJson handlerId - RemoveListener nodeId handlerId -> PlatformTasks.removeListener nodeId handlerId - -applyPatches : List Patch -> Task {} * -applyPatches = \patches -> - List.walk patches (Task.ok {}) \previousEffects, patch -> - previousEffects! - applyPatch patch - -# ------------------------------- -# EVENT HANDLING -# ------------------------------- -JsEventResult state initData : { - platformState : PlatformState state initData, - stopPropagation : Bool, - preventDefault : Bool, -} - -## Dispatch a JavaScript event to a Roc handler, given the handler ID and some JSON event data. -dispatchEvent : PlatformState state initData, List (List U8), HandlerId -> Task (JsEventResult state initData) * where initData implements Decoding -dispatchEvent = \platformState, eventData, handlerId -> - { app, state, rendered } = - platformState - maybeHandler = - List.get rendered.handlers handlerId - |> Result.withDefault (Err DeletedHandler) - { action, stopPropagation, preventDefault } = - when maybeHandler is - Err DeletedHandler -> - { action: Action.none, stopPropagation: Bool.false, preventDefault: Bool.false } - - Ok (Normal handler) -> - { action: handler state eventData, stopPropagation: Bool.false, preventDefault: Bool.false } - - Ok (Custom handler) -> - handler state eventData - - when action is - Update newState -> - newViewUnrendered = - app.render newState - { rendered: newRendered, patches } = - diff { rendered, patches: [] } newViewUnrendered - - applyPatches! patches - Task.ok { - platformState: { - app, - state: newState, - rendered: newRendered, - }, - stopPropagation, - preventDefault, - } - - None -> - Task.ok { platformState, stopPropagation, preventDefault } - -# ------------------------------- -# DIFF -# ------------------------------- -diff : DiffState state, Html state -> DiffState state -diff = \{ rendered, patches }, newNode -> - root = - rendered.root - oldNode = - List.get rendered.nodes root - |> Result.withDefault (Ok RenderedNone) - |> Result.withDefault (RenderedNone) - - when { oldNode, newNode } is - { oldNode: RenderedText oldContent, newNode: Text newContent } -> - if newContent != oldContent then - newNodes = - List.set rendered.nodes rendered.root (Ok (RenderedText newContent)) - - { - rendered: { rendered & - nodes: newNodes, - }, - patches: List.append patches (UpdateTextNode rendered.root newContent), - } - else - { rendered, patches } - - { oldNode: RenderedElement oldName oldAttrs oldChildren, newNode: Element newName _ newAttrs newChildren } -> - if newName != oldName then - replaceNode { rendered, patches } root newNode - else - stateAttrs = - diffAttrs { rendered, patches } root oldAttrs newAttrs - stateChildPairs = - List.map2 oldChildren newChildren (\oldChildId, newChild -> { oldChildId, newChild }) - |> List.walk stateAttrs \childWalkState, { oldChildId, newChild } -> - { rendered: childWalkRendered, patches: childWalkPatches } = childWalkState - diff { rendered: { childWalkRendered & root: oldChildId }, patches: childWalkPatches } newChild - { rendered: renderedLeftOverChildren, patches: patchesLeftOverChildren } = - if List.len oldChildren > List.len newChildren then - List.walkFrom oldChildren (List.len newChildren) stateChildPairs deleteNode - else if List.len oldChildren < List.len newChildren then - stateBeforeCreate = { - rendered: stateChildPairs.rendered, - patches: stateChildPairs.patches, - ids: [], - } - { rendered: renderedAfterCreate, patches: patchesAfterCreate, ids: createdIds } = - List.walkFrom newChildren (List.len oldChildren) stateBeforeCreate createChildNode - # Look up the children again since they might have new node IDs! - nodeWithUpdatedChildren = - when List.get renderedAfterCreate.nodes root is - Ok (Ok (RenderedElement n a c)) -> RenderedElement n a (List.concat c createdIds) - _ -> crash "Bug in virtual-dom framework: nodeWithUpdatedChildren not found" - updatedNodes = - List.set renderedAfterCreate.nodes root (Ok nodeWithUpdatedChildren) - - { - rendered: { renderedAfterCreate & nodes: updatedNodes }, - patches: List.walk createdIds patchesAfterCreate \p, id -> List.append p (AppendChild root id), - } - else - stateChildPairs - - { - rendered: { renderedLeftOverChildren & root }, - patches: patchesLeftOverChildren, - } - - { oldNode: RenderedNone, newNode: None } -> - { rendered, patches } - - _ -> - # old node has been replaced with a totally different variant. There's no point in diffing, just replace. - replaceNode { rendered, patches } rendered.root newNode - -replaceNode : DiffState state, NodeId, Html state -> DiffState state -replaceNode = \diffState, oldNodeId, newNode -> - { rendered: createRendered, patches: createPatches, id: createNodeId } = - createNode diffState newNode - preDeleteState = { - rendered: createRendered, - patches: List.append createPatches (ReplaceNode oldNodeId createNodeId), - } - - deleteNode preDeleteState oldNodeId - -# Delete a node, and drop any JS references to its children and event listeners -# TODO: see if it would speed things up to leave this junk lying around until the slot is reused. -# Any danger of spurious events being sent to the wrong handler? -# Otherwise, can we sweep everything at once at the end of the diff? -# Let's be conservative on things like this until we have more test cases working. -deleteNode : DiffState state, NodeId -> DiffState state -deleteNode = \diffState, id -> - { rendered, patches } = - when List.get diffState.rendered.nodes id is - Ok node -> - when node is - Ok (RenderedElement _ _ children) -> - List.walk children diffState deleteNode - - _ -> diffState - - _ -> diffState - - patchesRemoveListeners = - when List.get rendered.nodes id is - Ok (Ok (RenderedElement _ attrs _)) -> - Dict.walk attrs.eventListeners patches \p, _, { handlerId } -> - List.append p (RemoveListener id handlerId) - - _ -> patches - - newNodes = - List.set rendered.nodes id (Err DeletedNode) - newDeletedNodeCache = - List.append rendered.deletedNodeCache id - newPatches = - List.append patchesRemoveListeners (RemoveNode id) - - { - rendered: { rendered & - nodes: newNodes, - deletedNodeCache: newDeletedNodeCache, - }, - patches: newPatches, - } - -createNode : DiffState state, Html state -> { rendered : RenderedTree state, patches : List Patch, id : NodeId } -createNode = \{ rendered, patches }, newNode -> - when newNode is - Text content -> - { rendered: newRendered, id } = - insertNode rendered (RenderedText content) - - { - rendered: newRendered, - patches: List.append patches (CreateTextNode id content), - id, - } - - None -> - { rendered: newRendered, id } = - insertNode rendered RenderedNone - - { rendered: newRendered, patches, id } - - Element tagName _ attrs children -> - { rendered: renderedWithChildren, patches: patchesWithChildren, ids: childIds } = - List.walk children { rendered, patches, ids: [] } createChildNode - nodeId = - nextNodeId renderedWithChildren - patchesWithElem = - List.append patchesWithChildren (CreateElement nodeId tagName) - { renderedAttrs, rendered: renderedWithAttrs, patches: patchesWithAttrs } = - renderAttrs attrs renderedWithChildren patchesWithElem nodeId - { rendered: renderedWithNode } = - insertNode renderedWithAttrs (RenderedElement tagName renderedAttrs childIds) - - { - rendered: renderedWithNode, - patches: patchesWithAttrs, - id: nodeId, - } - -AttrDiffState state : { - nodeId : NodeId, - attrs : RenderedAttributes, - patches : List Patch, - handlers : List (Result (Handler state) [DeletedHandler]), - deletedHandlerCache : List HandlerId, -} - -diffAttrs : DiffState state, NodeId, RenderedAttributes, List (Attribute state) -> DiffState state -diffAttrs = \{ rendered, patches }, nodeId, attrs, newAttrs -> - initState = { - nodeId, - attrs, - patches, - handlers: rendered.handlers, - deletedHandlerCache: rendered.deletedHandlerCache, - } - finalState = - List.walk newAttrs initState diffAttr - newRendered = - { rendered & - handlers: finalState.handlers, - deletedHandlerCache: finalState.deletedHandlerCache, - } - - { - rendered: newRendered, - patches: finalState.patches, - } - -diffAttr : AttrDiffState state, Attribute state -> AttrDiffState state -diffAttr = \{ nodeId, attrs, patches, handlers, deletedHandlerCache }, attr -> - when attr is - EventListener eventName newAccessors newHandler -> - when Dict.get attrs.eventListeners eventName is - Ok { accessors, handlerId } -> - (Tuple newAttrs newPatches) = - if accessors == newAccessors then - Tuple attrs patches - else - json = newAccessors |> Encode.toBytes Json.json - - Tuple - { attrs & eventListeners: Dict.insert attrs.eventListeners eventName { accessors, handlerId } } - ( - patches - |> List.append (RemoveListener nodeId handlerId) - |> List.append (SetListener nodeId eventName json handlerId) - ) - - { - nodeId, - attrs: newAttrs, - patches: newPatches, - handlers: List.set handlers handlerId (Ok newHandler), - deletedHandlerCache, - } - - Err KeyNotFound -> - renderAttr { nodeId, attrs, patches, handlers, deletedHandlerCache } attr - - HtmlAttr k v -> - when Dict.get attrs.htmlAttrs k is - Ok oldVal -> - (Tuple newAttrs newPatches) = - if oldVal == v then - Tuple attrs patches - else - Tuple - { attrs & htmlAttrs: Dict.insert attrs.htmlAttrs k v } - (patches |> List.append (SetAttribute nodeId k v)) - { - nodeId, - attrs: newAttrs, - patches: newPatches, - handlers, - deletedHandlerCache, - } - - Err KeyNotFound -> - renderAttr { nodeId, attrs, patches, handlers, deletedHandlerCache } attr - - DomProp k v -> - when Dict.get attrs.domProps k is - Ok oldVal -> - (Tuple newAttrs newPatches) = - if oldVal == v then - Tuple attrs patches - else - Tuple - { attrs & domProps: Dict.insert attrs.domProps k v } - (patches |> List.append (SetProperty nodeId k v)) - { - nodeId, - attrs: newAttrs, - patches: newPatches, - handlers, - deletedHandlerCache, - } - - Err KeyNotFound -> - renderAttr { nodeId, attrs, patches, handlers, deletedHandlerCache } attr - - Style k v -> - when Dict.get attrs.styles k is - Ok oldVal -> - (Tuple newAttrs newPatches) = - if oldVal == v then - Tuple attrs patches - else - Tuple - { attrs & styles: Dict.insert attrs.styles k v } - (patches |> List.append (SetStyle nodeId k v)) - { - nodeId, - attrs: newAttrs, - patches: newPatches, - handlers, - deletedHandlerCache, - } - - Err KeyNotFound -> - renderAttr { nodeId, attrs, patches, handlers, deletedHandlerCache } attr - -renderAttrs : List (Attribute state), RenderedTree state, List Patch, NodeId -> { renderedAttrs : RenderedAttributes, rendered : RenderedTree state, patches : List Patch } -renderAttrs = \attrs, rendered, patches, nodeId -> - initState = { - nodeId, - attrs: emptyRenderedAttrs, - patches, - handlers: rendered.handlers, - deletedHandlerCache: rendered.deletedHandlerCache, - } - finalState = - List.walk attrs initState renderAttr - - { - renderedAttrs: finalState.attrs, - rendered: { rendered & - handlers: finalState.handlers, - deletedHandlerCache: finalState.deletedHandlerCache, - }, - patches: finalState.patches, - } - -renderAttr : AttrDiffState state, Attribute state -> AttrDiffState state -renderAttr = \{ nodeId, attrs, patches, handlers, deletedHandlerCache }, attr -> - when attr is - HtmlAttr k v -> - { - nodeId, - handlers, - deletedHandlerCache, - attrs: { attrs & htmlAttrs: Dict.insert attrs.htmlAttrs k v }, - patches: List.append patches (SetAttribute nodeId k v), - } - - DomProp k v -> - { - nodeId, - handlers, - deletedHandlerCache, - attrs: { attrs & domProps: Dict.insert attrs.domProps k v }, - patches: List.append patches (SetProperty nodeId k v), - } - - Style k v -> - { - nodeId, - handlers, - deletedHandlerCache, - attrs: { attrs & styles: Dict.insert attrs.styles k v }, - patches: List.append patches (SetStyle nodeId k v), - } - - EventListener eventType accessors handler -> - { handlerId, newHandlers, newDeletedHandlerCache } = - when List.last deletedHandlerCache is - Ok id -> - { - handlerId: id, - newHandlers: List.set handlers id (Ok handler), - newDeletedHandlerCache: List.dropLast deletedHandlerCache 1, - } - - Err _ -> - { - handlerId: List.len handlers, - newHandlers: List.append handlers (Ok handler), - newDeletedHandlerCache: deletedHandlerCache, - } - accessorsJson = - accessors |> Encode.toBytes Json.json - patch = - SetListener nodeId eventType accessorsJson handlerId - - { - nodeId, - attrs: { attrs & eventListeners: Dict.insert attrs.eventListeners eventType { accessors, handlerId } }, - handlers: newHandlers, - deletedHandlerCache: newDeletedHandlerCache, - patches: List.append patches patch, - } - -createChildNode : - { rendered : RenderedTree state, patches : List Patch, ids : List NodeId }, - Html state - -> { rendered : RenderedTree state, patches : List Patch, ids : List NodeId } -createChildNode = \{ rendered, patches, ids }, childHtml -> - { rendered: renderedChild, patches: childPatches, id } = - createNode { rendered, patches } childHtml - - { - rendered: renderedChild, - patches: childPatches, - ids: List.append ids id, - } - -# insert a node into the nodes list, assigning it a NodeId -insertNode : RenderedTree state, RenderedNode -> { rendered : RenderedTree state, id : NodeId } -insertNode = \rendered, node -> - when List.last rendered.deletedNodeCache is - Ok id -> - newRendered = - { rendered & - nodes: List.set rendered.nodes id (Ok node), - deletedNodeCache: List.dropLast rendered.deletedNodeCache 1, - } - - { rendered: newRendered, id } - - Err _ -> - newRendered = - { rendered & - nodes: List.append rendered.nodes (Ok node), - } - - { rendered: newRendered, id: List.len rendered.nodes } - -# Predict what NodeId will be assigned next, without actually assigning it -nextNodeId : RenderedTree state -> NodeId -nextNodeId = \rendered -> - when List.last rendered.deletedNodeCache is - Ok id -> id - Err _ -> List.len rendered.nodes - -# ------------------------------- -# TESTS -# ------------------------------- -eqRenderedTree : RenderedTree state, RenderedTree state -> Bool -eqRenderedTree = \a, b -> - (a.root == b.root) - && (a.nodes == b.nodes) - && (List.len a.handlers == List.len b.handlers) - && (a.deletedNodeCache == b.deletedNodeCache) - && (a.deletedHandlerCache == b.deletedHandlerCache) - -# indexNodes -expect - html : Html {} - html = - Element "a" 43 [HtmlAttr "href" "https://www.roc-lang.org/"] [Text "Roc"] - - actual : { nodes : List RenderedNode, siblingIds : List U64 } - actual = - indexNodes { nodes: [], siblingIds: [] } html - - expected : { nodes : List RenderedNode, siblingIds : List U64 } - expected = { - nodes: [ - RenderedText "Roc", - RenderedElement "a" { emptyRenderedAttrs & htmlAttrs: Dict.fromList [("href", "https://www.roc-lang.org/")] } [0], - ], - siblingIds: [1], - } - - (actual.nodes == expected.nodes) - && (actual.siblingIds == expected.siblingIds) - -# diff -expect - State : { answer : U32 } - - diffStateBefore : DiffState State - diffStateBefore = { - rendered: { - root: 4, - nodes: [ - Ok (RenderedText "The app"), - Ok (RenderedElement "h1" emptyRenderedAttrs [0]), - Ok (RenderedText "The answer is 42"), - Ok (RenderedElement "div" emptyRenderedAttrs [2]), - Ok (RenderedElement "body" emptyRenderedAttrs [1, 3]), - ], - deletedNodeCache: [], - handlers: [], - deletedHandlerCache: [], - }, - patches: [], - } - - # Sizes don't matter, use zero. We are not creating a HTML string so we don't care what size it would be. - newNode : Html State - newNode = - Element "body" 0 [] [ - Element "h1" 0 [] [Text "The app"], - Element "div" 0 [] [Text "The answer is 111"], - ] - - expected : DiffState State - expected = { - rendered: { - root: 4, - nodes: [ - Ok (RenderedText "The app"), - Ok (RenderedElement "h1" emptyRenderedAttrs [0]), - Ok (RenderedText "The answer is 111"), - Ok (RenderedElement "div" emptyRenderedAttrs [2]), - Ok (RenderedElement "body" emptyRenderedAttrs [1, 3]), - ], - deletedNodeCache: [], - handlers: [], - deletedHandlerCache: [], - }, - patches: [UpdateTextNode 2 "The answer is 111"], - } - - actual : DiffState State - actual = - diff diffStateBefore newNode - - (actual.patches == expected.patches) - && eqRenderedTree actual.rendered expected.rendered - -# initClientAppHelp -expect - State : { answer : U32 } - - init = \result -> - when result is - Ok state -> state - Err _ -> { answer: 0 } - - onClickHandler : Handler State - onClickHandler = - Normal \state, _ -> Action.update { answer: state.answer + 1 } - - render : State -> Html State - render = \state -> - num = Num.toStr state.answer - - onClickAttr : Attribute State - onClickAttr = - EventListener "click" [] onClickHandler - - # Sizes don't matter, use zero. We are not creating a HTML string so we don't care what size it would be. - Element "body" 0 [] [ - Element "h1" 0 [] [Text "The app"], - Element "div" 0 [onClickAttr] [Text "The answer is $(num)"], - ] - - app : App State State - app = { - init, - render, - wasmUrl: "assets/test.wasm", - } - - initJson : List U8 - initJson = - { answer: 42 } |> Encode.toBytes Json.json # panics at mono/src/ir.rs:5739:56 - expected : { state : State, rendered : RenderedTree State, patches : List Patch } - expected = { - state: { answer: 42 }, - rendered: { - root: 4, - nodes: [ - Ok (RenderedText "The app"), - Ok (RenderedElement "h1" emptyRenderedAttrs [0]), - Ok (RenderedText "The answer is 42"), - Ok (RenderedElement "div" { emptyRenderedAttrs & eventListeners: Dict.fromList [("click", { accessors: [], handlerId: 0 })] } [2]), - Ok (RenderedElement "body" emptyRenderedAttrs [1, 3]), - ], - deletedNodeCache: [], - handlers: [Ok onClickHandler], - deletedHandlerCache: [], - }, - patches: [SetListener 3 "click" [] 0], - } - - actual : { state : State, rendered : RenderedTree State, patches : List Patch } - actual = - initClientAppHelp initJson app - - (actual.state == expected.state) - && eqRenderedTree actual.rendered expected.rendered - && (actual.patches == expected.patches) diff --git a/examples/virtual-dom-wip/platform/Html/Internal/Server.roc b/examples/virtual-dom-wip/platform/Html/Internal/Server.roc deleted file mode 100644 index 9c20390f8c7..00000000000 --- a/examples/virtual-dom-wip/platform/Html/Internal/Server.roc +++ /dev/null @@ -1,121 +0,0 @@ -module [ - appendRenderedStatic, - initServerApp, -] - -import Html.Internal.Shared exposing [Html, Attribute, App, translateStatic, text, element] -import Json - -# ------------------------------- -# STATIC HTML -# ------------------------------- -appendRenderedStatic : Str, Html [] -> Str -appendRenderedStatic = \buffer, node -> - when node is - Text content -> - Str.concat buffer content - - Element name _ attrs children -> - withTagName = "$(buffer)<$(name)" - withAttrs = - if List.isEmpty attrs then - withTagName - else - init = { buffer: Str.concat withTagName " ", styles: "" } - { buffer: attrBuffer, styles } = - List.walk attrs init appendRenderedStaticAttr - - if Str.isEmpty styles then - attrBuffer - else - "$(attrBuffer) style=\"$(styles)\"" - - withTag = Str.concat withAttrs ">" - withChildren = List.walk children withTag appendRenderedStatic - - "$(withChildren)" - - None -> buffer - -appendRenderedStaticAttr : { buffer : Str, styles : Str }, Attribute [] -> { buffer : Str, styles : Str } -appendRenderedStaticAttr = \{ buffer, styles }, attr -> - when attr is - HtmlAttr key value -> - newBuffer = "$(buffer) $(key)=\"$(value)\"" - - { buffer: newBuffer, styles } - - Style key value -> - newStyles = "$(styles) $(key): $(value);" - - { buffer, styles: newStyles } - - DomProp _ _ -> { buffer, styles } - -# ------------------------------- -# INITIALISATION -# ------------------------------- -initServerApp : App state initData, initData, Str -> Result (Html []) [InvalidDocument] where initData implements Encoding -initServerApp = \app, initData, hostJavaScript -> - initData - |> Ok - |> app.init - |> app.render - |> translateStatic - |> insertRocScript initData app.wasmUrl hostJavaScript - -insertRocScript : Html [], initData, Str, Str -> Result (Html []) [InvalidDocument] where initData implements Encoding -insertRocScript = \document, initData, wasmUrl, hostJavaScript -> - encode = - \value -> - value - |> Encode.toBytes Json.json - |> Str.fromUtf8 - |> Result.withDefault "" - - # Convert initData to JSON as a Roc Str, then convert the Roc Str to a JS string. - # JSON won't have invalid UTF-8 in it, since it would be escaped as part of JSON encoding. - jsInitData = - initData |> encode |> encode - - jsWasmUrl = - encode wasmUrl - - script : Html [] - script = (element "script") [] [ - text - """ - $(hostJavaScript) - (function(){ - const initData = $(jsInitData); - const wasmUrl = $(jsWasmUrl); - window.roc = roc_init(initData, wasmUrl); - })(); - """, - ] - - # append the