mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Add examples/cli
This commit is contained in:
parent
1348ec433b
commit
7069046aaf
13 changed files with 255 additions and 1 deletions
1
examples/.gitignore
vendored
1
examples/.gitignore
vendored
|
@ -4,4 +4,3 @@ app
|
||||||
libhost.a
|
libhost.a
|
||||||
roc_app.ll
|
roc_app.ll
|
||||||
roc_app.bc
|
roc_app.bc
|
||||||
effect-example
|
|
||||||
|
|
1
examples/cli/.gitignore
vendored
Normal file
1
examples/cli/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
cli-example
|
8
examples/cli/Main.roc
Normal file
8
examples/cli/Main.roc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
app "cli-example"
|
||||||
|
packages { base: "platform" }
|
||||||
|
imports [ fx.Effect ]
|
||||||
|
provides [ main ] to base
|
||||||
|
|
||||||
|
main : Effect.Effect {}
|
||||||
|
main =
|
||||||
|
Effect.after Effect.getLine \lineThisThing -> Effect.putLine lineThisThing
|
BIN
examples/cli/cli-example
Executable file
BIN
examples/cli/cli-example
Executable file
Binary file not shown.
BIN
examples/cli/hello-world
Executable file
BIN
examples/cli/hello-world
Executable file
Binary file not shown.
21
examples/cli/platform/Cargo.lock
generated
Normal file
21
examples/cli/platform/Cargo.lock
generated
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "host"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"roc_std",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc_std"
|
||||||
|
version = "0.1.0"
|
15
examples/cli/platform/Cargo.toml
Normal file
15
examples/cli/platform/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "host"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["The Roc Contributors"]
|
||||||
|
license = "UPL-1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
roc_std = { path = "../../../roc_std" }
|
||||||
|
libc = "0.2"
|
||||||
|
|
||||||
|
[workspace]
|
15
examples/cli/platform/Package-Config.roc
Normal file
15
examples/cli/platform/Package-Config.roc
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
platform examples/cli
|
||||||
|
requires {} { main : Effect {} }
|
||||||
|
exposes []
|
||||||
|
packages {}
|
||||||
|
imports [ fx.Effect ]
|
||||||
|
provides [ mainForHost ]
|
||||||
|
effects fx.Effect
|
||||||
|
{
|
||||||
|
putLine : Str -> Effect {},
|
||||||
|
getLine : Effect Str
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mainForHost : Effect.Effect {} as Fx
|
||||||
|
mainForHost = main
|
17
examples/cli/platform/Stdin.roc
Normal file
17
examples/cli/platform/Stdin.roc
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
interface Stdin
|
||||||
|
exposes [ getInt ]
|
||||||
|
imports [ fx.Effect, Task ]
|
||||||
|
|
||||||
|
|
||||||
|
getInt : Task.Task I64 []
|
||||||
|
getInt =
|
||||||
|
Effect.after Effect.getInt \{ isError, value, errorCode } ->
|
||||||
|
when isError is
|
||||||
|
True ->
|
||||||
|
when errorCode is
|
||||||
|
# A -> Task.fail InvalidCharacter
|
||||||
|
# B -> Task.fail IOError
|
||||||
|
_ -> Task.succeed -1
|
||||||
|
|
||||||
|
False ->
|
||||||
|
Task.succeed value
|
9
examples/cli/platform/Stdout.roc
Normal file
9
examples/cli/platform/Stdout.roc
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
interface Stdout
|
||||||
|
exposes [ putLine, putInt ]
|
||||||
|
imports [ fx.Effect, Task ]
|
||||||
|
|
||||||
|
putLine : Str -> Task {} *
|
||||||
|
putLine = \line -> Effect.map (Effect.putLine line) (\_ -> Ok {})
|
||||||
|
|
||||||
|
putInt : I64 -> Task {} *
|
||||||
|
putInt = \line -> Effect.map (Effect.putInt line) (\_ -> Ok {})
|
30
examples/cli/platform/Task.roc
Normal file
30
examples/cli/platform/Task.roc
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
interface Task
|
||||||
|
exposes [ Task, succeed, fail, after, map ]
|
||||||
|
imports [ fx.Effect ]
|
||||||
|
|
||||||
|
|
||||||
|
Task ok err : Effect.Effect (Result ok err)
|
||||||
|
|
||||||
|
|
||||||
|
succeed : val -> Task val *
|
||||||
|
succeed = \val ->
|
||||||
|
Effect.always (Ok val)
|
||||||
|
|
||||||
|
|
||||||
|
fail : err -> Task * err
|
||||||
|
fail = \val ->
|
||||||
|
Effect.always (Err val)
|
||||||
|
|
||||||
|
after : Task a err, (a -> Task b err) -> Task b err
|
||||||
|
after = \effect, transform ->
|
||||||
|
Effect.after effect \result ->
|
||||||
|
when result is
|
||||||
|
Ok a -> transform a
|
||||||
|
Err err -> Task.fail err
|
||||||
|
|
||||||
|
map : Task a err, (a -> b) -> Task b err
|
||||||
|
map = \effect, transform ->
|
||||||
|
Effect.map effect \result ->
|
||||||
|
when result is
|
||||||
|
Ok a -> Ok (transform a)
|
||||||
|
Err err -> Err err
|
7
examples/cli/platform/host.c
Normal file
7
examples/cli/platform/host.c
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern int rust_main();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return rust_main();
|
||||||
|
}
|
132
examples/cli/platform/src/lib.rs
Normal file
132
examples/cli/platform/src/lib.rs
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use core::ffi::c_void;
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
use roc_std::{RocCallResult, RocStr};
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#[link_name = "roc__mainForHost_1_exposed"]
|
||||||
|
fn roc_main(output: *mut u8) -> ();
|
||||||
|
|
||||||
|
#[link_name = "roc__mainForHost_size"]
|
||||||
|
fn roc_main_size() -> i64;
|
||||||
|
|
||||||
|
#[link_name = "roc__mainForHost_1_Fx_caller"]
|
||||||
|
fn call_Fx(flags: *const u8, closure_data: *const u8, output: *mut u8) -> ();
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[link_name = "roc__mainForHost_1_Fx_size"]
|
||||||
|
fn size_Fx() -> i64;
|
||||||
|
|
||||||
|
#[link_name = "roc__mainForHost_1_Fx_result_size"]
|
||||||
|
fn size_Fx_result() -> i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void {
|
||||||
|
return libc::malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe 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 fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) {
|
||||||
|
return libc::free(c_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
|
match tag_id {
|
||||||
|
0 => {
|
||||||
|
let slice = CStr::from_ptr(c_ptr as *const c_char);
|
||||||
|
let string = slice.to_str().unwrap();
|
||||||
|
eprintln!("Roc hit a panic: {}", string);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn rust_main() -> isize {
|
||||||
|
let size = unsafe { roc_main_size() } as usize;
|
||||||
|
let layout = Layout::array::<u8>(size).unwrap();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// TODO allocate on the stack if it's under a certain size
|
||||||
|
let buffer = std::alloc::alloc(layout);
|
||||||
|
|
||||||
|
roc_main(buffer);
|
||||||
|
|
||||||
|
let output = buffer as *mut RocCallResult<()>;
|
||||||
|
|
||||||
|
match (&*output).into() {
|
||||||
|
Ok(()) => {
|
||||||
|
let closure_data_ptr = buffer.offset(8);
|
||||||
|
let result = call_the_closure(closure_data_ptr as *const u8);
|
||||||
|
|
||||||
|
std::alloc::dealloc(buffer, layout);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
Err(msg) => {
|
||||||
|
std::alloc::dealloc(buffer, layout);
|
||||||
|
|
||||||
|
panic!("Roc failed with message: {}", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exit code
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn call_the_closure(closure_data_ptr: *const u8) -> i64 {
|
||||||
|
let size = size_Fx_result() as usize;
|
||||||
|
let layout = Layout::array::<u8>(size).unwrap();
|
||||||
|
let buffer = std::alloc::alloc(layout) as *mut u8;
|
||||||
|
|
||||||
|
call_Fx(
|
||||||
|
// This flags pointer will never get dereferenced
|
||||||
|
MaybeUninit::uninit().as_ptr(),
|
||||||
|
closure_data_ptr as *const u8,
|
||||||
|
buffer as *mut u8,
|
||||||
|
);
|
||||||
|
|
||||||
|
let output = &*(buffer as *mut RocCallResult<()>);
|
||||||
|
|
||||||
|
match output.into() {
|
||||||
|
Ok(_) => 0,
|
||||||
|
Err(e) => panic!("failed with {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn roc_fx_getLine() -> RocStr {
|
||||||
|
use std::io::{self, BufRead};
|
||||||
|
|
||||||
|
let stdin = io::stdin();
|
||||||
|
let line1 = stdin.lock().lines().next().unwrap().unwrap();
|
||||||
|
|
||||||
|
RocStr::from_slice(line1.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn roc_fx_putLine(line: RocStr) -> () {
|
||||||
|
let bytes = line.as_slice();
|
||||||
|
let string = unsafe { std::str::from_utf8_unchecked(bytes) };
|
||||||
|
println!("{}", string);
|
||||||
|
|
||||||
|
()
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue