use cel::common::ast::{CallExpr, Expr};
use ferricel_types::functions::RuntimeFunction;
use walrus::{InstrSeqBuilder, ValType, ir::InstrSeqId};
use crate::compiler::{
context::{CompilerContext, CompilerEnv},
expr::compile_expr,
};
pub fn compile_two_var_comprehension(
func_name: &str,
call_expr: &CallExpr,
body: &mut InstrSeqBuilder,
env: &CompilerEnv,
ctx: &CompilerContext,
module: &mut walrus::Module,
) -> Result<(), anyhow::Error> {
match func_name {
"exists" => compile_exists(call_expr, body, env, ctx, module),
"all" => compile_all(call_expr, body, env, ctx, module),
"existsOne" | "exists_one" => compile_exists_one(call_expr, body, env, ctx, module),
"transformList" => compile_transform_list(call_expr, body, env, ctx, module),
"transformMap" => compile_transform_map(call_expr, body, env, ctx, module),
"transformMapEntry" => compile_transform_map_entry(call_expr, body, env, ctx, module),
_ => anyhow::bail!("Unknown two-var comprehension macro: {func_name}"),
}
}
fn extract_var_names(
call_expr: &CallExpr,
macro_name: &str,
) -> Result<(String, String), anyhow::Error> {
let var1 = match &call_expr.args[0].expr {
Expr::Ident(name) => name.clone(),
_ => anyhow::bail!("{macro_name}: first argument must be a simple identifier"),
};
let var2 = match &call_expr.args[1].expr {
Expr::Ident(name) => name.clone(),
_ => anyhow::bail!("{macro_name}: second argument must be a simple identifier"),
};
Ok((var1, var2))
}
fn emit_loop_setup(
target: &cel::common::ast::Expr,
body: &mut InstrSeqBuilder,
env: &CompilerEnv,
ctx: &CompilerContext,
module: &mut walrus::Module,
) -> Result<
(
walrus::LocalId,
walrus::LocalId,
walrus::LocalId,
walrus::LocalId,
),
anyhow::Error,
> {
compile_expr(target, body, env, ctx, module)?;
let range_local = module.locals.add(ValType::I32);
body.local_set(range_local);
body.local_get(range_local);
body.call(env.get(RuntimeFunction::IterPrepare));
let prepared_local = module.locals.add(ValType::I32);
body.local_set(prepared_local);
body.local_get(prepared_local);
body.call(env.get(RuntimeFunction::ArrayLen));
let length_local = module.locals.add(ValType::I32);
body.local_set(length_local);
let index_local = module.locals.add(ValType::I32);
body.i32_const(0);
body.local_set(index_local);
Ok((range_local, prepared_local, length_local, index_local))
}
#[allow(clippy::too_many_arguments)]
fn emit_bind_iter_vars(
range_local: walrus::LocalId,
prepared_local: walrus::LocalId,
index_local: walrus::LocalId,
var1_name: &str,
var2_name: &str,
loop_body: &mut InstrSeqBuilder,
env: &CompilerEnv,
ctx: &CompilerContext,
module: &mut walrus::Module,
) -> CompilerContext {
loop_body.local_get(range_local);
loop_body.local_get(prepared_local);
loop_body.local_get(index_local);
loop_body.call(env.get(RuntimeFunction::IterVar1));
let var1_local = module.locals.add(ValType::I32);
loop_body.local_set(var1_local);
loop_body.local_get(range_local);
loop_body.local_get(prepared_local);
loop_body.local_get(index_local);
loop_body.call(env.get(RuntimeFunction::IterVar2));
let var2_local = module.locals.add(ValType::I32);
loop_body.local_set(var2_local);
ctx.with_local(var1_name.to_string(), var1_local)
.with_local(var2_name.to_string(), var2_local)
}
fn emit_loop_exit_check(
index_local: walrus::LocalId,
length_local: walrus::LocalId,
exit_block_id: InstrSeqId,
loop_body: &mut InstrSeqBuilder,
) {
loop_body.local_get(index_local);
loop_body.local_get(length_local);
loop_body.binop(walrus::ir::BinaryOp::I32GeU);
loop_body.instr(walrus::ir::BrIf {
block: exit_block_id,
});
}
fn emit_index_increment_and_loop(
index_local: walrus::LocalId,
continue_loop_id: InstrSeqId,
loop_body: &mut InstrSeqBuilder,
) {
loop_body.local_get(index_local);
loop_body.i32_const(1);
loop_body.binop(walrus::ir::BinaryOp::I32Add);
loop_body.local_set(index_local);
loop_body.instr(walrus::ir::Br {
block: continue_loop_id,
});
}
fn compile_exists(
call_expr: &CallExpr,
body: &mut InstrSeqBuilder,
env: &CompilerEnv,
ctx: &CompilerContext,
module: &mut walrus::Module,
) -> Result<(), anyhow::Error> {
if call_expr.args.len() != 3 {
anyhow::bail!(
"exists() two-var form expects 3 arguments (var1, var2, pred), got {}",
call_expr.args.len()
);
}
let target = call_expr
.target
.as_ref()
.ok_or_else(|| anyhow::anyhow!("exists() requires a receiver"))?;
let (var1, var2) = extract_var_names(call_expr, "exists")?;
let pred_expr = &call_expr.args[2].expr;
let (range_local, prepared_local, length_local, index_local) =
emit_loop_setup(&target.expr, body, env, ctx, module)?;
body.i64_const(0);
body.call(env.get(RuntimeFunction::CreateBool));
let accu_local = module.locals.add(ValType::I32);
body.local_set(accu_local);
let exit_block = body.dangling_instr_seq(None);
let exit_block_id = exit_block.id();
let continue_loop = body.dangling_instr_seq(None);
let continue_loop_id = continue_loop.id();
body.instr(walrus::ir::Block { seq: exit_block_id });
body.instr_seq(exit_block_id).instr(walrus::ir::Loop {
seq: continue_loop_id,
});
let mut lb = body.instr_seq(continue_loop_id);
emit_loop_exit_check(index_local, length_local, exit_block_id, &mut lb);
let inner_ctx = emit_bind_iter_vars(
range_local,
prepared_local,
index_local,
&var1,
&var2,
&mut lb,
env,
ctx,
module,
);
lb.local_get(accu_local);
compile_expr(pred_expr, &mut lb, env, &inner_ctx, module)?;
lb.call(env.get(RuntimeFunction::BoolOr));
lb.local_set(accu_local);
lb.local_get(accu_local);
lb.call(env.get(RuntimeFunction::IsStrictlyTrue));
lb.instr(walrus::ir::BrIf {
block: exit_block_id,
});
emit_index_increment_and_loop(index_local, continue_loop_id, &mut lb);
body.local_get(accu_local);
Ok(())
}
fn compile_all(
call_expr: &CallExpr,
body: &mut InstrSeqBuilder,
env: &CompilerEnv,
ctx: &CompilerContext,
module: &mut walrus::Module,
) -> Result<(), anyhow::Error> {
if call_expr.args.len() != 3 {
anyhow::bail!(
"all() two-var form expects 3 arguments (var1, var2, pred), got {}",
call_expr.args.len()
);
}
let target = call_expr
.target
.as_ref()
.ok_or_else(|| anyhow::anyhow!("all() requires a receiver"))?;
let (var1, var2) = extract_var_names(call_expr, "all")?;
let pred_expr = &call_expr.args[2].expr;
let (range_local, prepared_local, length_local, index_local) =
emit_loop_setup(&target.expr, body, env, ctx, module)?;
body.i64_const(1);
body.call(env.get(RuntimeFunction::CreateBool));
let accu_local = module.locals.add(ValType::I32);
body.local_set(accu_local);
let exit_block = body.dangling_instr_seq(None);
let exit_block_id = exit_block.id();
let continue_loop = body.dangling_instr_seq(None);
let continue_loop_id = continue_loop.id();
body.instr(walrus::ir::Block { seq: exit_block_id });
body.instr_seq(exit_block_id).instr(walrus::ir::Loop {
seq: continue_loop_id,
});
let mut lb = body.instr_seq(continue_loop_id);
emit_loop_exit_check(index_local, length_local, exit_block_id, &mut lb);
let inner_ctx = emit_bind_iter_vars(
range_local,
prepared_local,
index_local,
&var1,
&var2,
&mut lb,
env,
ctx,
module,
);
lb.local_get(accu_local);
compile_expr(pred_expr, &mut lb, env, &inner_ctx, module)?;
lb.call(env.get(RuntimeFunction::BoolAnd));
lb.local_set(accu_local);
lb.local_get(accu_local);
lb.call(env.get(RuntimeFunction::IsStrictlyFalse));
lb.instr(walrus::ir::BrIf {
block: exit_block_id,
});
emit_index_increment_and_loop(index_local, continue_loop_id, &mut lb);
body.local_get(accu_local);
Ok(())
}
fn compile_exists_one(
call_expr: &CallExpr,
body: &mut InstrSeqBuilder,
env: &CompilerEnv,
ctx: &CompilerContext,
module: &mut walrus::Module,
) -> Result<(), anyhow::Error> {
if call_expr.args.len() != 3 {
anyhow::bail!(
"existsOne() two-var form expects 3 arguments (var1, var2, pred), got {}",
call_expr.args.len()
);
}
let target = call_expr
.target
.as_ref()
.ok_or_else(|| anyhow::anyhow!("existsOne() requires a receiver"))?;
let (var1, var2) = extract_var_names(call_expr, "existsOne")?;
let pred_expr = &call_expr.args[2].expr;
let (range_local, prepared_local, length_local, index_local) =
emit_loop_setup(&target.expr, body, env, ctx, module)?;
body.i64_const(0);
body.call(env.get(RuntimeFunction::CreateInt));
let accu_local = module.locals.add(ValType::I32);
body.local_set(accu_local);
let exit_block = body.dangling_instr_seq(None);
let exit_block_id = exit_block.id();
let continue_loop = body.dangling_instr_seq(None);
let continue_loop_id = continue_loop.id();
body.instr(walrus::ir::Block { seq: exit_block_id });
body.instr_seq(exit_block_id).instr(walrus::ir::Loop {
seq: continue_loop_id,
});
let mut lb = body.instr_seq(continue_loop_id);
emit_loop_exit_check(index_local, length_local, exit_block_id, &mut lb);
let inner_ctx = emit_bind_iter_vars(
range_local,
prepared_local,
index_local,
&var1,
&var2,
&mut lb,
env,
ctx,
module,
);
lb.local_get(accu_local);
compile_expr(pred_expr, &mut lb, env, &inner_ctx, module)?;
lb.call(env.get(RuntimeFunction::CondInc));
lb.local_set(accu_local);
emit_index_increment_and_loop(index_local, continue_loop_id, &mut lb);
body.local_get(accu_local);
body.i64_const(1);
body.call(env.get(RuntimeFunction::CreateInt));
body.call(env.get(RuntimeFunction::ValueEq));
Ok(())
}
fn compile_transform_list(
call_expr: &CallExpr,
body: &mut InstrSeqBuilder,
env: &CompilerEnv,
ctx: &CompilerContext,
module: &mut walrus::Module,
) -> Result<(), anyhow::Error> {
let nargs = call_expr.args.len();
if nargs != 3 && nargs != 4 {
anyhow::bail!("transformList() expects 3 or 4 arguments, got {nargs}");
}
let target = call_expr
.target
.as_ref()
.ok_or_else(|| anyhow::anyhow!("transformList() requires a receiver"))?;
let (var1, var2) = extract_var_names(call_expr, "transformList")?;
let (filter_expr, transform_expr) = if nargs == 4 {
(Some(&call_expr.args[2].expr), &call_expr.args[3].expr)
} else {
(None, &call_expr.args[2].expr)
};
let (range_local, prepared_local, length_local, index_local) =
emit_loop_setup(&target.expr, body, env, ctx, module)?;
body.call(env.get(RuntimeFunction::CreateArray));
let accu_local = module.locals.add(ValType::I32);
body.local_set(accu_local);
let exit_block = body.dangling_instr_seq(None);
let exit_block_id = exit_block.id();
let continue_loop = body.dangling_instr_seq(None);
let continue_loop_id = continue_loop.id();
body.instr(walrus::ir::Block { seq: exit_block_id });
body.instr_seq(exit_block_id).instr(walrus::ir::Loop {
seq: continue_loop_id,
});
let mut lb = body.instr_seq(continue_loop_id);
emit_loop_exit_check(index_local, length_local, exit_block_id, &mut lb);
let inner_ctx = emit_bind_iter_vars(
range_local,
prepared_local,
index_local,
&var1,
&var2,
&mut lb,
env,
ctx,
module,
);
let inner_ctx = inner_ctx.with_local("@accu".to_string(), accu_local);
let result_local = module.locals.add(ValType::I32);
if let Some(filt) = filter_expr {
compile_expr(filt, &mut lb, env, &inner_ctx, module)?;
lb.local_set(result_local);
lb.local_get(result_local);
lb.call(env.get(RuntimeFunction::IsError));
let ferr_then = lb.dangling_instr_seq(None);
let ferr_then_id = ferr_then.id();
let ferr_else = lb.dangling_instr_seq(None);
let ferr_else_id = ferr_else.id();
{
let mut t = lb.instr_seq(ferr_then_id);
t.local_get(result_local);
t.local_set(accu_local);
t.instr(walrus::ir::Br {
block: exit_block_id,
});
}
{
let mut e = lb.instr_seq(ferr_else_id);
e.local_get(result_local);
e.call(env.get(RuntimeFunction::IsStrictlyTrue));
let then_seq = e.dangling_instr_seq(None);
let then_id = then_seq.id();
let else_seq = e.dangling_instr_seq(None);
let else_id = else_seq.id();
{
let mut then_body = e.instr_seq(then_id);
compile_expr(transform_expr, &mut then_body, env, &inner_ctx, module)?;
then_body.local_set(result_local);
then_body.local_get(result_local);
then_body.call(env.get(RuntimeFunction::IsError));
let terr_then = then_body.dangling_instr_seq(None);
let terr_then_id = terr_then.id();
let terr_else = then_body.dangling_instr_seq(None);
let terr_else_id = terr_else.id();
{
let mut tt = then_body.instr_seq(terr_then_id);
tt.local_get(result_local);
tt.local_set(accu_local);
tt.instr(walrus::ir::Br {
block: exit_block_id,
});
}
{
let mut te = then_body.instr_seq(terr_else_id);
te.local_get(accu_local);
te.local_get(result_local);
te.call(env.get(RuntimeFunction::ArrayPush));
}
then_body.instr(walrus::ir::IfElse {
consequent: terr_then_id,
alternative: terr_else_id,
});
}
{
let _ = e.instr_seq(else_id); }
e.instr(walrus::ir::IfElse {
consequent: then_id,
alternative: else_id,
});
}
lb.instr(walrus::ir::IfElse {
consequent: ferr_then_id,
alternative: ferr_else_id,
});
} else {
compile_expr(transform_expr, &mut lb, env, &inner_ctx, module)?;
lb.local_set(result_local);
lb.local_get(result_local);
lb.call(env.get(RuntimeFunction::IsError));
let err_then = lb.dangling_instr_seq(None);
let err_then_id = err_then.id();
let err_else = lb.dangling_instr_seq(None);
let err_else_id = err_else.id();
{
let mut t = lb.instr_seq(err_then_id);
t.local_get(result_local);
t.local_set(accu_local);
t.instr(walrus::ir::Br {
block: exit_block_id,
});
}
{
let mut e = lb.instr_seq(err_else_id);
e.local_get(accu_local);
e.local_get(result_local);
e.call(env.get(RuntimeFunction::ArrayPush));
}
lb.instr(walrus::ir::IfElse {
consequent: err_then_id,
alternative: err_else_id,
});
}
emit_index_increment_and_loop(index_local, continue_loop_id, &mut lb);
body.local_get(accu_local);
Ok(())
}
fn compile_transform_map(
call_expr: &CallExpr,
body: &mut InstrSeqBuilder,
env: &CompilerEnv,
ctx: &CompilerContext,
module: &mut walrus::Module,
) -> Result<(), anyhow::Error> {
let nargs = call_expr.args.len();
if nargs != 3 && nargs != 4 {
anyhow::bail!("transformMap() expects 3 or 4 arguments, got {nargs}");
}
let target = call_expr
.target
.as_ref()
.ok_or_else(|| anyhow::anyhow!("transformMap() requires a receiver"))?;
let (var1, var2) = extract_var_names(call_expr, "transformMap")?;
let (filter_expr, transform_expr) = if nargs == 4 {
(Some(&call_expr.args[2].expr), &call_expr.args[3].expr)
} else {
(None, &call_expr.args[2].expr)
};
let (range_local, prepared_local, length_local, index_local) =
emit_loop_setup(&target.expr, body, env, ctx, module)?;
body.call(env.get(RuntimeFunction::CreateMap));
let accu_local = module.locals.add(ValType::I32);
body.local_set(accu_local);
let exit_block = body.dangling_instr_seq(None);
let exit_block_id = exit_block.id();
let continue_loop = body.dangling_instr_seq(None);
let continue_loop_id = continue_loop.id();
body.instr(walrus::ir::Block { seq: exit_block_id });
body.instr_seq(exit_block_id).instr(walrus::ir::Loop {
seq: continue_loop_id,
});
let mut lb = body.instr_seq(continue_loop_id);
emit_loop_exit_check(index_local, length_local, exit_block_id, &mut lb);
let inner_ctx = emit_bind_iter_vars(
range_local,
prepared_local,
index_local,
&var1,
&var2,
&mut lb,
env,
ctx,
module,
);
let inner_ctx = inner_ctx.with_local("@accu".to_string(), accu_local);
let result_local = module.locals.add(ValType::I32);
if let Some(filt) = filter_expr {
compile_expr(filt, &mut lb, env, &inner_ctx, module)?;
lb.local_set(result_local);
lb.local_get(result_local);
lb.call(env.get(RuntimeFunction::IsError));
let ferr_then = lb.dangling_instr_seq(None);
let ferr_then_id = ferr_then.id();
let ferr_else = lb.dangling_instr_seq(None);
let ferr_else_id = ferr_else.id();
{
let mut t = lb.instr_seq(ferr_then_id);
t.local_get(result_local);
t.local_set(accu_local);
t.instr(walrus::ir::Br {
block: exit_block_id,
});
}
{
let mut e = lb.instr_seq(ferr_else_id);
e.local_get(result_local);
e.call(env.get(RuntimeFunction::IsStrictlyTrue));
let then_seq = e.dangling_instr_seq(None);
let then_id = then_seq.id();
let else_seq = e.dangling_instr_seq(None);
let else_id = else_seq.id();
{
let mut then_body = e.instr_seq(then_id);
compile_expr(transform_expr, &mut then_body, env, &inner_ctx, module)?;
then_body.local_set(result_local);
then_body.local_get(result_local);
then_body.call(env.get(RuntimeFunction::IsError));
let terr_then = then_body.dangling_instr_seq(None);
let terr_then_id = terr_then.id();
let terr_else = then_body.dangling_instr_seq(None);
let terr_else_id = terr_else.id();
{
let mut tt = then_body.instr_seq(terr_then_id);
tt.local_get(result_local);
tt.local_set(accu_local);
tt.instr(walrus::ir::Br {
block: exit_block_id,
});
}
{
let mut te = then_body.instr_seq(terr_else_id);
te.local_get(accu_local);
compile_expr(&Expr::Ident(var1.clone()), &mut te, env, &inner_ctx, module)?;
te.local_get(result_local);
te.call(env.get(RuntimeFunction::MapInsert));
}
then_body.instr(walrus::ir::IfElse {
consequent: terr_then_id,
alternative: terr_else_id,
});
}
{
let _ = e.instr_seq(else_id);
}
e.instr(walrus::ir::IfElse {
consequent: then_id,
alternative: else_id,
});
}
lb.instr(walrus::ir::IfElse {
consequent: ferr_then_id,
alternative: ferr_else_id,
});
} else {
compile_expr(transform_expr, &mut lb, env, &inner_ctx, module)?;
lb.local_set(result_local);
lb.local_get(result_local);
lb.call(env.get(RuntimeFunction::IsError));
let err_then = lb.dangling_instr_seq(None);
let err_then_id = err_then.id();
let err_else = lb.dangling_instr_seq(None);
let err_else_id = err_else.id();
{
let mut t = lb.instr_seq(err_then_id);
t.local_get(result_local);
t.local_set(accu_local);
t.instr(walrus::ir::Br {
block: exit_block_id,
});
}
{
let mut e = lb.instr_seq(err_else_id);
e.local_get(accu_local);
compile_expr(&Expr::Ident(var1.clone()), &mut e, env, &inner_ctx, module)?;
e.local_get(result_local);
e.call(env.get(RuntimeFunction::MapInsert));
}
lb.instr(walrus::ir::IfElse {
consequent: err_then_id,
alternative: err_else_id,
});
}
emit_index_increment_and_loop(index_local, continue_loop_id, &mut lb);
body.local_get(accu_local);
Ok(())
}
fn compile_transform_map_entry(
call_expr: &CallExpr,
body: &mut InstrSeqBuilder,
env: &CompilerEnv,
ctx: &CompilerContext,
module: &mut walrus::Module,
) -> Result<(), anyhow::Error> {
let nargs = call_expr.args.len();
if nargs != 3 && nargs != 4 {
anyhow::bail!("transformMapEntry() expects 3 or 4 arguments, got {nargs}");
}
let target = call_expr
.target
.as_ref()
.ok_or_else(|| anyhow::anyhow!("transformMapEntry() requires a receiver"))?;
let (var1, var2) = extract_var_names(call_expr, "transformMapEntry")?;
let (filter_expr, entry_expr) = if nargs == 4 {
(Some(&call_expr.args[2].expr), &call_expr.args[3].expr)
} else {
(None, &call_expr.args[2].expr)
};
let (range_local, prepared_local, length_local, index_local) =
emit_loop_setup(&target.expr, body, env, ctx, module)?;
body.call(env.get(RuntimeFunction::CreateMap));
let accu_local = module.locals.add(walrus::ValType::I32);
body.local_set(accu_local);
let exit_block = body.dangling_instr_seq(None);
let exit_block_id = exit_block.id();
let continue_loop = body.dangling_instr_seq(None);
let continue_loop_id = continue_loop.id();
body.instr(walrus::ir::Block { seq: exit_block_id });
body.instr_seq(exit_block_id).instr(walrus::ir::Loop {
seq: continue_loop_id,
});
let mut lb = body.instr_seq(continue_loop_id);
emit_loop_exit_check(index_local, length_local, exit_block_id, &mut lb);
let inner_ctx = emit_bind_iter_vars(
range_local,
prepared_local,
index_local,
&var1,
&var2,
&mut lb,
env,
ctx,
module,
);
let inner_ctx = inner_ctx.with_local("@accu".to_string(), accu_local);
let result_local = module.locals.add(walrus::ValType::I32);
macro_rules! emit_insert_entry {
($seq:expr) => {{
let seq: &mut InstrSeqBuilder = $seq;
compile_expr(entry_expr, seq, env, &inner_ctx, module)?;
seq.local_set(result_local);
seq.local_get(result_local);
seq.call(env.get(RuntimeFunction::IsError));
let eerr_then = seq.dangling_instr_seq(None);
let eerr_then_id = eerr_then.id();
let eerr_else = seq.dangling_instr_seq(None);
let eerr_else_id = eerr_else.id();
{
let mut t = seq.instr_seq(eerr_then_id);
t.local_get(result_local);
t.local_set(accu_local);
t.instr(walrus::ir::Br {
block: exit_block_id,
});
}
{
let mut e = seq.instr_seq(eerr_else_id);
e.local_get(accu_local);
e.local_get(result_local);
e.call(env.get(RuntimeFunction::MapInsertEntry));
e.local_set(accu_local);
e.local_get(accu_local);
e.call(env.get(RuntimeFunction::IsError));
e.instr(walrus::ir::BrIf {
block: exit_block_id,
});
}
seq.instr(walrus::ir::IfElse {
consequent: eerr_then_id,
alternative: eerr_else_id,
});
}};
}
if let Some(filt) = filter_expr {
compile_expr(filt, &mut lb, env, &inner_ctx, module)?;
lb.local_set(result_local);
lb.local_get(result_local);
lb.call(env.get(RuntimeFunction::IsError));
let ferr_then = lb.dangling_instr_seq(None);
let ferr_then_id = ferr_then.id();
let ferr_else = lb.dangling_instr_seq(None);
let ferr_else_id = ferr_else.id();
{
let mut t = lb.instr_seq(ferr_then_id);
t.local_get(result_local);
t.local_set(accu_local);
t.instr(walrus::ir::Br {
block: exit_block_id,
});
}
{
let mut e = lb.instr_seq(ferr_else_id);
e.local_get(result_local);
e.call(env.get(RuntimeFunction::IsStrictlyTrue));
let then_seq = e.dangling_instr_seq(None);
let then_id = then_seq.id();
let else_seq = e.dangling_instr_seq(None);
let else_id = else_seq.id();
{
let mut then_body = e.instr_seq(then_id);
emit_insert_entry!(&mut then_body);
}
{
let _ = e.instr_seq(else_id);
}
e.instr(walrus::ir::IfElse {
consequent: then_id,
alternative: else_id,
});
}
lb.instr(walrus::ir::IfElse {
consequent: ferr_then_id,
alternative: ferr_else_id,
});
} else {
emit_insert_entry!(&mut lb);
}
emit_index_increment_and_loop(index_local, continue_loop_id, &mut lb);
body.local_get(accu_local);
Ok(())
}