Compiles a `WHILE` loop and emits bytecode into `ctx`.
(
ctx: &mut Context,
symtable: &mut LocalSymtable<'_>,
span: WhileSpan,
)
| 725 | |
| 726 | /// Compiles a `WHILE` loop and emits bytecode into `ctx`. |
| 727 | fn compile_while( |
| 728 | ctx: &mut Context, |
| 729 | symtable: &mut LocalSymtable<'_>, |
| 730 | span: WhileSpan, |
| 731 | ) -> Result<()> { |
| 732 | let start_pc = ctx.codegen.next_pc(); |
| 733 | |
| 734 | let (jump_end_pc, cond_reg, guard_pos) = { |
| 735 | let guard_pos = span.expr.start_pos(); |
| 736 | let mut frozen = symtable.frozen(); |
| 737 | let mut scope = frozen.temp_scope(); |
| 738 | let reg = scope.alloc().map_err(|e| Error::from_syms(e, guard_pos))?; |
| 739 | compile_expr_as_type(&mut ctx.codegen, &mut frozen, reg, span.expr, ExprType::Boolean)?; |
| 740 | (ctx.codegen.emit(bytecode::make_nop(), guard_pos), reg, guard_pos) |
| 741 | }; |
| 742 | |
| 743 | for stmt in span.body { |
| 744 | compile_stmt(ctx, symtable, stmt)?; |
| 745 | } |
| 746 | |
| 747 | let start_target = |
| 748 | u16::try_from(start_pc).map_err(|_| Error::TargetTooFar(guard_pos, start_pc))?; |
| 749 | ctx.codegen.emit(bytecode::make_jump(start_target), guard_pos); |
| 750 | |
| 751 | let end_addr = ctx.codegen.next_pc(); |
| 752 | let end_target = |
| 753 | u16::try_from(end_addr).map_err(|_| Error::TargetTooFar(guard_pos, end_addr))?; |
| 754 | ctx.codegen.patch(jump_end_pc, bytecode::make_jump_if_false(cond_reg, end_target)); |
| 755 | |
| 756 | Ok(()) |
| 757 | } |
| 758 | |
| 759 | /// Compiles a single `stmt` into the `ctx`. |
| 760 | fn compile_stmt( |
no test coverage detected