mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
repl helper codegen
This commit is contained in:
parent
45ce8e4da6
commit
5557fb7e34
8 changed files with 331 additions and 58 deletions
|
@ -1215,6 +1215,220 @@ fn test_helper_body<'a>(
|
|||
))
|
||||
}
|
||||
|
||||
pub fn repl_helper<'a>(
|
||||
env: &CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
main_proc: &Proc<'a>,
|
||||
) -> Proc<'a> {
|
||||
let name = LambdaName::no_niche(env.create_symbol(ident_ids, "test_main"));
|
||||
|
||||
// NOTE: main_proc's arguments are ignored here. There can be arguments if the input on the
|
||||
// repl is a lambda, but then we don't read the output of the evaluation anyway (and just print
|
||||
// the function type)
|
||||
|
||||
// tag: u64,
|
||||
// error_msg: *mut RocStr,
|
||||
// value: MaybeUninit<T>,
|
||||
let fields = [Layout::U64, Layout::U64, main_proc.ret_layout];
|
||||
let repr = LayoutRepr::Struct(env.arena.alloc(fields));
|
||||
let output_layout = layout_interner.insert_direct_no_semantic(repr);
|
||||
|
||||
let argument_layout = layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(output_layout));
|
||||
let argument_symbol = env.create_symbol(ident_ids, "output");
|
||||
let argument = (argument_layout, argument_symbol);
|
||||
|
||||
let args = &env.arena.alloc([argument])[..];
|
||||
|
||||
let body = repl_helper_body(
|
||||
env,
|
||||
ident_ids,
|
||||
layout_interner,
|
||||
main_proc,
|
||||
argument_symbol,
|
||||
output_layout,
|
||||
);
|
||||
|
||||
Proc {
|
||||
name,
|
||||
args,
|
||||
body,
|
||||
closure_data_layout: None,
|
||||
ret_layout: Layout::UNIT,
|
||||
is_self_recursive: main_proc.is_self_recursive,
|
||||
is_erased: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn repl_helper_body<'a>(
|
||||
env: &CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
main_proc: &Proc<'a>,
|
||||
output_symbol: Symbol,
|
||||
output_layout: InLayout<'a>,
|
||||
) -> Stmt<'a> {
|
||||
// let buffer = SetLongJmpBuffer
|
||||
let buffer_symbol = env.create_symbol(ident_ids, "buffer");
|
||||
let buffer_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::SetLongJmpBuffer,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: &[],
|
||||
});
|
||||
let buffer_stmt = |next| Stmt::Let(buffer_symbol, buffer_expr, Layout::U64, next);
|
||||
|
||||
let field_layouts = env.arena.alloc([Layout::U64, Layout::U64]);
|
||||
let ret_layout = layout_interner.insert_direct_no_semantic(LayoutRepr::Struct(field_layouts));
|
||||
|
||||
let setjmp_symbol = env.create_symbol(ident_ids, "setjmp");
|
||||
let setjmp_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::SetJmp,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: env.arena.alloc([buffer_symbol]),
|
||||
});
|
||||
let setjmp_stmt = |next| Stmt::Let(setjmp_symbol, setjmp_expr, ret_layout, next);
|
||||
|
||||
let is_longjmp_symbol = env.create_symbol(ident_ids, "is_longjmp");
|
||||
let is_longjmp_expr = Expr::StructAtIndex {
|
||||
index: 0,
|
||||
field_layouts,
|
||||
structure: setjmp_symbol,
|
||||
};
|
||||
let is_longjmp_stmt = |next| Stmt::Let(is_longjmp_symbol, is_longjmp_expr, Layout::U64, next);
|
||||
|
||||
let tag_symbol = env.create_symbol(ident_ids, "tag");
|
||||
let tag_expr = Expr::StructAtIndex {
|
||||
index: 1,
|
||||
field_layouts,
|
||||
structure: setjmp_symbol,
|
||||
};
|
||||
let tag_stmt = |next| Stmt::Let(tag_symbol, tag_expr, Layout::U64, next);
|
||||
|
||||
// normal path, no panics
|
||||
let if_zero_stmt = {
|
||||
let it = main_proc.args.iter().map(|(a, _)| *a);
|
||||
let arg_layouts = Vec::from_iter_in(it, env.arena).into_bump_slice();
|
||||
|
||||
let result_symbol = env.create_symbol(ident_ids, "result");
|
||||
let result_expr = Expr::Call(Call {
|
||||
call_type: CallType::ByName {
|
||||
name: main_proc.name,
|
||||
ret_layout: main_proc.ret_layout,
|
||||
arg_layouts,
|
||||
specialization_id: CallSpecId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: &[],
|
||||
});
|
||||
let result = |next| Stmt::Let(result_symbol, result_expr, main_proc.ret_layout, next);
|
||||
|
||||
let ok_tag_symbol = env.create_symbol(ident_ids, "ok_tag");
|
||||
let ok_tag_expr = Expr::Literal(Literal::Int((0i128).to_ne_bytes()));
|
||||
let ok_tag = |next| Stmt::Let(ok_tag_symbol, ok_tag_expr, Layout::U64, next);
|
||||
|
||||
let msg_ptr_symbol = env.create_symbol(ident_ids, "msg_ptr");
|
||||
let msg_ptr_expr = Expr::Literal(Literal::Int((0i128).to_ne_bytes()));
|
||||
let msg_ptr = |next| Stmt::Let(msg_ptr_symbol, msg_ptr_expr, Layout::U64, next);
|
||||
|
||||
// construct the record
|
||||
let result_symbol1 = env.create_symbol(ident_ids, "output_ok");
|
||||
let fields = [ok_tag_symbol, msg_ptr_symbol, result_symbol];
|
||||
let result_expr = Expr::Struct(env.arena.alloc(fields));
|
||||
let output = |next| Stmt::Let(result_symbol1, result_expr, output_layout, next);
|
||||
|
||||
let unit_symbol = env.create_symbol(ident_ids, "unit");
|
||||
let unit_expr = Expr::ptr_store(env.arena.alloc([output_symbol, result_symbol1]));
|
||||
let unit = |next| Stmt::Let(unit_symbol, unit_expr, Layout::UNIT, next);
|
||||
|
||||
let arena = env.arena;
|
||||
result(arena.alloc(
|
||||
//
|
||||
ok_tag(arena.alloc(
|
||||
//
|
||||
msg_ptr(arena.alloc(
|
||||
//
|
||||
output(arena.alloc(
|
||||
//
|
||||
unit(arena.alloc(
|
||||
//
|
||||
Stmt::Ret(unit_symbol),
|
||||
)),
|
||||
)),
|
||||
)),
|
||||
)),
|
||||
))
|
||||
};
|
||||
|
||||
// a longjmp/panic occurred
|
||||
let if_nonzero_stmt = {
|
||||
let alloca_symbol = env.create_symbol(ident_ids, "alloca");
|
||||
let alloca_expr = Expr::Alloca {
|
||||
element_layout: main_proc.ret_layout,
|
||||
initializer: None,
|
||||
};
|
||||
let alloca = |next| Stmt::Let(alloca_symbol, alloca_expr, Layout::U64, next);
|
||||
|
||||
let load_symbol = env.create_symbol(ident_ids, "load");
|
||||
let load_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::PtrLoad,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: env.arena.alloc([alloca_symbol]),
|
||||
});
|
||||
let load = |next| Stmt::Let(load_symbol, load_expr, main_proc.ret_layout, next);
|
||||
|
||||
// construct the record
|
||||
let result_symbol1 = env.create_symbol(ident_ids, "output_err");
|
||||
// is_longjmp_symbol is a pointer to the error message
|
||||
let fields = [tag_symbol, is_longjmp_symbol, load_symbol];
|
||||
let output_expr = Expr::Struct(env.arena.alloc(fields));
|
||||
let output = |next| Stmt::Let(result_symbol1, output_expr, output_layout, next);
|
||||
|
||||
let unit_symbol = env.create_symbol(ident_ids, "unit");
|
||||
let unit_expr = Expr::ptr_store(env.arena.alloc([output_symbol, result_symbol1]));
|
||||
let unit = |next| Stmt::Let(unit_symbol, unit_expr, Layout::UNIT, next);
|
||||
|
||||
let arena = env.arena;
|
||||
arena.alloc(alloca(arena.alloc(
|
||||
//
|
||||
load(arena.alloc(
|
||||
//
|
||||
output(arena.alloc(
|
||||
//
|
||||
unit(arena.alloc(
|
||||
//
|
||||
Stmt::Ret(unit_symbol),
|
||||
)),
|
||||
)),
|
||||
)),
|
||||
)))
|
||||
};
|
||||
|
||||
buffer_stmt(env.arena.alloc(
|
||||
//
|
||||
setjmp_stmt(env.arena.alloc(
|
||||
//
|
||||
is_longjmp_stmt(env.arena.alloc(
|
||||
//
|
||||
tag_stmt(env.arena.alloc(
|
||||
//
|
||||
switch_if_zero_else(
|
||||
env.arena,
|
||||
is_longjmp_symbol,
|
||||
Layout::UNIT,
|
||||
if_zero_stmt,
|
||||
if_nonzero_stmt,
|
||||
),
|
||||
)),
|
||||
)),
|
||||
)),
|
||||
))
|
||||
}
|
||||
|
||||
fn switch_if_zero_else<'a>(
|
||||
arena: &'a Bump,
|
||||
condition_symbol: Symbol,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue