Merge branch 'trunk' of github.com:rtfeldman/roc into wasm-runtime-error

This commit is contained in:
Brian Carroll 2022-03-08 08:58:15 +00:00
commit 70804e9bec
102 changed files with 253 additions and 645 deletions

View file

@ -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.

View file

@ -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.

View file

@ -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(|| {

View file

@ -1,4 +1,4 @@
platform "examples/multi-module"
platform "multi-module"
requires {}{ main : Str }
exposes []
packages {}

View file

@ -1,4 +1,4 @@
platform "examples/multi-dep-thunk"
platform "multi-dep-thunk"
requires {}{ main : Str }
exposes []
packages {}

View file

@ -1 +1 @@
../../../examples/cli/platform
../../../examples/interactive/cli-platform

View file

@ -794,11 +794,13 @@ pub fn build_exp_literal<'a, 'ctx, 'env>(
_ => panic!("Invalid layout for float literal = {:?}", layout),
},
Decimal(int) => env
.context
Decimal(int) => {
let (upper_bits, lower_bits) = int.as_bits();
env.context
.i128_type()
.const_int(int.0 as u64, false)
.into(),
.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) => {

View file

@ -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;

View file

@ -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 {}

View file

@ -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));

View file

@ -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)),

View file

@ -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",
),
],

View file

@ -1,4 +1,4 @@
platform "examples/cli"
platform "cli"
requires {}{ main : Task {} [] } # TODO FIXME
exposes []
packages {}

View file

@ -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);

6
examples/.gitignore vendored
View file

@ -1,10 +1,6 @@
app
*.o
*.dSYM
libhost.a
roc_app.ll
roc_app.bc
libapp.so
dynhost
preprocessedhost
metadata
libapp.so

View file

@ -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.

View file

@ -1 +1,2 @@
fibonacci
quicksort

View file

@ -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
```

View file

@ -1,4 +1,4 @@
platform "examples/add"
platform "fibonacci"
requires {} { main : I64 -> I64 }
exposes []
packages {}

View file

@ -1,5 +1,5 @@
app "fib"
packages { pf: "platform" }
app "fibonacci"
packages { pf: "fibonacci-platform" }
imports []
provides [ main ] to pf

View file

@ -1,4 +1,4 @@
platform "examples/quicksort"
platform "quicksort"
requires {} { quicksort : List I64 -> List I64 }
exposes []
packages {}

View file

@ -1,5 +1,5 @@
app "quicksort"
packages { pf: "platform" }
packages { pf: "quicksort-platform" }
imports []
provides [ quicksort ] to pf

View file

@ -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

View file

@ -1,4 +1,4 @@
platform "folkertdev/foo"
platform "benchmarks"
requires {} { main : Effect {} }
exposes []
packages {}

View file

@ -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.

View file

@ -1 +0,0 @@
effect-example

View file

@ -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

View file

@ -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

View file

@ -1,4 +1,4 @@
platform "examples/cli"
platform "false-interpreter"
requires {} { main : Str -> Task {} [] }
exposes []
packages {}

View file

@ -1,2 +0,0 @@
add
fib

View file

@ -1,4 +1,4 @@
platform "examples/hello-world"
platform "gui"
requires {} { render : Elem }
exposes []
packages {}

View file

@ -1 +0,0 @@
hello-rust

View file

@ -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

View file

@ -1 +0,0 @@
hello-swift

View file

@ -1,10 +0,0 @@
app "hello-swift"
packages { pf: "platform" }
imports []
provides [ main ] to pf
main =
host = "Swift"
app = "Roc"
"Hello \(host), meet \(app)"

View file

@ -1,2 +0,0 @@
hello-web.wasm
*.wat

View file

@ -1,12 +0,0 @@
app "hello-web"
packages { pf: "platform" }
imports []
provides [ main ] to pf
greeting =
hi = "Hello"
name = "World"
"\(hi), \(name)!"
main = greeting

View file

@ -1 +1,7 @@
hello-world
helloC
helloRust
helloSwift
helloWeb.wasm
helloWorld
helloWorld.wasm
helloZig

View file

@ -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.

View file

@ -1,4 +1,4 @@
platform "examples/hello-swift"
platform "hello-world-in-c"
requires {} { main : Str }
exposes []
packages {}

View file

@ -1,5 +1,5 @@
app "hello-world"
packages { pf: "platform" }
app "helloC"
packages { pf: "." }
imports []
provides [ main ] to pf

View file

@ -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"

View file

@ -1,4 +1,4 @@
platform "examples/hello-world"
platform "hello-world-in-rust"
requires {} { main : Str }
exposes []
packages {}

View file

@ -0,0 +1,6 @@
app "helloRust"
packages { pf: "." }
imports []
provides [ main ] to pf
main = "Hello, World!\n"

View file

@ -1,4 +1,4 @@
platform "examples/hello-world"
platform "hello-world-in-swift"
requires {} { main : Str }
exposes []
packages {}

View file

@ -0,0 +1,6 @@
app "helloSwift"
packages { pf: "." }
imports []
provides [ main ] to pf
main = "Hello, World!\n"

View file

@ -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
}

View file

@ -0,0 +1,9 @@
platform "hello-world-in-web-assembly"
requires {} { main : Str }
exposes []
packages {}
imports []
provides [ mainForHost ]
mainForHost : Str
mainForHost = main

View file

@ -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.

View file

@ -0,0 +1,6 @@
app "helloWeb"
packages { pf: "." }
imports []
provides [ main ] to pf
main = "Hello, World!\n"

View file

@ -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);

View file

@ -1,10 +1,10 @@
<html>
<body>
<div id="output"></div>
<script src="platform/host.js"></script>
<script src="./host.js"></script>
<script>
const elem = document.getElementById("output");
roc_web_platform_run("./hello-web.wasm", (string_from_roc) => {
roc_web_platform_run("./helloWeb.wasm", (string_from_roc) => {
elem.textContent = string_from_roc;
});
</script>

View file

@ -1,4 +1,4 @@
platform "examples/hello-world"
platform "hello-world-in-zig"
requires {} { main : Str }
exposes []
packages {}

View file

@ -0,0 +1,6 @@
app "helloZig"
packages { pf: "." }
imports []
provides [ main ] to pf
main = "Hello, World!\n"

View file

@ -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();

View file

@ -1 +0,0 @@
hello-world

View file

@ -1,12 +0,0 @@
app "hello-world"
packages { pf: "platform" }
imports []
provides [ main ] to pf
greeting =
hi = "Hello"
name = "World"
"\(hi), \(name)!"
main = greeting

View file

@ -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.

View file

@ -1,9 +0,0 @@
platform "examples/hello-world"
requires {} { main : Str }
exposes []
packages {}
imports []
provides [ mainForHost ]
mainForHost : Str
mainForHost = main

View file

@ -1,3 +1,5 @@
countdown
echo
effects
form
tui

View file

@ -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.

View file

@ -1,4 +1,4 @@
platform "examples/cli"
platform "cli"
requires {} { main : Task {} [] }
exposes []
packages {}

View file

@ -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

View file

@ -1,5 +1,5 @@
app "echo"
packages { pf: "platform" }
packages { pf: "cli-platform" }
imports [ pf.Stdin, pf.Stdout, pf.Task ]
provides [ main ] to pf

View file

@ -1,4 +1,4 @@
platform "roc-examples/cli"
platform "effects"
requires {} { main : Effect {} }
exposes []
packages {}

View file

@ -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

View file

@ -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

View file

@ -1,4 +1,4 @@
platform "folkertdev/foo"
platform "tui"
requires { Model } { main : Effect {} }
exposes []
packages {}

View file

@ -1,5 +1,5 @@
app "tui"
packages { pf: "platform" }
packages { pf: "tui-platform" }
imports [ pf.Program.{ Program } ]
provides [ main ] { Model } to pf

View file

@ -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
```

View file

@ -1 +0,0 @@
tui

View file

@ -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.

View file

@ -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.

View file

@ -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;

Some files were not shown because too many files have changed in this diff Show more