Generate effectful hosted functions

This commit is contained in:
Agus Zubiaga 2024-10-13 22:50:27 -03:00
parent 7af05cc6c9
commit bc3ab0186a
No known key found for this signature in database
8 changed files with 59 additions and 56 deletions

View file

@ -33,7 +33,7 @@ pub fn build_host_exposed_def(
let def_body = {
match typ.shallow_structural_dealias() {
Type::Function(args, _, _, _) => {
Type::Function(args, _, _, fx) if **fx == Type::Pure => {
for i in 0..args.len() {
let name = format!("closure_arg_{ident}_{i}");
@ -109,6 +109,45 @@ pub fn build_host_exposed_def(
loc_body: Box::new(Loc::at_zero(body)),
})
}
Type::Function(args, _, _, fx) if **fx == Type::Effectful => {
for i in 0..args.len() {
let name = format!("{ident}_arg_{i}");
let arg_symbol = {
let ident = name.clone().into();
scope.introduce(ident, Region::zero()).unwrap()
};
let arg_var = var_store.fresh();
arguments.push((
arg_var,
AnnotatedMark::new(var_store),
Loc::at_zero(Pattern::Identifier(arg_symbol)),
));
linked_symbol_arguments.push((arg_var, Expr::Var(arg_symbol, arg_var)));
}
let foreign_symbol_name = format!("roc_fx_{ident}");
let foreign_call = Expr::ForeignCall {
foreign_symbol: foreign_symbol_name.into(),
args: linked_symbol_arguments,
ret_var: var_store.fresh(),
};
Expr::Closure(ClosureData {
function_type: var_store.fresh(),
closure_type: var_store.fresh(),
return_type: var_store.fresh(),
fx_type: var_store.fresh(),
name: symbol,
captured_symbols: std::vec::Vec::new(),
recursive: Recursive::NotRecursive,
arguments,
loc_body: Box::new(Loc::at_zero(foreign_call)),
})
}
_ => {
// not a function

View file

@ -14,6 +14,7 @@ pub mod copy;
pub mod def;
mod derive;
pub mod desugar;
pub mod effect_module;
pub mod env;
pub mod exhaustive;
pub mod expected;
@ -25,7 +26,6 @@ pub mod procedure;
pub mod scope;
pub mod string;
pub mod suffixed;
pub mod task_module;
pub mod traverse;
pub use derive::DERIVED_REGION;

View file

@ -533,7 +533,7 @@ pub fn canonicalize_module_defs<'a>(
aliases: Default::default(),
};
let hosted_def = crate::task_module::build_host_exposed_def(
let hosted_def = crate::effect_module::build_host_exposed_def(
&mut scope, *symbol, &ident, var_store, annotation,
);
@ -586,7 +586,7 @@ pub fn canonicalize_module_defs<'a>(
aliases: Default::default(),
};
let hosted_def = crate::task_module::build_host_exposed_def(
let hosted_def = crate::effect_module::build_host_exposed_def(
&mut scope, *symbol, &ident, var_store, annotation,
);

View file

@ -0,0 +1,7 @@
hosted Effect
exposes [putLine, getLine]
imports []
putLine : Str => {}
getLine : {} => Str

View file

@ -1,7 +0,0 @@
hosted PlatformTasks
exposes [putLine, getLine]
imports []
putLine : Str -> Task {} *
getLine : Task Str *

View file

@ -12,9 +12,6 @@ const Allocator = mem.Allocator;
extern fn roc__mainForHost_1_exposed_generic([*]u8) void;
extern fn roc__mainForHost_1_exposed_size() i64;
extern fn roc__mainForHost_0_caller(*const u8, [*]u8, [*]u8) void;
extern fn roc__mainForHost_0_size() i64;
extern fn roc__mainForHost_0_result_size() i64;
const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
@ -127,8 +124,6 @@ pub export fn main() u8 {
roc__mainForHost_1_exposed_generic(output);
call_the_closure(output);
const nanos = timer.read();
const seconds = (@as(f64, @floatFromInt(nanos)) / 1_000_000_000.0);
@ -141,35 +136,6 @@ fn to_seconds(tms: std.os.timespec) f64 {
return @as(f64, @floatFromInt(tms.tv_sec)) + (@as(f64, @floatFromInt(tms.tv_nsec)) / 1_000_000_000.0);
}
fn call_the_closure(closure_data_pointer: [*]u8) void {
const allocator = std.heap.page_allocator;
const size = roc__mainForHost_0_result_size();
if (size == 0) {
// the function call returns an empty record
// allocating 0 bytes causes issues because the allocator will return a NULL pointer
// So it's special-cased
const flags: u8 = 0;
var result: [1]u8 = .{0};
roc__mainForHost_0_caller(&flags, closure_data_pointer, &result);
return;
}
const raw_output = allocator.alignedAlloc(u8, @alignOf(u64), @as(usize, @intCast(size))) catch unreachable;
var output = @as([*]u8, @ptrCast(raw_output));
defer {
allocator.free(raw_output);
}
const flags: u8 = 0;
roc__mainForHost_0_caller(&flags, closure_data_pointer, output);
return;
}
pub export fn roc_fx_getLine() str.RocStr {
return roc_fx_getLine_help() catch return str.RocStr.empty();
}

View file

@ -1,9 +1,9 @@
platform "effects"
requires {} { main : Task {} [] }
requires {} { main : {} => {} }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Task {} []
mainForHost = main
mainForHost : {} => {}
mainForHost = \{} -> main {}

View file

@ -1,11 +1,9 @@
app [main] { pf: platform "effects-platform/main.roc" }
import pf.PlatformTasks
import pf.Effect
main : Task {} []
main =
line = PlatformTasks.getLine!
PlatformTasks.putLine! "You entered: $(line)"
PlatformTasks.putLine! "It is known"
Task.ok {}
main : {} => {}
main = \{} ->
line = Effect.getLine {}
_ = Effect.putLine "You entered: $(line)"
Effect.putLine "It is known"