repl helper codegen

This commit is contained in:
Folkert 2023-09-13 12:49:25 +02:00
parent 45ce8e4da6
commit 5557fb7e34
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
8 changed files with 331 additions and 58 deletions

View file

@ -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,