mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
make roc main return values, instead of write them into pointer
This commit is contained in:
parent
f13e65ff8e
commit
e319d1e758
9 changed files with 199 additions and 120 deletions
|
@ -22,7 +22,7 @@ comptime {
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
|
|
||||||
extern fn roc__mainForHost_1_exposed(*RocStr) void;
|
extern fn roc__mainForHost_1_exposed() RocStr;
|
||||||
|
|
||||||
extern fn malloc(size: usize) callconv(.C) ?*c_void;
|
extern fn malloc(size: usize) callconv(.C) ?*c_void;
|
||||||
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void;
|
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void;
|
||||||
|
@ -53,15 +53,12 @@ pub export fn main() i32 {
|
||||||
const stdout = std.io.getStdOut().writer();
|
const stdout = std.io.getStdOut().writer();
|
||||||
const stderr = std.io.getStdErr().writer();
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
|
||||||
// make space for the result
|
|
||||||
var callresult = RocStr.empty();
|
|
||||||
|
|
||||||
// start time
|
// start time
|
||||||
var ts1: std.os.timespec = undefined;
|
var ts1: std.os.timespec = undefined;
|
||||||
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
||||||
|
|
||||||
// actually call roc to populate the callresult
|
// actually call roc to populate the callresult
|
||||||
roc__mainForHost_1_exposed(&callresult);
|
const callresult = roc__mainForHost_1_exposed();
|
||||||
|
|
||||||
// stdout the result
|
// stdout the result
|
||||||
stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable;
|
stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable;
|
||||||
|
|
|
@ -22,7 +22,7 @@ comptime {
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
|
|
||||||
extern fn roc__mainForHost_1_exposed(*RocStr) void;
|
extern fn roc__mainForHost_1_exposed() RocStr;
|
||||||
|
|
||||||
extern fn malloc(size: usize) callconv(.C) ?*c_void;
|
extern fn malloc(size: usize) callconv(.C) ?*c_void;
|
||||||
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void;
|
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void;
|
||||||
|
@ -53,15 +53,12 @@ pub export fn main() i32 {
|
||||||
const stdout = std.io.getStdOut().writer();
|
const stdout = std.io.getStdOut().writer();
|
||||||
const stderr = std.io.getStdErr().writer();
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
|
||||||
// make space for the result
|
|
||||||
var callresult = RocStr.empty();
|
|
||||||
|
|
||||||
// start time
|
// start time
|
||||||
var ts1: std.os.timespec = undefined;
|
var ts1: std.os.timespec = undefined;
|
||||||
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
||||||
|
|
||||||
// actually call roc to populate the callresult
|
// actually call roc to populate the callresult
|
||||||
roc__mainForHost_1_exposed(&callresult);
|
const callresult = roc__mainForHost_1_exposed();
|
||||||
|
|
||||||
// stdout the result
|
// stdout the result
|
||||||
stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable;
|
stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable;
|
||||||
|
|
|
@ -704,8 +704,14 @@ fn promote_to_main_function<'a, 'ctx, 'env>(
|
||||||
let main_fn_name = "$Test.main";
|
let main_fn_name = "$Test.main";
|
||||||
|
|
||||||
// Add main to the module.
|
// Add main to the module.
|
||||||
let main_fn =
|
let main_fn = expose_function_to_host_help_c_abi(
|
||||||
expose_function_to_host_help_c_abi(env, main_fn_name, roc_main_fn, &[], main_fn_name);
|
env,
|
||||||
|
main_fn_name,
|
||||||
|
roc_main_fn,
|
||||||
|
&[],
|
||||||
|
top_level.result,
|
||||||
|
main_fn_name,
|
||||||
|
);
|
||||||
|
|
||||||
(main_fn_name, main_fn)
|
(main_fn_name, main_fn)
|
||||||
}
|
}
|
||||||
|
@ -3075,6 +3081,7 @@ fn expose_function_to_host<'a, 'ctx, 'env>(
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
roc_function: FunctionValue<'ctx>,
|
roc_function: FunctionValue<'ctx>,
|
||||||
arguments: &[Layout<'a>],
|
arguments: &[Layout<'a>],
|
||||||
|
return_layout: Layout<'a>,
|
||||||
) {
|
) {
|
||||||
// Assumption: there is only one specialization of a host-exposed function
|
// Assumption: there is only one specialization of a host-exposed function
|
||||||
let ident_string = symbol.as_str(&env.interns);
|
let ident_string = symbol.as_str(&env.interns);
|
||||||
|
@ -3085,32 +3092,19 @@ fn expose_function_to_host<'a, 'ctx, 'env>(
|
||||||
ident_string,
|
ident_string,
|
||||||
roc_function,
|
roc_function,
|
||||||
arguments,
|
arguments,
|
||||||
|
return_layout,
|
||||||
&c_function_name,
|
&c_function_name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
ident_string: &str,
|
|
||||||
roc_function: FunctionValue<'ctx>,
|
roc_function: FunctionValue<'ctx>,
|
||||||
arguments: &[Layout<'a>],
|
arguments: &[Layout<'a>],
|
||||||
c_function_name: &str,
|
c_function_name: &str,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
let context = env.context;
|
// NOTE we ingore env.is_gen_test here
|
||||||
|
let wrapper_return_type = roc_function.get_type().get_return_type().unwrap();
|
||||||
let wrapper_return_type = if env.is_gen_test {
|
|
||||||
context
|
|
||||||
.struct_type(
|
|
||||||
&[
|
|
||||||
context.i64_type().into(),
|
|
||||||
roc_function.get_type().get_return_type().unwrap(),
|
|
||||||
],
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
roc_function.get_type().get_return_type().unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena);
|
let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena);
|
||||||
for layout in arguments {
|
for layout in arguments {
|
||||||
|
@ -3121,6 +3115,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
||||||
// let mut argument_types = roc_function.get_type().get_param_types();
|
// let mut argument_types = roc_function.get_type().get_param_types();
|
||||||
let mut argument_types = cc_argument_types;
|
let mut argument_types = cc_argument_types;
|
||||||
let return_type = wrapper_return_type;
|
let return_type = wrapper_return_type;
|
||||||
|
|
||||||
let output_type = return_type.ptr_type(AddressSpace::Generic);
|
let output_type = return_type.ptr_type(AddressSpace::Generic);
|
||||||
argument_types.push(output_type.into());
|
argument_types.push(output_type.into());
|
||||||
|
|
||||||
|
@ -3148,9 +3143,11 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
||||||
debug_info_init!(env, c_function);
|
debug_info_init!(env, c_function);
|
||||||
|
|
||||||
// drop the final argument, which is the pointer we write the result into
|
// drop the final argument, which is the pointer we write the result into
|
||||||
let args = c_function.get_params();
|
let args_vector = c_function.get_params();
|
||||||
let output_arg_index = args.len() - 1;
|
let mut args = args_vector.as_slice();
|
||||||
let args = &args[..args.len() - 1];
|
let args_length = args.len();
|
||||||
|
|
||||||
|
args = &args[..args.len() - 1];
|
||||||
|
|
||||||
let mut arguments_for_call = Vec::with_capacity_in(args.len(), env.arena);
|
let mut arguments_for_call = Vec::with_capacity_in(args.len(), env.arena);
|
||||||
|
|
||||||
|
@ -3200,15 +3197,173 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let output_arg_index = args_length - 1;
|
||||||
|
|
||||||
let output_arg = c_function
|
let output_arg = c_function
|
||||||
.get_nth_param(output_arg_index as u32)
|
.get_nth_param(output_arg_index as u32)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
|
|
||||||
builder.build_store(output_arg, call_result);
|
builder.build_store(output_arg, call_result);
|
||||||
|
|
||||||
builder.build_return(None);
|
builder.build_return(None);
|
||||||
|
|
||||||
|
c_function
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
ident_string: &str,
|
||||||
|
roc_function: FunctionValue<'ctx>,
|
||||||
|
arguments: &[Layout<'a>],
|
||||||
|
return_layout: Layout<'a>,
|
||||||
|
c_function_name: &str,
|
||||||
|
) -> FunctionValue<'ctx> {
|
||||||
|
let context = env.context;
|
||||||
|
|
||||||
|
// a generic version that writes the result into a passed *u8 pointer
|
||||||
|
if !env.is_gen_test {
|
||||||
|
expose_function_to_host_help_c_abi_generic(
|
||||||
|
env,
|
||||||
|
roc_function,
|
||||||
|
arguments,
|
||||||
|
&format!("{}_generic", c_function_name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let wrapper_return_type = if env.is_gen_test {
|
||||||
|
context
|
||||||
|
.struct_type(
|
||||||
|
&[
|
||||||
|
context.i64_type().into(),
|
||||||
|
roc_function.get_type().get_return_type().unwrap(),
|
||||||
|
],
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
roc_function.get_type().get_return_type().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena);
|
||||||
|
for layout in arguments {
|
||||||
|
cc_argument_types.push(to_cc_type(env, layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 1: turn `f : a,b,c -> d` into `f : a,b,c, &d -> {}` if the C abi demands it
|
||||||
|
let mut argument_types = cc_argument_types;
|
||||||
|
let return_type = wrapper_return_type;
|
||||||
|
|
||||||
|
let cc_return = to_cc_return(env, &return_layout);
|
||||||
|
|
||||||
|
let c_function_type = match cc_return {
|
||||||
|
CCReturn::Void => env.context.void_type().fn_type(&argument_types, false),
|
||||||
|
CCReturn::Return if !env.is_gen_test => return_type.fn_type(&argument_types, false),
|
||||||
|
_ => {
|
||||||
|
let output_type = return_type.ptr_type(AddressSpace::Generic);
|
||||||
|
argument_types.push(output_type.into());
|
||||||
|
env.context.void_type().fn_type(&argument_types, false)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let c_function = add_func(
|
||||||
|
env.module,
|
||||||
|
c_function_name,
|
||||||
|
c_function_type,
|
||||||
|
Linkage::External,
|
||||||
|
C_CALL_CONV,
|
||||||
|
);
|
||||||
|
|
||||||
|
let subprogram = env.new_subprogram(c_function_name);
|
||||||
|
c_function.set_subprogram(subprogram);
|
||||||
|
|
||||||
|
// STEP 2: build the exposed function's body
|
||||||
|
let builder = env.builder;
|
||||||
|
let context = env.context;
|
||||||
|
|
||||||
|
let entry = context.append_basic_block(c_function, "entry");
|
||||||
|
|
||||||
|
builder.position_at_end(entry);
|
||||||
|
|
||||||
|
debug_info_init!(env, c_function);
|
||||||
|
|
||||||
|
// drop the final argument, which is the pointer we write the result into
|
||||||
|
let args_vector = c_function.get_params();
|
||||||
|
let mut args = args_vector.as_slice();
|
||||||
|
let args_length = args.len();
|
||||||
|
|
||||||
|
if let CCReturn::ByPointer = cc_return {
|
||||||
|
args = &args[..args.len() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut arguments_for_call = Vec::with_capacity_in(args.len(), env.arena);
|
||||||
|
|
||||||
|
let it = args.iter().zip(roc_function.get_type().get_param_types());
|
||||||
|
for (arg, fastcc_type) in it {
|
||||||
|
let arg_type = arg.get_type();
|
||||||
|
if arg_type == fastcc_type {
|
||||||
|
// the C and Fast calling conventions agree
|
||||||
|
arguments_for_call.push(*arg);
|
||||||
|
} else {
|
||||||
|
let cast = complex_bitcast_check_size(env, *arg, fastcc_type, "to_fastcc_type");
|
||||||
|
arguments_for_call.push(cast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let arguments_for_call = &arguments_for_call.into_bump_slice();
|
||||||
|
|
||||||
|
debug_assert_eq!(args.len(), roc_function.get_params().len());
|
||||||
|
|
||||||
|
let call_result = {
|
||||||
|
if env.is_gen_test {
|
||||||
|
let roc_wrapper_function = make_exception_catcher(env, roc_function);
|
||||||
|
debug_assert_eq!(
|
||||||
|
arguments_for_call.len(),
|
||||||
|
roc_wrapper_function.get_params().len()
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.position_at_end(entry);
|
||||||
|
|
||||||
|
let call_wrapped = builder.build_call(
|
||||||
|
roc_wrapper_function,
|
||||||
|
arguments_for_call,
|
||||||
|
"call_wrapped_function",
|
||||||
|
);
|
||||||
|
call_wrapped.set_call_convention(FAST_CALL_CONV);
|
||||||
|
|
||||||
|
call_wrapped.try_as_basic_value().left().unwrap()
|
||||||
|
} else {
|
||||||
|
let call_unwrapped =
|
||||||
|
builder.build_call(roc_function, arguments_for_call, "call_unwrapped_function");
|
||||||
|
call_unwrapped.set_call_convention(FAST_CALL_CONV);
|
||||||
|
|
||||||
|
let call_unwrapped_result = call_unwrapped.try_as_basic_value().left().unwrap();
|
||||||
|
|
||||||
|
// make_good_roc_result(env, call_unwrapped_result)
|
||||||
|
call_unwrapped_result
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match cc_return {
|
||||||
|
CCReturn::Void => {
|
||||||
|
// TODO return empty struct here?
|
||||||
|
builder.build_return(None);
|
||||||
|
}
|
||||||
|
CCReturn::Return if !env.is_gen_test => {
|
||||||
|
builder.build_return(Some(&call_result));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let output_arg_index = args_length - 1;
|
||||||
|
|
||||||
|
let output_arg = c_function
|
||||||
|
.get_nth_param(output_arg_index as u32)
|
||||||
|
.unwrap()
|
||||||
|
.into_pointer_value();
|
||||||
|
|
||||||
|
builder.build_store(output_arg, call_result);
|
||||||
|
builder.build_return(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// STEP 3: build a {} -> u64 function that gives the size of the return type
|
// STEP 3: build a {} -> u64 function that gives the size of the return type
|
||||||
let size_function_type = env.context.i64_type().fn_type(&[], false);
|
let size_function_type = env.context.i64_type().fn_type(&[], false);
|
||||||
let size_function_name: String = format!("roc__{}_size", ident_string);
|
let size_function_name: String = format!("roc__{}_size", ident_string);
|
||||||
|
@ -3722,7 +3877,13 @@ fn build_proc_header<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
if env.exposed_to_host.contains(&symbol) {
|
if env.exposed_to_host.contains(&symbol) {
|
||||||
let arguments = Vec::from_iter_in(proc.args.iter().map(|(layout, _)| *layout), env.arena);
|
let arguments = Vec::from_iter_in(proc.args.iter().map(|(layout, _)| *layout), env.arena);
|
||||||
expose_function_to_host(env, symbol, fn_val, arguments.into_bump_slice());
|
expose_function_to_host(
|
||||||
|
env,
|
||||||
|
symbol,
|
||||||
|
fn_val,
|
||||||
|
arguments.into_bump_slice(),
|
||||||
|
proc.ret_layout,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn_val
|
fn_val
|
||||||
|
|
|
@ -23,7 +23,7 @@ comptime {
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
|
|
||||||
extern fn roc__mainForHost_1_exposed([*]u8) void;
|
extern fn roc__mainForHost_1_exposed_generic([*]u8) void;
|
||||||
extern fn roc__mainForHost_size() i64;
|
extern fn roc__mainForHost_size() i64;
|
||||||
extern fn roc__mainForHost_1_Fx_caller(*const u8, [*]u8, [*]u8) void;
|
extern fn roc__mainForHost_1_Fx_caller(*const u8, [*]u8, [*]u8) void;
|
||||||
extern fn roc__mainForHost_1_Fx_size() i64;
|
extern fn roc__mainForHost_1_Fx_size() i64;
|
||||||
|
@ -90,7 +90,7 @@ pub export fn main() callconv(.C) u8 {
|
||||||
var ts1: std.os.timespec = undefined;
|
var ts1: std.os.timespec = undefined;
|
||||||
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
||||||
|
|
||||||
roc__mainForHost_1_exposed(output);
|
roc__mainForHost_1_exposed_generic(output);
|
||||||
|
|
||||||
const closure_data_pointer = @ptrCast([*]u8, output);
|
const closure_data_pointer = @ptrCast([*]u8, output);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::ffi::CStr;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "roc__mainForHost_1_exposed"]
|
#[link_name = "roc__mainForHost_1_exposed"]
|
||||||
fn roc_main(output: *mut RocStr) -> ();
|
fn roc_main() -> RocStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -46,12 +46,8 @@ pub unsafe fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn rust_main() -> isize {
|
pub fn rust_main() -> isize {
|
||||||
let mut raw_output: MaybeUninit<RocStr> = MaybeUninit::uninit();
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
roc_main(raw_output.as_mut_ptr());
|
let roc_str = roc_main();
|
||||||
|
|
||||||
let roc_str = raw_output.assume_init();
|
|
||||||
|
|
||||||
let len = roc_str.len();
|
let len = roc_str.len();
|
||||||
let str_bytes = roc_str.get_bytes() as *const libc::c_void;
|
let str_bytes = roc_str.get_bytes() as *const libc::c_void;
|
||||||
|
|
|
@ -52,14 +52,11 @@ size_t roc_str_len(struct RocStr str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern void roc__mainForHost_1_exposed(struct RocStr *re);
|
extern struct RocStr roc__mainForHost_1_exposed();
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Make space for the Roc call result
|
|
||||||
struct RocStr call_result;
|
|
||||||
|
|
||||||
// Call Roc to populate call_result
|
// Call Roc to populate call_result
|
||||||
roc__mainForHost_1_exposed(&call_result);
|
struct RocStr call_result = roc__mainForHost_1_exposed();
|
||||||
|
|
||||||
// Determine str_len and the str_bytes pointer,
|
// Determine str_len and the str_bytes pointer,
|
||||||
// taking into account the small string optimization.
|
// taking into account the small string optimization.
|
||||||
|
|
|
@ -54,7 +54,7 @@ export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
|
|
||||||
extern fn roc__mainForHost_1_exposed(*RocStr) void;
|
extern fn roc__mainForHost_1_exposed() RocStr;
|
||||||
|
|
||||||
const Unit = extern struct {};
|
const Unit = extern struct {};
|
||||||
|
|
||||||
|
@ -62,15 +62,12 @@ pub fn main() u8 {
|
||||||
const stdout = std.io.getStdOut().writer();
|
const stdout = std.io.getStdOut().writer();
|
||||||
const stderr = std.io.getStdErr().writer();
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
|
||||||
// make space for the result
|
|
||||||
var callresult = RocStr.empty();
|
|
||||||
|
|
||||||
// start time
|
// start time
|
||||||
var ts1: std.os.timespec = undefined;
|
var ts1: std.os.timespec = undefined;
|
||||||
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
||||||
|
|
||||||
// actually call roc to populate the callresult
|
// actually call roc to populate the callresult
|
||||||
roc__mainForHost_1_exposed(&callresult);
|
var callresult = roc__mainForHost_1_exposed();
|
||||||
|
|
||||||
// stdout the result
|
// stdout the result
|
||||||
stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable;
|
stdout.print("{s}\n", .{callresult.asSlice()}) catch unreachable;
|
||||||
|
|
|
@ -20,7 +20,7 @@ comptime {
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
|
|
||||||
extern fn roc__mainForHost_1_exposed(RocList, *RocList) void;
|
extern fn roc__mainForHost_1_exposed(RocList) RocList;
|
||||||
|
|
||||||
const Align = extern struct { a: usize, b: usize };
|
const Align = extern struct { a: usize, b: usize };
|
||||||
extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) c_void;
|
extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) c_void;
|
||||||
|
@ -91,15 +91,12 @@ pub export fn main() u8 {
|
||||||
|
|
||||||
const roc_list = RocList{ .elements = numbers, .length = NUM_NUMS };
|
const roc_list = RocList{ .elements = numbers, .length = NUM_NUMS };
|
||||||
|
|
||||||
// make space for the result
|
|
||||||
var callresult: RocList = undefined;
|
|
||||||
|
|
||||||
// start time
|
// start time
|
||||||
var ts1: std.os.timespec = undefined;
|
var ts1: std.os.timespec = undefined;
|
||||||
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
std.os.clock_gettime(std.os.CLOCK_REALTIME, &ts1) catch unreachable;
|
||||||
|
|
||||||
// actually call roc to populate the callresult
|
// actually call roc to populate the callresult
|
||||||
roc__mainForHost_1_exposed(roc_list, &callresult);
|
var callresult = roc__mainForHost_1_exposed(roc_list);
|
||||||
|
|
||||||
// stdout the result
|
// stdout the result
|
||||||
const length = std.math.min(20, callresult.length);
|
const length = std.math.min(20, callresult.length);
|
||||||
|
|
|
@ -758,69 +758,6 @@ pub enum RocResult<Ok, Err> {
|
||||||
Ok(Ok),
|
Ok(Ok),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
type c_char = u8;
|
|
||||||
|
|
||||||
#[repr(u64)]
|
|
||||||
pub enum RocCallResult<T> {
|
|
||||||
Success(T),
|
|
||||||
Failure(*mut c_char),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Sized> From<RocCallResult<T>> for Result<T, &'static str> {
|
|
||||||
fn from(call_result: RocCallResult<T>) -> Self {
|
|
||||||
use RocCallResult::*;
|
|
||||||
|
|
||||||
match call_result {
|
|
||||||
Success(value) => Ok(value),
|
|
||||||
Failure(failure) => Err({
|
|
||||||
let msg = unsafe {
|
|
||||||
let mut null_byte_index = 0;
|
|
||||||
loop {
|
|
||||||
if *failure.offset(null_byte_index) == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
null_byte_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let bytes = core::slice::from_raw_parts(failure, null_byte_index as usize);
|
|
||||||
|
|
||||||
core::str::from_utf8_unchecked(bytes)
|
|
||||||
};
|
|
||||||
|
|
||||||
msg
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: Sized + Copy> From<&'a RocCallResult<T>> for Result<T, &'a str> {
|
|
||||||
fn from(call_result: &'a RocCallResult<T>) -> Self {
|
|
||||||
use RocCallResult::*;
|
|
||||||
|
|
||||||
match call_result {
|
|
||||||
Success(value) => Ok(*value),
|
|
||||||
Failure(failure) => Err({
|
|
||||||
let msg = unsafe {
|
|
||||||
let mut null_byte_index = 0;
|
|
||||||
loop {
|
|
||||||
if *failure.offset(null_byte_index) == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
null_byte_index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let bytes = core::slice::from_raw_parts(*failure, null_byte_index as usize);
|
|
||||||
|
|
||||||
core::str::from_utf8_unchecked(bytes)
|
|
||||||
};
|
|
||||||
|
|
||||||
msg
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct RocDec(pub i128);
|
pub struct RocDec(pub i128);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue