conditionally unwrapping while loops
This commit is contained in:
+106
-97
@@ -924,6 +924,101 @@ lower_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
return last
|
||||
}
|
||||
|
||||
lower_conditional_unwrap_header :: proc(
|
||||
state: ^State,
|
||||
statement: hir.Stmt,
|
||||
success_lbl, false_lbl: i64,
|
||||
) {
|
||||
for unwrap in statement.unwraps {
|
||||
optional := lower_expr(state, unwrap.expr)
|
||||
present := append_instruction(state, ir.Instruction{
|
||||
op=.Optional_Is_Some,
|
||||
span=statement.span,
|
||||
type=types.BOOL,
|
||||
target=ir.INVALID_REF,
|
||||
a=optional,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
next_lbl := fresh_label(state)
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Cond_Br,
|
||||
span=statement.span,
|
||||
type=types.VOID,
|
||||
a=present,
|
||||
integer=next_lbl,
|
||||
target=ir.Ref(u32(false_lbl)),
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label,
|
||||
span=statement.span,
|
||||
type=types.VOID,
|
||||
integer=next_lbl,
|
||||
target=ir.INVALID_REF,
|
||||
a=ir.INVALID_INSTRUCTION,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
if unwrap.local != hir.INVALID_LOCAL && int(unwrap.local) < len(state.func_locals) {
|
||||
local := state.func_locals[unwrap.local]
|
||||
slot := append_instruction(state, ir.Instruction{
|
||||
op=.Alloca,
|
||||
span=statement.span,
|
||||
type=local.type,
|
||||
target=ir.local_ref(ir.Local_Id(unwrap.local)),
|
||||
a=ir.INVALID_INSTRUCTION,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
state.local_slots[unwrap.local] = slot
|
||||
inner := append_instruction(state, ir.Instruction{
|
||||
op=.Optional_Value,
|
||||
span=statement.span,
|
||||
type=local.type,
|
||||
target=ir.INVALID_REF,
|
||||
a=optional,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Store,
|
||||
span=statement.span,
|
||||
type=local.type,
|
||||
target=ir.INVALID_REF,
|
||||
a=slot,
|
||||
b=inner,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
}
|
||||
if statement.guard != hir.INVALID_EXPR {
|
||||
guard := lower_expr(state, statement.guard)
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Cond_Br,
|
||||
span=statement.span,
|
||||
type=types.VOID,
|
||||
a=guard,
|
||||
integer=success_lbl,
|
||||
target=ir.Ref(u32(false_lbl)),
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
} else {
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Br,
|
||||
span=statement.span,
|
||||
type=types.VOID,
|
||||
integer=success_lbl,
|
||||
target=ir.INVALID_REF,
|
||||
a=ir.INVALID_INSTRUCTION,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
lower_statements :: proc(state: ^State, statements: []hir.Stmt_Id) {
|
||||
hir_module := state.hir_module
|
||||
for statement_id in statements {
|
||||
@@ -1136,97 +1231,7 @@ lower_statements :: proc(state: ^State, statements: []hir.Stmt_Id) {
|
||||
false_target := else_lbl if has_else else merge_lbl
|
||||
|
||||
if len(statement.unwraps) > 0 {
|
||||
// Evaluate each optional exactly once, entering the next operand only
|
||||
// after the previous one is present. Capture storage is initialized in
|
||||
// these success blocks so the optional guard can use every binding.
|
||||
for unwrap in statement.unwraps {
|
||||
optional := lower_expr(state, unwrap.expr)
|
||||
present := append_instruction(state, ir.Instruction{
|
||||
op=.Optional_Is_Some,
|
||||
span=statement.span,
|
||||
type=types.BOOL,
|
||||
target=ir.INVALID_REF,
|
||||
a=optional,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
success_lbl := fresh_label(state)
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Cond_Br,
|
||||
span=statement.span,
|
||||
type=types.VOID,
|
||||
a=present,
|
||||
integer=success_lbl,
|
||||
target=ir.Ref(u32(false_target)),
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label,
|
||||
span=statement.span,
|
||||
type=types.VOID,
|
||||
integer=success_lbl,
|
||||
target=ir.INVALID_REF,
|
||||
a=ir.INVALID_INSTRUCTION,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
if unwrap.local != hir.INVALID_LOCAL && int(unwrap.local) < len(state.func_locals) {
|
||||
local := state.func_locals[unwrap.local]
|
||||
slot := append_instruction(state, ir.Instruction{
|
||||
op=.Alloca,
|
||||
span=statement.span,
|
||||
type=local.type,
|
||||
target=ir.local_ref(ir.Local_Id(unwrap.local)),
|
||||
a=ir.INVALID_INSTRUCTION,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
state.local_slots[unwrap.local] = slot
|
||||
inner := append_instruction(state, ir.Instruction{
|
||||
op=.Optional_Value,
|
||||
span=statement.span,
|
||||
type=local.type,
|
||||
target=ir.INVALID_REF,
|
||||
a=optional,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Store,
|
||||
span=statement.span,
|
||||
type=local.type,
|
||||
target=ir.INVALID_REF,
|
||||
a=slot,
|
||||
b=inner,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
}
|
||||
if statement.guard != hir.INVALID_EXPR {
|
||||
guard := lower_expr(state, statement.guard)
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Cond_Br,
|
||||
span=statement.span,
|
||||
type=types.VOID,
|
||||
a=guard,
|
||||
integer=then_lbl,
|
||||
target=ir.Ref(u32(false_target)),
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
} else {
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Br,
|
||||
span=statement.span,
|
||||
type=types.VOID,
|
||||
integer=then_lbl,
|
||||
target=ir.INVALID_REF,
|
||||
a=ir.INVALID_INSTRUCTION,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
lower_conditional_unwrap_header(state, statement, then_lbl, false_target)
|
||||
} else {
|
||||
cond := lower_expr(state, statement.expr)
|
||||
append_instruction(state, ir.Instruction{
|
||||
@@ -1282,12 +1287,16 @@ lower_statements :: proc(state: ^State, statements: []hir.Stmt_Id) {
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
condition := lower_expr(state, statement.expr)
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Cond_Br, span=statement.span, type=types.VOID,
|
||||
a=condition, integer=body_lbl, target=ir.Ref(u32(exit_lbl)),
|
||||
b=ir.INVALID_INSTRUCTION, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
if len(statement.unwraps) > 0 {
|
||||
lower_conditional_unwrap_header(state, statement, body_lbl, exit_lbl)
|
||||
} else {
|
||||
condition := lower_expr(state, statement.expr)
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Cond_Br, span=statement.span, type=types.VOID,
|
||||
a=condition, integer=body_lbl, target=ir.Ref(u32(exit_lbl)),
|
||||
b=ir.INVALID_INSTRUCTION, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label, span=statement.span, type=types.VOID, integer=body_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
|
||||
Reference in New Issue
Block a user