diff --git a/Earthfile b/Earthfile index 9801229848..170f06b9d6 100644 --- a/Earthfile +++ b/Earthfile @@ -124,7 +124,7 @@ build-nightly-release: RUN printf " on: " >> version.txt RUN date >> version.txt RUN RUSTFLAGS="-C target-cpu=x86-64" cargo build --features with_sound --release - RUN cd ./target/release && tar -czvf roc_linux_x86_64.tar.gz ./roc ../../LICENSE ../../LEGAL_DETAILS ../../examples/hello-world ../../examples/hello-rust ../../examples/hello-zig ../../compiler/builtins/bitcode/src/ ../../roc_std + RUN cd ./target/release && tar -czvf roc_linux_x86_64.tar.gz ./roc ../../LICENSE ../../LEGAL_DETAILS ../../examples/hello-world ../../compiler/builtins/bitcode/src/ ../../roc_std SAVE ARTIFACT ./target/release/roc_linux_x86_64.tar.gz AS LOCAL roc_linux_x86_64.tar.gz # compile everything needed for benchmarks and output a self-contained dir from which benchmarks can be run. diff --git a/README.md b/README.md index 6197a8a6ac..2b094900b3 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Many programs can however be compiled correctly. Check out [examples](examples) Run examples as follows: ``` -cargo run examples/hello-world/Hello.roc +cargo run examples/hello-world/helloWorld.roc ``` Some examples like `examples/benchmarks/NQueens.roc` require input after running. For NQueens, input 10 in the terminal and press enter. diff --git a/cli/tests/cli_run.rs b/cli/tests/cli_run.rs index 7b13d5b039..0a9213731d 100644 --- a/cli/tests/cli_run.rs +++ b/cli/tests/cli_run.rs @@ -234,12 +234,12 @@ mod cli_run { let file_name = example_file(dir_name, example.filename); match example.executable_filename { - "hello-web" => { + "helloWeb" => { // this is a web webassembly example, but we don't test with JS at the moment eprintln!("WARNING: skipping testing example {} because the test is broken right now!", example.filename); return; } - "hello-swift" => { + "helloSwift" => { if cfg!(not(target_os = "macos")) { eprintln!("WARNING: skipping testing example {} because it only works on MacOS.", example.filename); return; @@ -324,49 +324,57 @@ mod cli_run { // }, // ] examples! { - hello_world:"hello-world" => Example { - filename: "Hello.roc", - executable_filename: "hello-world", + helloWorld:"hello-world" => Example { + filename: "helloWorld.roc", + executable_filename: "helloWorld", stdin: &[], input_file: None, expected_ending:"Hello, World!\n", use_valgrind: true, }, - hello_zig:"hello-zig" => Example { - filename: "Hello.roc", - executable_filename: "hello-world", + helloC:"hello-world/c-platform" => Example { + filename: "helloC.roc", + executable_filename: "helloC", stdin: &[], input_file: None, expected_ending:"Hello, World!\n", use_valgrind: true, }, - hello_rust:"hello-rust" => Example { - filename: "Hello.roc", - executable_filename: "hello-rust", + helloZig:"hello-world/zig-platform" => Example { + filename: "helloZig.roc", + executable_filename: "helloZig", stdin: &[], input_file: None, expected_ending:"Hello, World!\n", use_valgrind: true, }, - hello_swift:"hello-swift" => Example { - filename: "Hello.roc", - executable_filename: "hello-swift", - stdin: &[], - input_file: None, - expected_ending:"Hello Swift, meet Roc\n", - use_valgrind: true, - }, - hello_web:"hello-web" => Example { - filename: "Hello.roc", - executable_filename: "hello-web", + helloRust:"hello-world/rust-platform" => Example { + filename: "helloRust.roc", + executable_filename: "helloRust", stdin: &[], input_file: None, expected_ending:"Hello, World!\n", use_valgrind: true, }, - fib:"fib" => Example { - filename: "Fib.roc", - executable_filename: "fib", + helloSwift:"hello-world/swift-platform" => Example { + filename: "helloSwift.roc", + executable_filename: "helloSwift", + stdin: &[], + input_file: None, + expected_ending:"Hello, World!\n", + use_valgrind: true, + }, + helloWeb:"hello-world/web-platform" => Example { + filename: "helloWeb.roc", + executable_filename: "helloWeb", + stdin: &[], + input_file: None, + expected_ending:"Hello, World!\n", + use_valgrind: true, + }, + fib:"algorithms" => Example { + filename: "fibonacci.roc", + executable_filename: "fibonacci", stdin: &[], input_file: None, expected_ending:"55\n", @@ -380,8 +388,8 @@ mod cli_run { expected_ending: "", use_valgrind: false, }, - quicksort:"quicksort" => Example { - filename: "Quicksort.roc", + quicksort:"algorithms" => Example { + filename: "quicksort.roc", executable_filename: "quicksort", stdin: &[], input_file: None, @@ -396,9 +404,9 @@ mod cli_run { // expected_ending: "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n", // use_valgrind: true, // }, - effect:"effect" => Example { - filename: "Main.roc", - executable_filename: "effect-example", + effects:"interactive" => Example { + filename: "effects.roc", + executable_filename: "effects", stdin: &["hi there!"], input_file: None, expected_ending: "hi there!\nIt is known\n", @@ -412,7 +420,7 @@ mod cli_run { // expected_ending: "", // use_valgrind: true, // }, - cli:"cli" => Example { + cli:"interactive" => Example { filename: "form.roc", executable_filename: "form", stdin: &["Giovanni\n", "Giorgio\n"], @@ -420,8 +428,8 @@ mod cli_run { expected_ending: "Hi, Giovanni Giorgio! 👋\n", use_valgrind: true, }, - tui:"tui" => Example { - filename: "Main.roc", + tui:"interactive" => Example { + filename: "tui.roc", executable_filename: "tui", stdin: &["foo\n"], // NOTE: adding more lines leads to memory leaks input_file: None, @@ -706,6 +714,22 @@ mod cli_run { if entry.file_type().unwrap().is_dir() { let example_dir_name = entry.file_name().into_string().unwrap(); + // TODO: Improve this with a more-dynamic approach. (Read all subdirectories?) + // Some hello-world examples live in nested directories + if example_dir_name == "hello-world" { + for sub_dir in [ + "c-platform", + "rust-platform", + "swift-platform", + "web-platform", + "zig-platform", + ] { + all_examples.remove(format!("{}/{}", example_dir_name, sub_dir).as_str()).unwrap_or_else(|| { + panic!("The example directory {}/{}/{} does not have any corresponding tests in cli_run. Please add one, so if it ever stops working, we'll know about it right away!", examples_dir, example_dir_name, sub_dir); + }); + } + } + // We test benchmarks separately if example_dir_name != "benchmarks" { all_examples.remove(example_dir_name.as_str()).unwrap_or_else(|| { diff --git a/cli/tests/fixtures/multi-dep-str/platform/Package-Config.roc b/cli/tests/fixtures/multi-dep-str/platform/Package-Config.roc index eb69cce73a..3917c35843 100644 --- a/cli/tests/fixtures/multi-dep-str/platform/Package-Config.roc +++ b/cli/tests/fixtures/multi-dep-str/platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/multi-module" +platform "multi-module" requires {}{ main : Str } exposes [] packages {} diff --git a/cli/tests/fixtures/multi-dep-thunk/platform/Package-Config.roc b/cli/tests/fixtures/multi-dep-thunk/platform/Package-Config.roc index 68c2ca0962..4a4fcb8269 100644 --- a/cli/tests/fixtures/multi-dep-thunk/platform/Package-Config.roc +++ b/cli/tests/fixtures/multi-dep-thunk/platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/multi-dep-thunk" +platform "multi-dep-thunk" requires {}{ main : Str } exposes [] packages {} diff --git a/cli/tests/known_bad/platform b/cli/tests/known_bad/platform index 79724c8631..b58068a18f 120000 --- a/cli/tests/known_bad/platform +++ b/cli/tests/known_bad/platform @@ -1 +1 @@ -../../../examples/cli/platform \ No newline at end of file +../../../examples/interactive/cli-platform \ No newline at end of file diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index b0cd6b0921..c043622f08 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -794,11 +794,13 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( _ => panic!("Invalid layout for float literal = {:?}", layout), }, - Decimal(int) => env - .context - .i128_type() - .const_int(int.0 as u64, false) - .into(), + Decimal(int) => { + let (upper_bits, lower_bits) = int.as_bits(); + env.context + .i128_type() + .const_int_arbitrary_precision(&[lower_bits, upper_bits as u64]) + .into() + } Bool(b) => env.context.bool_type().const_int(*b as u64, false).into(), Byte(b) => env.context.i8_type().const_int(*b as u64, false).into(), Str(str_literal) => { diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index f7c4fe232d..4e4b0f5b21 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -637,9 +637,8 @@ impl<'a> WasmBackend<'a> { match lit { Literal::Decimal(decimal) => { - let lower_bits = (decimal.0 & 0xffff_ffff_ffff_ffff) as i64; - let upper_bits = (decimal.0 >> 64) as i64; - write128(lower_bits, upper_bits); + let (upper_bits, lower_bits) = decimal.as_bits(); + write128(lower_bits as i64, upper_bits); } Literal::Int(x) => { let lower_bits = (*x & 0xffff_ffff_ffff_ffff) as i64; diff --git a/compiler/load/tests/test_load.rs b/compiler/load/tests/test_load.rs index d9ba9608b2..6411d8ae91 100644 --- a/compiler/load/tests/test_load.rs +++ b/compiler/load/tests/test_load.rs @@ -647,7 +647,7 @@ mod test_load { "platform/Package-Config.roc", indoc!( r#" - platform "examples/hello-world" + platform "hello-c" requires {} { main : Str } exposes [] packages {} @@ -691,7 +691,7 @@ mod test_load { "platform/Package-Config.roc", indoc!( r#" - platform "examples/hello-world" + platform "hello-world" requires {} { main : { content: Str, other: Str } } exposes [] packages {} diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index d0b1a1dff7..2d9718c417 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -135,7 +135,7 @@ impl<'a> Hash for Test<'a> { IsDecimal(v) => { // TODO: Is this okay? state.write_u8(6); - v.0.hash(state); + v.hash(state); } IsU128(v) => { state.write_u8(7); @@ -906,7 +906,7 @@ fn to_relevant_branch_help<'a>( }, DecimalLiteral(dec) => match test { - IsDecimal(test_dec) if dec.0 == test_dec.0 => { + IsDecimal(test_dec) if dec.eq(test_dec) => { start.extend(end); Some(Branch { goal: branch.goal, @@ -1396,7 +1396,7 @@ fn test_to_equality<'a>( } Test::IsDecimal(test_dec) => { - let lhs = Expr::Literal(Literal::Int(test_dec.0)); + let lhs = Expr::Literal(Literal::Decimal(test_dec)); let lhs_symbol = env.unique_symbol(); stores.push((lhs_symbol, *cond_layout, lhs)); diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 67fd1b3432..9681202f6b 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -1536,8 +1536,7 @@ impl<'a> Literal<'a> { Int(lit) => alloc.text(format!("{}i64", lit)), U128(lit) => alloc.text(format!("{}u128", lit)), Float(lit) => alloc.text(format!("{}f64", lit)), - // TODO: Add proper Dec.to_str - Decimal(lit) => alloc.text(format!("{}Dec", lit.0)), + Decimal(lit) => alloc.text(format!("{}dec", lit)), Bool(lit) => alloc.text(format!("{}", lit)), Byte(lit) => alloc.text(format!("{}u8", lit)), Str(lit) => alloc.text(format!("{:?}", lit)), diff --git a/compiler/parse/tests/snapshots/pass/function_effect_types.header.result-ast b/compiler/parse/tests/snapshots/pass/function_effect_types.header.result-ast index 9075843166..39d72bce49 100644 --- a/compiler/parse/tests/snapshots/pass/function_effect_types.header.result-ast +++ b/compiler/parse/tests/snapshots/pass/function_effect_types.header.result-ast @@ -1,22 +1,22 @@ Platform { header: PlatformHeader { - name: @9-23 PackageName( - "examples/cli", + name: @9-14 PackageName( + "cli", ), requires: PlatformRequires { rigids: [], - signature: @41-58 TypedIdent { - ident: @41-45 "main", + signature: @32-49 TypedIdent { + ident: @32-36 "main", spaces_before_colon: [], - ann: @48-58 Apply( + ann: @39-49 Apply( "", "Task", [ - @53-55 Record { + @44-46 Record { fields: [], ext: None, }, - @56-58 TagUnion { + @47-49 TagUnion { ext: None, tags: [], }, @@ -27,19 +27,19 @@ Platform { exposes: [], packages: [], imports: [ - @119-132 Module( + @110-123 Module( ModuleName( "Task", ), [ - @126-130 ExposedName( + @117-121 ExposedName( "Task", ), ], ), ], provides: [ - @150-161 ExposedName( + @141-152 ExposedName( "mainForHost", ), ], diff --git a/compiler/parse/tests/snapshots/pass/function_effect_types.header.roc b/compiler/parse/tests/snapshots/pass/function_effect_types.header.roc index 8142e6a4fe..a4ec7c9b78 100644 --- a/compiler/parse/tests/snapshots/pass/function_effect_types.header.roc +++ b/compiler/parse/tests/snapshots/pass/function_effect_types.header.roc @@ -1,4 +1,4 @@ -platform "examples/cli" +platform "cli" requires {}{ main : Task {} [] } # TODO FIXME exposes [] packages {} diff --git a/editor/src/editor/main.rs b/editor/src/editor/main.rs index 1351572319..fc2a4f3036 100644 --- a/editor/src/editor/main.rs +++ b/editor/src/editor/main.rs @@ -517,7 +517,7 @@ fn read_main_roc_file(project_dir_path_opt: Option<&Path>) -> (PathStr, String) // returns path and content of app file fn init_new_roc_project(project_dir_path_str: &str) -> (PathStr, String) { - let orig_platform_path = Path::new("./examples/hello-world/platform"); + let orig_platform_path = Path::new("./examples/hello-c/platform"); let project_dir_path = Path::new(project_dir_path_str); diff --git a/examples/.gitignore b/examples/.gitignore index c0e522cc76..58cb449bb9 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,10 +1,6 @@ -app -*.o *.dSYM libhost.a -roc_app.ll -roc_app.bc +libapp.so dynhost preprocessedhost metadata -libapp.so \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 07e56d7580..9399ba7fed 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,13 +1,20 @@ - # Examples -Took a look around in the `examples` folder, `examples/benchmarks` contains some larger examples. +Took a look around in this folder; `examples/benchmarks/` contains some larger examples. Run examples as follows: -1. Navigate to `/examples` -2. Run with: -``` -cargo run hello-world/Hello.roc -``` + +1. Navigate to the examples directory + + ```bash + cd examples + ``` + +2. Run "Hello, World!" example + + ```bash + cargo run hello-world/helloWorld.roc + ``` + Some examples like `examples/benchmarks/NQueens.roc` require input after running. For NQueens, input 10 in the terminal and press enter. diff --git a/examples/quicksort/.gitignore b/examples/algorithms/.gitignore similarity index 50% rename from examples/quicksort/.gitignore rename to examples/algorithms/.gitignore index 19abff6005..f3f3289d94 100644 --- a/examples/quicksort/.gitignore +++ b/examples/algorithms/.gitignore @@ -1 +1,2 @@ +fibonacci quicksort diff --git a/examples/algorithms/README.md b/examples/algorithms/README.md new file mode 100644 index 0000000000..377360a396 --- /dev/null +++ b/examples/algorithms/README.md @@ -0,0 +1,15 @@ +# Algorithm examples + +To run: + +```bash +cargo run fibonacci.roc +cargo run quicksort.roc +``` + +To run in release mode instead, do: + +```bash +cargo run --release fibonacci.roc +cargo run --release quicksort.roc +``` diff --git a/examples/fib/platform/Package-Config.roc b/examples/algorithms/fibonacci-platform/Package-Config.roc similarity index 87% rename from examples/fib/platform/Package-Config.roc rename to examples/algorithms/fibonacci-platform/Package-Config.roc index 8d28005b1a..6cbd2805d9 100644 --- a/examples/fib/platform/Package-Config.roc +++ b/examples/algorithms/fibonacci-platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/add" +platform "fibonacci" requires {} { main : I64 -> I64 } exposes [] packages {} diff --git a/examples/fib/platform/host.zig b/examples/algorithms/fibonacci-platform/host.zig similarity index 100% rename from examples/fib/platform/host.zig rename to examples/algorithms/fibonacci-platform/host.zig diff --git a/examples/fib/Fib.roc b/examples/algorithms/fibonacci.roc similarity index 77% rename from examples/fib/Fib.roc rename to examples/algorithms/fibonacci.roc index 511f2e3e8a..e79c0fea36 100644 --- a/examples/fib/Fib.roc +++ b/examples/algorithms/fibonacci.roc @@ -1,5 +1,5 @@ -app "fib" - packages { pf: "platform" } +app "fibonacci" + packages { pf: "fibonacci-platform" } imports [] provides [ main ] to pf diff --git a/examples/quicksort/platform/Package-Config.roc b/examples/algorithms/quicksort-platform/Package-Config.roc similarity index 87% rename from examples/quicksort/platform/Package-Config.roc rename to examples/algorithms/quicksort-platform/Package-Config.roc index 08d8bf0f0b..bf872f2eed 100644 --- a/examples/quicksort/platform/Package-Config.roc +++ b/examples/algorithms/quicksort-platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/quicksort" +platform "quicksort" requires {} { quicksort : List I64 -> List I64 } exposes [] packages {} diff --git a/examples/quicksort/platform/host.zig b/examples/algorithms/quicksort-platform/host.zig similarity index 100% rename from examples/quicksort/platform/host.zig rename to examples/algorithms/quicksort-platform/host.zig diff --git a/examples/quicksort/Quicksort.roc b/examples/algorithms/quicksort.roc similarity index 97% rename from examples/quicksort/Quicksort.roc rename to examples/algorithms/quicksort.roc index f4820c5ed0..d7cc023e2d 100644 --- a/examples/quicksort/Quicksort.roc +++ b/examples/algorithms/quicksort.roc @@ -1,5 +1,5 @@ app "quicksort" - packages { pf: "platform" } + packages { pf: "quicksort-platform" } imports [] provides [ quicksort ] to pf diff --git a/examples/benchmarks/.gitignore b/examples/benchmarks/.gitignore index b42405dacb..66394864b9 100644 --- a/examples/benchmarks/.gitignore +++ b/examples/benchmarks/.gitignore @@ -1,19 +1,11 @@ -app -*.o -*.dSYM -*.ll -*.bc -libhost.a -roc_app.ll -roc_app.bc -nqueens -deriv -closure cfold -rbtree-insert -rbtree-del +closure +deriv issue2279 +nqueens +quicksortapp rbtree-ck +rbtree-del +rbtree-insert test-astar test-base64 -quicksortapp diff --git a/examples/benchmarks/platform/Package-Config.roc b/examples/benchmarks/platform/Package-Config.roc index fe634bbc7f..f78bdf17c2 100644 --- a/examples/benchmarks/platform/Package-Config.roc +++ b/examples/benchmarks/platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "folkertdev/foo" +platform "benchmarks" requires {} { main : Effect {} } exposes [] packages {} diff --git a/examples/cli/README.md b/examples/cli/README.md deleted file mode 100644 index 91591d963f..0000000000 --- a/examples/cli/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Command Line Interface (CLI) Example - -This is an example of how to make an extremely basic CLI in Roc. - -There's not currently much documentation for the CLI platform (which also doesn't support many operations at this point!) -but you can look at [the modules it includes](platform) - for example, -multiple other modules use the [`Task`](platform/Task.roc) module, including the -[`Stdin`](platform/Stdin.roc) and [`Stdout`](platform/Stdout.roc) modules. diff --git a/examples/effect/.gitignore b/examples/effect/.gitignore deleted file mode 100644 index ffc7415330..0000000000 --- a/examples/effect/.gitignore +++ /dev/null @@ -1 +0,0 @@ -effect-example diff --git a/examples/effect/ConsList.roc b/examples/effect/ConsList.roc deleted file mode 100644 index 824f9e86fa..0000000000 --- a/examples/effect/ConsList.roc +++ /dev/null @@ -1,33 +0,0 @@ -interface ConsList exposes [ ConsList, empty, isEmpty, map, len ] imports [] - -ConsList a : [ Cons a (ConsList a), Nil ] - -empty : ConsList a -empty = Nil - -len : ConsList a -> Int * -len = \list -> - when list is - Cons _ rest -> - 1 + len rest - - Nil -> - 0 - -map : ConsList a, (a -> b) -> ConsList b -map = \list, f -> - when list is - Cons x xs -> - Cons (f x) (map xs f) - - Nil -> - Nil - -isEmpty : ConsList a -> Bool -isEmpty = \list -> - when list is - Cons _ _ -> - False - - Nil -> - True diff --git a/examples/effect/RBTree.roc b/examples/effect/RBTree.roc deleted file mode 100644 index b6dea736cf..0000000000 --- a/examples/effect/RBTree.roc +++ /dev/null @@ -1,341 +0,0 @@ -interface RBTree exposes [ Dict, empty, size, singleton, isEmpty, insert, remove, update, fromList, toList, balance ] imports [] - -# The color of a node. Leaves are considered Black. -NodeColor : [ Red, Black ] - -Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ] - -Key k : Num k - -Maybe a : [ Just a, Nothing ] - -# Create an empty dictionary. -empty : Dict k v -empty = - Empty - -# Create a dictionary with one key-value pair. -singleton : Key k, v -> Dict (Key k) v -singleton = \key, value -> - # Root node is always Black - Node Black key value Empty Empty - -# {-| Determine the number of key-value pairs in the dictionary. -} -size : Dict k v -> Int * -size = \dict -> - sizeHelp 0 dict - -sizeHelp : Int *, Dict k v -> Int * -sizeHelp = \n, dict -> - when dict is - Empty -> - n - - Node _ _ _ left right -> - sizeHelp (sizeHelp (n + 1) right) left - -isEmpty : Dict k v -> Bool -isEmpty = \dict -> - when dict is - Empty -> - True - - Node _ _ _ _ _ -> - False - -insert : Key k, v, Dict (Key k) v -> Dict (Key k) v -insert = \key, value, dict -> - when insertHelp key value dict is - Node Red k v l r -> - Node Black k v l r - - x -> - x - -insertHelp : Key k, v, Dict (Key k) v -> Dict (Key k) v -insertHelp = \key, value, dict -> - when dict is - Empty -> - # New nodes are always red. If it violates the rules, it will be fixed - # when balancing. - Node Red key value Empty Empty - - Node nColor nKey nValue nLeft nRight -> - when Num.compare key nKey is - LT -> - balance nColor nKey nValue (insertHelp key value nLeft) nRight - - EQ -> - Node nColor nKey value nLeft nRight - - GT -> - balance nColor nKey nValue nLeft (insertHelp key value nRight) - -balance : NodeColor, k, v, Dict k v, Dict k v -> Dict k v -balance = \color, key, value, left, right -> - when right is - Node Red rK rV rLeft rRight -> - when left is - Node Red lK lV lLeft lRight -> - Node - Red - key - value - (Node Black lK lV lLeft lRight) - (Node Black rK rV rLeft rRight) - - _ -> - Node color rK rV (Node Red key value left rLeft) rRight - - _ -> - when left is - Node Red lK lV (Node Red llK llV llLeft llRight) lRight -> - Node - Red - lK - lV - (Node Black llK llV llLeft llRight) - (Node Black key value lRight right) - - _ -> - Node color key value left right - -remove : Key k, Dict (Key k) v -> Dict (Key k) v -remove = \key, dict -> - # Root node is always Black - when removeHelp key dict is - Node Red k v l r -> - Node Black k v l r - - x -> - x - -# The easiest thing to remove from the tree, is a red node. However, when searching for the -# node to remove, we have no way of knowing if it will be red or not. This remove implementation -# makes sure that the bottom node is red by moving red colors down the tree through rotation -# and color flips. Any violations this will cause, can easily be fixed by balancing on the way -# up again. -removeHelp : Key k, Dict (Key k) v -> Dict (Key k) v -removeHelp = \targetKey, dict -> - when dict is - Empty -> - Empty - - Node color key value left right -> - if targetKey < key then - when left is - Node Black _ _ lLeft _ -> - when lLeft is - Node Red _ _ _ _ -> - Node color key value (removeHelp targetKey left) right - - _ -> - when moveRedLeft dict is - Node nColor nKey nValue nLeft nRight -> - balance nColor nKey nValue (removeHelp targetKey nLeft) nRight - - Empty -> - Empty - - _ -> - Node color key value (removeHelp targetKey left) right - else - removeHelpEQGT targetKey (removeHelpPrepEQGT targetKey dict color key value left right) - -removeHelpPrepEQGT : Key k, Dict (Key k) v, NodeColor, Key k, v, Dict (Key k) v, Dict (Key k) v -> Dict (Key k) v -removeHelpPrepEQGT = \_, dict, color, key, value, left, right -> - when left is - Node Red lK lV lLeft lRight -> - Node - color - lK - lV - lLeft - (Node Red key value lRight right) - - _ -> - when right is - Node Black _ _ (Node Black _ _ _ _) _ -> - moveRedRight dict - - Node Black _ _ Empty _ -> - moveRedRight dict - - _ -> - dict - -# When we find the node we are looking for, we can remove by replacing the key-value -# pair with the key-value pair of the left-most node on the right side (the closest pair). -removeHelpEQGT : Key k, Dict (Key k) v -> Dict (Key k) v -removeHelpEQGT = \targetKey, dict -> - when dict is - Node color key value left right -> - if targetKey == key then - when getMin right is - Node _ minKey minValue _ _ -> - balance color minKey minValue left (removeMin right) - - Empty -> - Empty - else - balance color key value left (removeHelp targetKey right) - - Empty -> - Empty - -getMin : Dict k v -> Dict k v -getMin = \dict -> - when dict is - # Node _ _ _ ((Node _ _ _ _ _) as left) _ -> - Node _ _ _ left _ -> - when left is - Node _ _ _ _ _ -> - getMin left - - _ -> - dict - - _ -> - dict - -moveRedLeft : Dict k v -> Dict k v -moveRedLeft = \dict -> - when dict is - # Node clr k v (Node lClr lK lV lLeft lRight) (Node rClr rK rV ((Node Red rlK rlV rlL rlR) as rLeft) rRight) -> - # Node clr k v (Node lClr lK lV lLeft lRight) (Node rClr rK rV rLeft rRight) -> - Node clr k v (Node _ lK lV lLeft lRight) (Node _ rK rV rLeft rRight) -> - when rLeft is - Node Red rlK rlV rlL rlR -> - Node - Red - rlK - rlV - (Node Black k v (Node Red lK lV lLeft lRight) rlL) - (Node Black rK rV rlR rRight) - - _ -> - when clr is - Black -> - Node - Black - k - v - (Node Red lK lV lLeft lRight) - (Node Red rK rV rLeft rRight) - - Red -> - Node - Black - k - v - (Node Red lK lV lLeft lRight) - (Node Red rK rV rLeft rRight) - - _ -> - dict - -moveRedRight : Dict k v -> Dict k v -moveRedRight = \dict -> - when dict is - Node _ k v (Node _ lK lV (Node Red llK llV llLeft llRight) lRight) (Node _ rK rV rLeft rRight) -> - Node - Red - lK - lV - (Node Black llK llV llLeft llRight) - (Node Black k v lRight (Node Red rK rV rLeft rRight)) - - Node clr k v (Node _ lK lV lLeft lRight) (Node _ rK rV rLeft rRight) -> - when clr is - Black -> - Node - Black - k - v - (Node Red lK lV lLeft lRight) - (Node Red rK rV rLeft rRight) - - Red -> - Node - Black - k - v - (Node Red lK lV lLeft lRight) - (Node Red rK rV rLeft rRight) - - _ -> - dict - -removeMin : Dict k v -> Dict k v -removeMin = \dict -> - when dict is - Node color key value left right -> - when left is - Node lColor _ _ lLeft _ -> - when lColor is - Black -> - when lLeft is - Node Red _ _ _ _ -> - Node color key value (removeMin left) right - - _ -> - when moveRedLeft dict is - Node nColor nKey nValue nLeft nRight -> - balance nColor nKey nValue (removeMin nLeft) nRight - - Empty -> - Empty - - _ -> - Node color key value (removeMin left) right - - _ -> - Empty - - _ -> - Empty - -# Update the value of a dictionary for a specific key with a given function. -update : Key k, (Maybe v -> Maybe v), Dict (Key k) v -> Dict (Key k) v -update = \targetKey, alter, dictionary -> - when alter (get targetKey dictionary) is - Just value -> - insert targetKey value dictionary - - Nothing -> - remove targetKey dictionary - -get : Key k, Dict (Key k) v -> Maybe v -get = \targetKey, dict -> - when dict is - Empty -> - Nothing - - Node _ key value left right -> - when Num.compare targetKey key is - LT -> - get targetKey left - - EQ -> - Just value - - GT -> - get targetKey right - -fromList : List { key : Num k, value : v } -> Dict (Num k) v -fromList = \xs -> - List.walkRight xs (\{ key, value }, dict -> insert key value dict) empty - -foldr : (k, v, b -> b), b, Dict k v -> b -foldr = \func, acc, t -> - when t is - Empty -> - acc - - Node _ key value left right -> - foldr func (func key value (foldr func acc right)) left - -# Convert a dictionary into an association list of key-value pairs, sorted by keys. -toList : Dict k v -> List { key : k, value : v } -toList = \dict -> - foldr (\key, value, list -> List.append list { key, value }) [] dict diff --git a/examples/false-interpreter/platform/Package-Config.roc b/examples/false-interpreter/platform/Package-Config.roc index 304d4d0fe5..315a96c588 100644 --- a/examples/false-interpreter/platform/Package-Config.roc +++ b/examples/false-interpreter/platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/cli" +platform "false-interpreter" requires {} { main : Str -> Task {} [] } exposes [] packages {} diff --git a/examples/fib/.gitignore b/examples/fib/.gitignore deleted file mode 100644 index 41d1223f94..0000000000 --- a/examples/fib/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -add -fib diff --git a/examples/gui/platform/Package-Config.roc b/examples/gui/platform/Package-Config.roc index 855c45e23b..8099b4ded7 100644 --- a/examples/gui/platform/Package-Config.roc +++ b/examples/gui/platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/hello-world" +platform "gui" requires {} { render : Elem } exposes [] packages {} diff --git a/examples/hello-rust/.gitignore b/examples/hello-rust/.gitignore deleted file mode 100644 index 8485821d7c..0000000000 --- a/examples/hello-rust/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hello-rust diff --git a/examples/hello-rust/Hello.roc b/examples/hello-rust/Hello.roc deleted file mode 100644 index 19be5569f1..0000000000 --- a/examples/hello-rust/Hello.roc +++ /dev/null @@ -1,12 +0,0 @@ -app "hello-rust" - packages { pf: "platform" } - imports [] - provides [ main ] to pf - -greeting = - hi = "Hello" - name = "World" - - "\(hi), \(name)!\n" - -main = greeting diff --git a/examples/hello-swift/.gitignore b/examples/hello-swift/.gitignore deleted file mode 100644 index a0e866b7eb..0000000000 --- a/examples/hello-swift/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hello-swift \ No newline at end of file diff --git a/examples/hello-swift/Hello.roc b/examples/hello-swift/Hello.roc deleted file mode 100644 index a733c57efd..0000000000 --- a/examples/hello-swift/Hello.roc +++ /dev/null @@ -1,10 +0,0 @@ -app "hello-swift" - packages { pf: "platform" } - imports [] - provides [ main ] to pf - -main = - host = "Swift" - app = "Roc" - - "Hello \(host), meet \(app)" diff --git a/examples/hello-web/.gitignore b/examples/hello-web/.gitignore deleted file mode 100644 index 9cd8cd131d..0000000000 --- a/examples/hello-web/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -hello-web.wasm -*.wat diff --git a/examples/hello-web/Hello.roc b/examples/hello-web/Hello.roc deleted file mode 100644 index 600e119848..0000000000 --- a/examples/hello-web/Hello.roc +++ /dev/null @@ -1,12 +0,0 @@ -app "hello-web" - packages { pf: "platform" } - imports [] - provides [ main ] to pf - -greeting = - hi = "Hello" - name = "World" - - "\(hi), \(name)!" - -main = greeting diff --git a/examples/hello-world/.gitignore b/examples/hello-world/.gitignore index 6b820fd903..a566f1dab8 100644 --- a/examples/hello-world/.gitignore +++ b/examples/hello-world/.gitignore @@ -1 +1,7 @@ -hello-world +helloC +helloRust +helloSwift +helloWeb.wasm +helloWorld +helloWorld.wasm +helloZig diff --git a/examples/hello-world/README.md b/examples/hello-world/README.md index 26d4c8e7d9..bd5fbda39f 100644 --- a/examples/hello-world/README.md +++ b/examples/hello-world/README.md @@ -3,19 +3,19 @@ To run, `cd` into this directory and run: ```bash -$ cargo run Hello.roc +cargo run helloWorld.roc ``` To run in release mode instead, do: ```bash -$ cargo run --release Hello.roc +cargo run --release helloWorld.roc ``` ## Design Notes This demonstrates the basic design of hosts: Roc code gets compiled into a pure -function (in this case, a thunk that always returns `"Hello, World!"`) and +function (in this case, a thunk that always returns `"Hello, World!\n"`) and then the host calls that function. Fundamentally, that's the whole idea! The host might not even have a `main` - it could be a library, a plugin, anything. Everything else is built on this basic "hosts calling linked pure functions" design. diff --git a/examples/hello-swift/platform/Package-Config.roc b/examples/hello-world/c-platform/Package-Config.roc similarity index 81% rename from examples/hello-swift/platform/Package-Config.roc rename to examples/hello-world/c-platform/Package-Config.roc index 5eca9b81b4..f5e23c9733 100644 --- a/examples/hello-swift/platform/Package-Config.roc +++ b/examples/hello-world/c-platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/hello-swift" +platform "hello-world-in-c" requires {} { main : Str } exposes [] packages {} diff --git a/examples/hello-world/Hello.roc b/examples/hello-world/c-platform/helloC.roc similarity index 57% rename from examples/hello-world/Hello.roc rename to examples/hello-world/c-platform/helloC.roc index de5250ff5f..9db5abbac7 100644 --- a/examples/hello-world/Hello.roc +++ b/examples/hello-world/c-platform/helloC.roc @@ -1,5 +1,5 @@ -app "hello-world" - packages { pf: "platform" } +app "helloC" + packages { pf: "." } imports [] provides [ main ] to pf diff --git a/examples/hello-world/platform/host.c b/examples/hello-world/c-platform/host.c similarity index 100% rename from examples/hello-world/platform/host.c rename to examples/hello-world/c-platform/host.c diff --git a/examples/hello-world/helloWorld.roc b/examples/hello-world/helloWorld.roc new file mode 100644 index 0000000000..40f354147d --- /dev/null +++ b/examples/hello-world/helloWorld.roc @@ -0,0 +1,11 @@ +app "helloWorld" + packages { pf: "c-platform" } + # To switch platforms, comment-out the line above and un-comment one below. + # packages { pf: "rust-platform" } + # packages { pf: "swift-platform" } + # packages { pf: "web-platform" } # See ./web-platform/README.md + # packages { pf: "zig-platform" } + imports [] + provides [ main ] to pf + +main = "Hello, World!\n" diff --git a/examples/hello-rust/platform/Cargo.lock b/examples/hello-world/rust-platform/Cargo.lock similarity index 100% rename from examples/hello-rust/platform/Cargo.lock rename to examples/hello-world/rust-platform/Cargo.lock diff --git a/examples/hello-rust/platform/Cargo.toml b/examples/hello-world/rust-platform/Cargo.toml similarity index 100% rename from examples/hello-rust/platform/Cargo.toml rename to examples/hello-world/rust-platform/Cargo.toml diff --git a/examples/hello-rust/platform/Package-Config.roc b/examples/hello-world/rust-platform/Package-Config.roc similarity index 81% rename from examples/hello-rust/platform/Package-Config.roc rename to examples/hello-world/rust-platform/Package-Config.roc index 61e4c96bf2..7475f3d65b 100644 --- a/examples/hello-rust/platform/Package-Config.roc +++ b/examples/hello-world/rust-platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/hello-world" +platform "hello-world-in-rust" requires {} { main : Str } exposes [] packages {} diff --git a/examples/cli/platform/build.rs b/examples/hello-world/rust-platform/build.rs similarity index 100% rename from examples/cli/platform/build.rs rename to examples/hello-world/rust-platform/build.rs diff --git a/examples/hello-world/rust-platform/helloRust.roc b/examples/hello-world/rust-platform/helloRust.roc new file mode 100644 index 0000000000..321e46ec8c --- /dev/null +++ b/examples/hello-world/rust-platform/helloRust.roc @@ -0,0 +1,6 @@ +app "helloRust" + packages { pf: "." } + imports [] + provides [ main ] to pf + +main = "Hello, World!\n" diff --git a/examples/hello-rust/platform/host.c b/examples/hello-world/rust-platform/host.c similarity index 100% rename from examples/hello-rust/platform/host.c rename to examples/hello-world/rust-platform/host.c diff --git a/examples/hello-rust/platform/src/lib.rs b/examples/hello-world/rust-platform/src/lib.rs similarity index 100% rename from examples/hello-rust/platform/src/lib.rs rename to examples/hello-world/rust-platform/src/lib.rs diff --git a/examples/cli/platform/src/main.rs b/examples/hello-world/rust-platform/src/main.rs similarity index 100% rename from examples/cli/platform/src/main.rs rename to examples/hello-world/rust-platform/src/main.rs diff --git a/examples/hello-web/platform/Package-Config.roc b/examples/hello-world/swift-platform/Package-Config.roc similarity index 81% rename from examples/hello-web/platform/Package-Config.roc rename to examples/hello-world/swift-platform/Package-Config.roc index 61e4c96bf2..edaf0337ba 100644 --- a/examples/hello-web/platform/Package-Config.roc +++ b/examples/hello-world/swift-platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/hello-world" +platform "hello-world-in-swift" requires {} { main : Str } exposes [] packages {} diff --git a/examples/hello-world/swift-platform/helloSwift.roc b/examples/hello-world/swift-platform/helloSwift.roc new file mode 100644 index 0000000000..96de2bce26 --- /dev/null +++ b/examples/hello-world/swift-platform/helloSwift.roc @@ -0,0 +1,6 @@ +app "helloSwift" + packages { pf: "." } + imports [] + provides [ main ] to pf + +main = "Hello, World!\n" diff --git a/examples/hello-swift/platform/host.h b/examples/hello-world/swift-platform/host.h similarity index 100% rename from examples/hello-swift/platform/host.h rename to examples/hello-world/swift-platform/host.h diff --git a/examples/hello-swift/platform/host.swift b/examples/hello-world/swift-platform/host.swift similarity index 95% rename from examples/hello-swift/platform/host.swift rename to examples/hello-world/swift-platform/host.swift index 74edc494d2..6451a6c534 100644 --- a/examples/hello-swift/platform/host.swift +++ b/examples/hello-world/swift-platform/host.swift @@ -53,6 +53,6 @@ extension RocStr { @_cdecl("main") func main() -> UInt8 { - print(roc__mainForHost_1_exposed().string) + print(roc__mainForHost_1_exposed().string, terminator: "") return 0 } diff --git a/examples/hello-world/web-platform/Package-Config.roc b/examples/hello-world/web-platform/Package-Config.roc new file mode 100644 index 0000000000..23b395f2db --- /dev/null +++ b/examples/hello-world/web-platform/Package-Config.roc @@ -0,0 +1,9 @@ +platform "hello-world-in-web-assembly" + requires {} { main : Str } + exposes [] + packages {} + imports [] + provides [ mainForHost ] + +mainForHost : Str +mainForHost = main diff --git a/examples/hello-web/README.md b/examples/hello-world/web-platform/README.md similarity index 76% rename from examples/hello-web/README.md rename to examples/hello-world/web-platform/README.md index 4401c8d367..9708431198 100644 --- a/examples/hello-web/README.md +++ b/examples/hello-world/web-platform/README.md @@ -1,16 +1,22 @@ # Hello, World! -To run, go to the project home directory and run: +To run this website, first compile either of these identical apps: ```bash -$ cargo run -- build --target=wasm32 examples/hello-web/Hello.roc +# Option A: Compile helloWeb.roc +cargo run -- build --target=wasm32 examples/hello-world/web-platform/helloWeb.roc + +# Option B: Compile helloWorld.roc with `pf: "web-platform"` and move the result +cargo run -- build --target=wasm32 examples/hello-world/helloWorld.roc +(cd examples/hello-world && mv helloWorld.wasm web-platform/helloWeb.wasm) ``` -Then `cd` into the example directory and run any web server that can handle WebAssembly. -For example with `http-server`: +Then `cd` into the website directory +and run any web server that can handle WebAssembly. +For example, with `http-server`: ```bash -cd examples/hello-web +cd examples/hello-world/web-platform npm install -g http-server http-server ``` @@ -20,7 +26,7 @@ Now open your browser at http://localhost:8080 ## Design Notes This demonstrates the basic design of hosts: Roc code gets compiled into a pure -function (in this case, a thunk that always returns `"Hello, World!"`) and +function (in this case, a thunk that always returns `"Hello, World!\n"`) and then the host calls that function. Fundamentally, that's the whole idea! The host might not even have a `main` - it could be a library, a plugin, anything. Everything else is built on this basic "hosts calling linked pure functions" design. diff --git a/examples/hello-world/web-platform/helloWeb.roc b/examples/hello-world/web-platform/helloWeb.roc new file mode 100644 index 0000000000..8ec32459cd --- /dev/null +++ b/examples/hello-world/web-platform/helloWeb.roc @@ -0,0 +1,6 @@ +app "helloWeb" + packages { pf: "." } + imports [] + provides [ main ] to pf + +main = "Hello, World!\n" diff --git a/examples/hello-web/platform/host.js b/examples/hello-world/web-platform/host.js similarity index 100% rename from examples/hello-web/platform/host.js rename to examples/hello-world/web-platform/host.js diff --git a/examples/hello-web/test-node.js b/examples/hello-world/web-platform/host.test.js similarity index 70% rename from examples/hello-web/test-node.js rename to examples/hello-world/web-platform/host.test.js index ce1eed5d6e..ac0b1f5dc7 100644 --- a/examples/hello-web/test-node.js +++ b/examples/hello-world/web-platform/host.test.js @@ -1,5 +1,5 @@ /** - * Node.js test file for hello-web example + * Node.js test file for helloWeb example * We are not running this in CI currently, and Node.js is not a Roc dependency. * But if you happen to have it, you can run this. */ @@ -13,10 +13,10 @@ global.fetch = (filename) => }, })); -const { roc_web_platform_run } = require("./platform/host"); +const { roc_web_platform_run } = require("./host"); -roc_web_platform_run("./hello-world.wasm", (string_from_roc) => { - const expected = "Hello, World!"; +roc_web_platform_run("../helloWeb.wasm", (string_from_roc) => { + const expected = "Hello, World!\n"; if (string_from_roc !== expected) { console.error(`Expected "${expected}", but got "${string_from_roc}"`); process.exit(1); diff --git a/examples/hello-web/platform/host.zig b/examples/hello-world/web-platform/host.zig similarity index 100% rename from examples/hello-web/platform/host.zig rename to examples/hello-world/web-platform/host.zig diff --git a/examples/hello-web/index.html b/examples/hello-world/web-platform/index.html similarity index 63% rename from examples/hello-web/index.html rename to examples/hello-world/web-platform/index.html index 87ca0302cb..0397305c5a 100644 --- a/examples/hello-web/index.html +++ b/examples/hello-world/web-platform/index.html @@ -1,10 +1,10 @@
- + diff --git a/examples/hello-world/platform/Package-Config.roc b/examples/hello-world/zig-platform/Package-Config.roc similarity index 81% rename from examples/hello-world/platform/Package-Config.roc rename to examples/hello-world/zig-platform/Package-Config.roc index 61e4c96bf2..5aeef200f4 100644 --- a/examples/hello-world/platform/Package-Config.roc +++ b/examples/hello-world/zig-platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/hello-world" +platform "hello-world-in-zig" requires {} { main : Str } exposes [] packages {} diff --git a/examples/hello-world/zig-platform/helloZig.roc b/examples/hello-world/zig-platform/helloZig.roc new file mode 100644 index 0000000000..6c7223111a --- /dev/null +++ b/examples/hello-world/zig-platform/helloZig.roc @@ -0,0 +1,6 @@ +app "helloZig" + packages { pf: "." } + imports [] + provides [ main ] to pf + +main = "Hello, World!\n" diff --git a/examples/hello-zig/platform/host.zig b/examples/hello-world/zig-platform/host.zig similarity index 98% rename from examples/hello-zig/platform/host.zig rename to examples/hello-world/zig-platform/host.zig index a2e4df7ac5..d30eccfbfe 100644 --- a/examples/hello-zig/platform/host.zig +++ b/examples/hello-world/zig-platform/host.zig @@ -97,7 +97,7 @@ pub fn main() u8 { std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts2) catch unreachable; // stdout the result - stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable; + stdout.print("{s}", .{callresult.asSlice()}) catch unreachable; callresult.deinit(); diff --git a/examples/hello-zig/.gitignore b/examples/hello-zig/.gitignore deleted file mode 100644 index 6b820fd903..0000000000 --- a/examples/hello-zig/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hello-world diff --git a/examples/hello-zig/Hello.roc b/examples/hello-zig/Hello.roc deleted file mode 100644 index 59bff71388..0000000000 --- a/examples/hello-zig/Hello.roc +++ /dev/null @@ -1,12 +0,0 @@ -app "hello-world" - packages { pf: "platform" } - imports [] - provides [ main ] to pf - -greeting = - hi = "Hello" - name = "World" - - "\(hi), \(name)!" - -main = greeting diff --git a/examples/hello-zig/README.md b/examples/hello-zig/README.md deleted file mode 100644 index 26d4c8e7d9..0000000000 --- a/examples/hello-zig/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# Hello, World! - -To run, `cd` into this directory and run: - -```bash -$ cargo run Hello.roc -``` - -To run in release mode instead, do: - -```bash -$ cargo run --release Hello.roc -``` - -## Design Notes - -This demonstrates the basic design of hosts: Roc code gets compiled into a pure -function (in this case, a thunk that always returns `"Hello, World!"`) and -then the host calls that function. Fundamentally, that's the whole idea! The host -might not even have a `main` - it could be a library, a plugin, anything. -Everything else is built on this basic "hosts calling linked pure functions" design. - -For example, things get more interesting when the compiled Roc function returns -a `Task` - that is, a tagged union data structure containing function pointers -to callback closures. This lets the Roc pure function describe arbitrary -chainable effects, which the host can interpret to perform I/O as requested by -the Roc program. (The tagged union `Task` would have a variant for each supported -I/O operation.) - -In this trivial example, it's very easy to line up the API between the host and -the Roc program. In a more involved host, this would be much trickier - especially -if the API were changing frequently during development. - -The idea there is to have a first-class concept of "glue code" which host authors -can write (it would be plain Roc code, but with some extra keywords that aren't -available in normal modules - kinda like `port module` in Elm), and which -describe both the Roc-host/C boundary as well as the Roc-host/Roc-app boundary. -Roc application authors only care about the Roc-host/Roc-app portion, and the -host author only cares about the Roc-host/C boundary when implementing the host. - -Using this glue code, the Roc compiler can generate C header files describing the -boundary. This not only gets us host compatibility with C compilers, but also -Rust FFI for free, because [`rust-bindgen`](https://github.com/rust-lang/rust-bindgen) -generates correct Rust FFI bindings from C headers. diff --git a/examples/hello-zig/platform/Package-Config.roc b/examples/hello-zig/platform/Package-Config.roc deleted file mode 100644 index 61e4c96bf2..0000000000 --- a/examples/hello-zig/platform/Package-Config.roc +++ /dev/null @@ -1,9 +0,0 @@ -platform "examples/hello-world" - requires {} { main : Str } - exposes [] - packages {} - imports [] - provides [ mainForHost ] - -mainForHost : Str -mainForHost = main diff --git a/examples/cli/.gitignore b/examples/interactive/.gitignore similarity index 62% rename from examples/cli/.gitignore rename to examples/interactive/.gitignore index a87a68d9e2..a36aa49837 100644 --- a/examples/cli/.gitignore +++ b/examples/interactive/.gitignore @@ -1,3 +1,5 @@ countdown echo +effects form +tui diff --git a/examples/interactive/README.md b/examples/interactive/README.md new file mode 100644 index 0000000000..92bc5563b0 --- /dev/null +++ b/examples/interactive/README.md @@ -0,0 +1,9 @@ +# Interactive examples + +These are examples of how to make extremely basic +CLI (command-line interface) and TUI (terminal user interface) apps in Roc. + +There's not currently much documentation for the CLI platform (which also doesn't support many operations at this point!) +but you can look at [the modules it includes](cli-platform) - for example, +multiple other modules use the [`Task`](cli-platform/Task.roc) module, including the +[`Stdin`](cli-platform/Stdin.roc) and [`Stdout`](cli-platform/Stdout.roc) modules. diff --git a/examples/cli/platform/Cargo.lock b/examples/interactive/cli-platform/Cargo.lock similarity index 100% rename from examples/cli/platform/Cargo.lock rename to examples/interactive/cli-platform/Cargo.lock diff --git a/examples/cli/platform/Cargo.toml b/examples/interactive/cli-platform/Cargo.toml similarity index 100% rename from examples/cli/platform/Cargo.toml rename to examples/interactive/cli-platform/Cargo.toml diff --git a/examples/cli/platform/Effect.roc b/examples/interactive/cli-platform/Effect.roc similarity index 100% rename from examples/cli/platform/Effect.roc rename to examples/interactive/cli-platform/Effect.roc diff --git a/examples/cli/platform/Package-Config.roc b/examples/interactive/cli-platform/Package-Config.roc similarity index 88% rename from examples/cli/platform/Package-Config.roc rename to examples/interactive/cli-platform/Package-Config.roc index 4f9c8bdf62..e106016d0d 100644 --- a/examples/cli/platform/Package-Config.roc +++ b/examples/interactive/cli-platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "examples/cli" +platform "cli" requires {} { main : Task {} [] } exposes [] packages {} diff --git a/examples/cli/platform/Stdin.roc b/examples/interactive/cli-platform/Stdin.roc similarity index 100% rename from examples/cli/platform/Stdin.roc rename to examples/interactive/cli-platform/Stdin.roc diff --git a/examples/cli/platform/Stdout.roc b/examples/interactive/cli-platform/Stdout.roc similarity index 100% rename from examples/cli/platform/Stdout.roc rename to examples/interactive/cli-platform/Stdout.roc diff --git a/examples/cli/platform/Task.roc b/examples/interactive/cli-platform/Task.roc similarity index 100% rename from examples/cli/platform/Task.roc rename to examples/interactive/cli-platform/Task.roc diff --git a/examples/hello-rust/platform/build.rs b/examples/interactive/cli-platform/build.rs similarity index 100% rename from examples/hello-rust/platform/build.rs rename to examples/interactive/cli-platform/build.rs diff --git a/examples/cli/platform/host.c b/examples/interactive/cli-platform/host.c similarity index 100% rename from examples/cli/platform/host.c rename to examples/interactive/cli-platform/host.c diff --git a/examples/cli/platform/src/lib.rs b/examples/interactive/cli-platform/src/lib.rs similarity index 100% rename from examples/cli/platform/src/lib.rs rename to examples/interactive/cli-platform/src/lib.rs diff --git a/examples/hello-rust/platform/src/main.rs b/examples/interactive/cli-platform/src/main.rs similarity index 100% rename from examples/hello-rust/platform/src/main.rs rename to examples/interactive/cli-platform/src/main.rs diff --git a/examples/cli/countdown.roc b/examples/interactive/countdown.roc similarity index 93% rename from examples/cli/countdown.roc rename to examples/interactive/countdown.roc index 79f9decb7c..8e022f1970 100644 --- a/examples/cli/countdown.roc +++ b/examples/interactive/countdown.roc @@ -1,5 +1,5 @@ app "countdown" - packages { pf: "platform" } + packages { pf: "cli-platform" } imports [ pf.Stdin, pf.Stdout, pf.Task.{ await, loop, succeed } ] provides [ main ] to pf diff --git a/examples/cli/echo.roc b/examples/interactive/echo.roc similarity index 95% rename from examples/cli/echo.roc rename to examples/interactive/echo.roc index 29cb05c17c..b40ad14154 100644 --- a/examples/cli/echo.roc +++ b/examples/interactive/echo.roc @@ -1,5 +1,5 @@ app "echo" - packages { pf: "platform" } + packages { pf: "cli-platform" } imports [ pf.Stdin, pf.Stdout, pf.Task ] provides [ main ] to pf diff --git a/examples/effect/thing/platform-dir/Effect.roc b/examples/interactive/effects-platform/Effect.roc similarity index 100% rename from examples/effect/thing/platform-dir/Effect.roc rename to examples/interactive/effects-platform/Effect.roc diff --git a/examples/effect/thing/platform-dir/Package-Config.roc b/examples/interactive/effects-platform/Package-Config.roc similarity index 86% rename from examples/effect/thing/platform-dir/Package-Config.roc rename to examples/interactive/effects-platform/Package-Config.roc index b7377c6412..4e4d6abea2 100644 --- a/examples/effect/thing/platform-dir/Package-Config.roc +++ b/examples/interactive/effects-platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "roc-examples/cli" +platform "effects" requires {} { main : Effect {} } exposes [] packages {} diff --git a/examples/effect/thing/platform-dir/host.zig b/examples/interactive/effects-platform/host.zig similarity index 100% rename from examples/effect/thing/platform-dir/host.zig rename to examples/interactive/effects-platform/host.zig diff --git a/examples/effect/Main.roc b/examples/interactive/effects.roc similarity index 86% rename from examples/effect/Main.roc rename to examples/interactive/effects.roc index d980596cfe..a81c87f1ea 100644 --- a/examples/effect/Main.roc +++ b/examples/interactive/effects.roc @@ -1,5 +1,5 @@ -app "effect-example" - packages { pf: "thing/platform-dir" } +app "effects" + packages { pf: "effects-platform" } imports [ pf.Effect ] provides [ main ] to pf diff --git a/examples/cli/form.roc b/examples/interactive/form.roc similarity index 90% rename from examples/cli/form.roc rename to examples/interactive/form.roc index 735c752527..171d4e8c98 100644 --- a/examples/cli/form.roc +++ b/examples/interactive/form.roc @@ -1,5 +1,5 @@ app "form" - packages { pf: "platform" } + packages { pf: "cli-platform" } imports [ pf.Stdin, pf.Stdout, pf.Task.{ await, Task } ] provides [ main ] to pf diff --git a/examples/tui/platform/Package-Config.roc b/examples/interactive/tui-platform/Package-Config.roc similarity index 90% rename from examples/tui/platform/Package-Config.roc rename to examples/interactive/tui-platform/Package-Config.roc index 8196beeb56..726147e9cb 100644 --- a/examples/tui/platform/Package-Config.roc +++ b/examples/interactive/tui-platform/Package-Config.roc @@ -1,4 +1,4 @@ -platform "folkertdev/foo" +platform "tui" requires { Model } { main : Effect {} } exposes [] packages {} diff --git a/examples/tui/platform/Program.roc b/examples/interactive/tui-platform/Program.roc similarity index 100% rename from examples/tui/platform/Program.roc rename to examples/interactive/tui-platform/Program.roc diff --git a/examples/tui/platform/host.zig b/examples/interactive/tui-platform/host.zig similarity index 100% rename from examples/tui/platform/host.zig rename to examples/interactive/tui-platform/host.zig diff --git a/examples/tui/Main.roc b/examples/interactive/tui.roc similarity index 88% rename from examples/tui/Main.roc rename to examples/interactive/tui.roc index 12b1a8da01..03b05efc17 100644 --- a/examples/tui/Main.roc +++ b/examples/interactive/tui.roc @@ -1,5 +1,5 @@ app "tui" - packages { pf: "platform" } + packages { pf: "tui-platform" } imports [ pf.Program.{ Program } ] provides [ main ] { Model } to pf diff --git a/examples/quicksort/README.md b/examples/quicksort/README.md deleted file mode 100644 index 6d0be18eed..0000000000 --- a/examples/quicksort/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Quicksort - -To run: - -```bash -$ cargo run Quicksort.roc -``` - -To run in release mode instead, do: - -```bash -$ cargo run --release Quicksort.roc -``` diff --git a/examples/tui/.gitignore b/examples/tui/.gitignore deleted file mode 100644 index ba0da0793e..0000000000 --- a/examples/tui/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tui diff --git a/getting_started/linux_x86.md b/getting_started/linux_x86.md index 5cb46e360b..f499209607 100644 --- a/getting_started/linux_x86.md +++ b/getting_started/linux_x86.md @@ -22,11 +22,11 @@ 0. Run examples with: ``` # Rust. If you installed rust in this terminal you'll need to open a new one first! - ./roc examples/hello-rust/Hello.roc + ./roc examples/hello-world/rust-platform/helloRust.roc # Zig - ./roc examples/hello-zig/Hello.roc + ./roc examples/hello-world/zig-platform/helloZig.roc # C - ./roc examples/hello-world/Hello.roc + ./roc examples/hello-world/c-platform/helloC.roc ``` 0. See [here](../README.md#examples) for the other examples. diff --git a/getting_started/other.md b/getting_started/other.md index 1686bd0e21..7d214058e4 100644 --- a/getting_started/other.md +++ b/getting_started/other.md @@ -4,11 +4,11 @@ 3. Run examples with: ``` # Rust - cargo run examples/hello-rust/Hello.roc + cargo run examples/hello-world/rust-platform/helloRust.roc # Zig - cargo run examples/hello-zig/Hello.roc + cargo run examples/hello-world/zig-platform/helloZig.roc # C - cargo run examples/hello-world/Hello.roc + cargo run examples/hello-world/c-platform/helloC.roc ``` 4. See [here](../README.md#examples) for the other examples. diff --git a/repl_eval/src/lib.rs b/repl_eval/src/lib.rs index 1db9f294ad..898777d4e4 100644 --- a/repl_eval/src/lib.rs +++ b/repl_eval/src/lib.rs @@ -50,7 +50,7 @@ pub trait ReplAppMemory { fn deref_dec(&self, addr: usize) -> RocDec { let bits = self.deref_i128(addr); - RocDec(bits) + RocDec::new(bits) } fn deref_str(&self, addr: usize) -> &str; diff --git a/reporting/src/error/mono.rs b/reporting/src/error/mono.rs index 86e6f7bf36..270f037a7d 100644 --- a/reporting/src/error/mono.rs +++ b/reporting/src/error/mono.rs @@ -156,8 +156,7 @@ fn pattern_to_doc_help<'b>( Bit(false) => alloc.text("False"), Byte(b) => alloc.text(b.to_string()), Float(f) => alloc.text(f.to_string()), - // TODO: Proper Dec.to_str - Decimal(d) => alloc.text(d.0.to_string()), + Decimal(d) => alloc.text(d.to_string()), Str(s) => alloc.string(s.into()), }, Ctor(union, tag_id, args) => { diff --git a/roc_std/src/lib.rs b/roc_std/src/lib.rs index 41fb698ae1..d52a3c2f9f 100644 --- a/roc_std/src/lib.rs +++ b/roc_std/src/lib.rs @@ -210,7 +210,7 @@ impl Drop for RocResult { } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct RocDec(pub i128); +pub struct RocDec(i128); impl RocDec { pub const MIN: Self = Self(i128::MIN); @@ -221,6 +221,16 @@ impl RocDec { const MAX_DIGITS: usize = 39; const MAX_STR_LENGTH: usize = Self::MAX_DIGITS + 2; // + 2 here to account for the sign & decimal dot + pub fn new(bits: i128) -> Self { + Self(bits) + } + + pub fn as_bits(&self) -> (i64, u64) { + let lower_bits = self.0 as u64; + let upper_bits = (self.0 >> 64) as i64; + (upper_bits, lower_bits) + } + #[allow(clippy::should_implement_trait)] pub fn from_str(value: &str) -> Option { // Split the string into the parts before and after the "."