diff --git a/compiler/gen/src/llvm/build.rs b/compiler/gen/src/llvm/build.rs index 94fc5202b3..335eb91c1e 100644 --- a/compiler/gen/src/llvm/build.rs +++ b/compiler/gen/src/llvm/build.rs @@ -478,7 +478,6 @@ pub fn build_exp_literal<'a, 'ctx, 'env>( let ctx = env.context; let builder = env.builder; 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 populate_str = |ptr| { diff --git a/compiler/gen/src/llvm/convert.rs b/compiler/gen/src/llvm/convert.rs index 5bcc9b4c78..cb7842b859 100644 --- a/compiler/gen/src/llvm/convert.rs +++ b/compiler/gen/src/llvm/convert.rs @@ -3,7 +3,6 @@ use bumpalo::Bump; use inkwell::context::Context; use inkwell::types::BasicTypeEnum::{self, *}; use inkwell::types::{ArrayType, BasicType, FunctionType, IntType, PointerType, StructType}; -use inkwell::values::IntValue; use inkwell::AddressSpace; use roc_mono::layout::Layout; diff --git a/examples/tea/platform/Cmd.roc b/examples/tea/platform/Cmd.roc index 07c6158cfc..cb0a78b1cc 100644 --- a/examples/tea/platform/Cmd.roc +++ b/examples/tea/platform/Cmd.roc @@ -1,5 +1,5 @@ interface Cmd - exposes [ Cmd, none, map, putLine ] + exposes [ Cmd, none, map, putLine, getLine, always, after ] imports [ Effect ] Cmd a : Effect.Effect a @@ -7,10 +7,18 @@ Cmd a : Effect.Effect a none : Cmd {} 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 = \line -> Effect.putLine line map : Cmd a, (a -> b) -> Cmd b map = \cmd, transform -> Effect.map cmd transform + +after : Cmd a, (a -> Cmd b) -> Cmd b +after = \cmd, transform -> Effect.after cmd transform diff --git a/examples/tea/platform/Pkg-Config.roc b/examples/tea/platform/Pkg-Config.roc index 0ccf2493a6..6d9a0a0752 100644 --- a/examples/tea/platform/Pkg-Config.roc +++ b/examples/tea/platform/Pkg-Config.roc @@ -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 = - { 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 } + } diff --git a/examples/tea/platform/src/lib.rs b/examples/tea/platform/src/lib.rs index 5ad83af045..3d9efe668d 100644 --- a/examples/tea/platform/src/lib.rs +++ b/examples/tea/platform/src/lib.rs @@ -6,6 +6,9 @@ use roc_std::RocStr; use std::alloc::Layout; use std::time::SystemTime; +type Msg = RocStr; +type Model = i64; + extern "C" { #[link_name = "roc__mainForHost_1_exposed"] fn roc_main(output: *mut u8) -> (); @@ -19,6 +22,33 @@ extern "C" { #[link_name = "roc__mainForHost_1_Init_size"] 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"] fn size_Model() -> i64; } @@ -50,23 +80,104 @@ pub fn roc_fx_getLine() -> RocStr { 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 { - let size = size_Init() as usize; +unsafe fn run_fx(function_pointer: *const u8, closure_data_ptr: *const u8) -> Msg { + let size = size_Fx_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( + call_Fx( function_pointer, - 42 as *const u8, // closure_data_ptr as *const u8, + closure_data_ptr as *const u8, buffer as *mut u8, ); - let output = &*(buffer as *mut RocCallResult); + let output = &*(buffer as *mut RocCallResult<()>); 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), } }) @@ -83,37 +194,31 @@ pub fn rust_main() -> isize { roc_main(buffer); - let output = &*(buffer as *mut RocCallResult<*const u8>); + let output = &*(buffer as *mut RocCallResult<(*const u8, *const u8)>); match output.into() { - Ok(_) if size > 16 => { - 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) => { + Ok((init_fn_ptr, update_fn_ptr)) => { // let closure_data_ptr = buffer.offset(16); let closure_data_ptr = 0 as *const u8; - let result = - call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8); + let (mut model, mut msg) = + 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); - result + model } Err(msg) => { std::alloc::dealloc(buffer, layout);