make the example loop a couple of times

This commit is contained in:
Folkert 2020-12-13 19:58:23 +01:00
parent f00bd9ba01
commit a67a750fdc
5 changed files with 168 additions and 35 deletions

View file

@ -478,7 +478,6 @@ pub fn build_exp_literal<'a, 'ctx, 'env>(
let ctx = env.context; let ctx = env.context;
let builder = env.builder; let builder = env.builder;
let number_of_chars = str_literal.len() as u64; let number_of_chars = str_literal.len() as u64;
let elem_bytes = CHAR_LAYOUT.stack_size(env.ptr_bytes) as u64;
let ptr_bytes = env.ptr_bytes; let ptr_bytes = env.ptr_bytes;
let populate_str = |ptr| { let populate_str = |ptr| {

View file

@ -3,7 +3,6 @@ use bumpalo::Bump;
use inkwell::context::Context; use inkwell::context::Context;
use inkwell::types::BasicTypeEnum::{self, *}; use inkwell::types::BasicTypeEnum::{self, *};
use inkwell::types::{ArrayType, BasicType, FunctionType, IntType, PointerType, StructType}; use inkwell::types::{ArrayType, BasicType, FunctionType, IntType, PointerType, StructType};
use inkwell::values::IntValue;
use inkwell::AddressSpace; use inkwell::AddressSpace;
use roc_mono::layout::Layout; use roc_mono::layout::Layout;

View file

@ -1,5 +1,5 @@
interface Cmd interface Cmd
exposes [ Cmd, none, map, putLine ] exposes [ Cmd, none, map, putLine, getLine, always, after ]
imports [ Effect ] imports [ Effect ]
Cmd a : Effect.Effect a Cmd a : Effect.Effect a
@ -7,10 +7,18 @@ Cmd a : Effect.Effect a
none : Cmd {} none : Cmd {}
none = Effect.always {} none = Effect.always {}
# getLine = Effect.after Effect.getLine always always : {} -> Cmd {}
always = \x -> Effect.always x
getLine : (Str -> msg) -> Cmd msg
getLine = \toMsg ->
Effect.map Effect.getLine toMsg
putLine : Str -> Cmd {} putLine : Str -> Cmd {}
putLine = \line -> Effect.putLine line putLine = \line -> Effect.putLine line
map : Cmd a, (a -> b) -> Cmd b map : Cmd a, (a -> b) -> Cmd b
map = \cmd, transform -> Effect.map cmd transform map = \cmd, transform -> Effect.map cmd transform
after : Cmd a, (a -> Cmd b) -> Cmd b
after = \cmd, transform -> Effect.after cmd transform

View file

@ -12,8 +12,30 @@ platform folkertdev/foo
} }
mainForHost : {init : ({} -> I64) as Init } mainForHost :
{
init : ({} -> { model: I64, cmd : (Cmd.Cmd [ Line Str ]) as Fx }) as Init,
update : ([ Line Str ], I64 -> { model: I64, cmd : Cmd.Cmd [ Line Str ] } ) as Update
}
mainForHost = mainForHost =
{ init : \{} -> 42 } {
init : \{} ->
{
model: 42,
cmd:
Cmd.after (Cmd.putLine "Type a thing, and I'll say it back") \{} ->
Cmd.getLine (\l -> Line l)
},
update : \msg, model ->
when msg is
Line line ->
cmd =
Cmd.after (Cmd.putLine "You said:") \{} ->
Cmd.after (Cmd.putLine line) \{} ->
Cmd.after (Cmd.putLine "Type another thing, and I'll say it back") \{} ->
Cmd.getLine (\l -> Line l)
{ model: model + 1, cmd }
}

View file

@ -6,6 +6,9 @@ use roc_std::RocStr;
use std::alloc::Layout; use std::alloc::Layout;
use std::time::SystemTime; use std::time::SystemTime;
type Msg = RocStr;
type Model = i64;
extern "C" { extern "C" {
#[link_name = "roc__mainForHost_1_exposed"] #[link_name = "roc__mainForHost_1_exposed"]
fn roc_main(output: *mut u8) -> (); fn roc_main(output: *mut u8) -> ();
@ -19,6 +22,33 @@ extern "C" {
#[link_name = "roc__mainForHost_1_Init_size"] #[link_name = "roc__mainForHost_1_Init_size"]
fn size_Init() -> i64; fn size_Init() -> i64;
#[link_name = "roc__mainForHost_1_Init_result_size"]
fn size_Init_result() -> i64;
#[link_name = "roc__mainForHost_1_Update_caller"]
fn call_Update(
msg: Msg,
model: Model,
function_pointer: *const u8,
closure_data: *const u8,
output: *mut u8,
) -> ();
#[link_name = "roc__mainForHost_1_Update_size"]
fn size_Update() -> i64;
#[link_name = "roc__mainForHost_1_Update_result_size"]
fn size_Update_result() -> i64;
#[link_name = "roc__mainForHost_1_Fx_caller"]
fn call_Fx(function_pointer: *const u8, closure_data: *const u8, output: *mut u8) -> ();
#[link_name = "roc__mainForHost_1_Fx_size"]
fn size_Fx() -> i64;
#[link_name = "roc__mainForHost_1_Fx_result_size"]
fn size_Fx_result() -> i64;
#[link_name = "roc__mainForHost_1_Model_size"] #[link_name = "roc__mainForHost_1_Model_size"]
fn size_Model() -> i64; fn size_Model() -> i64;
} }
@ -50,23 +80,104 @@ pub fn roc_fx_getLine() -> RocStr {
RocStr::from_slice_with_capacity(line1.as_bytes(), line1.len()) RocStr::from_slice_with_capacity(line1.as_bytes(), line1.len())
} }
unsafe fn call_the_closure(function_pointer: *const u8, closure_data_ptr: *const u8) -> i64 { unsafe fn run_fx(function_pointer: *const u8, closure_data_ptr: *const u8) -> Msg {
let size = size_Init() as usize; let size = size_Fx_result() as usize;
alloca::with_stack_bytes(size, |buffer| { alloca::with_stack_bytes(size, |buffer| {
let buffer: *mut std::ffi::c_void = buffer; let buffer: *mut std::ffi::c_void = buffer;
let buffer: *mut u8 = buffer as *mut u8; let buffer: *mut u8 = buffer as *mut u8;
call_Init( call_Fx(
function_pointer, function_pointer,
42 as *const u8, // closure_data_ptr as *const u8, closure_data_ptr as *const u8,
buffer as *mut u8, buffer as *mut u8,
); );
let output = &*(buffer as *mut RocCallResult<i64>); let output = &*(buffer as *mut RocCallResult<()>);
match output.into() { match output.into() {
Ok(x) => x, Ok(()) => {
let mut bytes = *(buffer.add(8) as *const (u64, u64));
let msg = std::mem::transmute::<(u64, u64), RocStr>(bytes);
msg
}
Err(e) => panic!("failed with {}", e),
}
})
}
unsafe fn run_init(function_pointer: *const u8, closure_data_ptr: *const u8) -> (Model, Msg) {
let size = size_Init_result() as usize;
alloca::with_stack_bytes(size, |buffer| {
let buffer: *mut std::ffi::c_void = buffer;
let buffer: *mut u8 = buffer as *mut u8;
call_Init(function_pointer, 0 as *const u8, buffer as *mut u8);
// cmd < model, so the command comes first
let output = &*(buffer as *mut RocCallResult<()>);
match output.into() {
Ok(_) => {
let offset = 8 + size_Fx();
let model_ptr = buffer.add(offset as usize);
let model: i64 = *(model_ptr as *const i64);
let cmd_fn_ptr_ptr = buffer.add(8) as *const i64;
let cmd_fn_ptr = (*cmd_fn_ptr_ptr) as *const u8;
let cmd_closure_data_ptr = buffer.add(16);
let msg = run_fx(cmd_fn_ptr, cmd_closure_data_ptr);
(model, msg)
}
Err(e) => panic!("failed with {}", e),
}
})
}
unsafe fn run_update(
msg: RocStr,
model: Model,
function_pointer: *const u8,
closure_data_ptr: *const u8,
) -> (Model, Msg) {
let size = size_Update_result() as usize;
alloca::with_stack_bytes(size, |buffer| {
let buffer: *mut std::ffi::c_void = buffer;
let buffer: *mut u8 = buffer as *mut u8;
call_Update(
msg,
model,
function_pointer,
closure_data_ptr,
buffer as *mut u8,
);
// cmd < model, so the command comes first
let output = &*(buffer as *mut RocCallResult<()>);
match output.into() {
Ok(_) => {
let offset = 8 + size_Fx();
let model_ptr = buffer.add(offset as usize);
let model: i64 = *(model_ptr as *const i64);
let cmd_fn_ptr_ptr = buffer.add(8) as *const i64;
let cmd_fn_ptr = (*cmd_fn_ptr_ptr) as *const u8;
let cmd_closure_data_ptr = buffer.add(16);
let msg = run_fx(cmd_fn_ptr, cmd_closure_data_ptr);
(model, msg)
}
Err(e) => panic!("failed with {}", e), Err(e) => panic!("failed with {}", e),
} }
}) })
@ -83,37 +194,31 @@ pub fn rust_main() -> isize {
roc_main(buffer); roc_main(buffer);
let output = &*(buffer as *mut RocCallResult<*const u8>); let output = &*(buffer as *mut RocCallResult<(*const u8, *const u8)>);
match output.into() { match output.into() {
Ok(_) if size > 16 => { Ok((init_fn_ptr, update_fn_ptr)) => {
let function_pointer = {
// this is a pointer to the location where the function pointer is stored
// we pass just the function pointer
let temp = buffer.offset(8) as *const i64;
(*temp) as *const u8
};
let closure_data_ptr = buffer.offset(16);
let result =
call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8);
std::alloc::dealloc(buffer, layout);
result
}
Ok(function_pointer) => {
// let closure_data_ptr = buffer.offset(16); // let closure_data_ptr = buffer.offset(16);
let closure_data_ptr = 0 as *const u8; let closure_data_ptr = 0 as *const u8;
let result = let (mut model, mut msg) =
call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8); run_init(init_fn_ptr as *const u8, closure_data_ptr as *const u8);
for _ in 0..5 {
let result = run_update(
msg,
model,
update_fn_ptr as *const u8,
closure_data_ptr as *const u8,
);
model = result.0;
msg = result.1;
}
std::alloc::dealloc(buffer, layout); std::alloc::dealloc(buffer, layout);
result model
} }
Err(msg) => { Err(msg) => {
std::alloc::dealloc(buffer, layout); std::alloc::dealloc(buffer, layout);