MCPcopy Index your code
hub / github.com/endbasic/endbasic / compile_do

Function compile_do

core/src/compiler/top.rs:495–603  ·  view source on GitHub ↗

Compiles a `DO` loop and emits bytecode into `ctx`.

(ctx: &mut Context, symtable: &mut LocalSymtable<'_>, span: DoSpan)

Source from the content-addressed store, hash-verified

493
494/// Compiles a `DO` loop and emits bytecode into `ctx`.
495fn compile_do(ctx: &mut Context, symtable: &mut LocalSymtable<'_>, span: DoSpan) -> Result<()> {
496 /// Compiles one loop guard expression to a temporary boolean register.
497 fn compile_guard(
498 ctx: &mut Context,
499 symtable: &mut LocalSymtable<'_>,
500 guard: Expr,
501 ) -> Result<(Register, LineCol)> {
502 let guard_pos = guard.start_pos();
503 let mut frozen = symtable.frozen();
504 let mut scope = frozen.temp_scope();
505 let reg = scope.alloc().map_err(|e| Error::from_syms(e, guard_pos))?;
506 compile_expr_as_type(&mut ctx.codegen, &mut frozen, reg, guard, ExprType::Boolean)?;
507 Ok((reg, guard_pos))
508 }
509
510 ctx.do_exit_stack.push(vec![]);
511
512 let end_addr = match span.guard {
513 DoGuard::Infinite => {
514 let start_pc = ctx.codegen.next_pc();
515 for stmt in span.body {
516 compile_stmt(ctx, symtable, stmt)?;
517 }
518 let end_pos = LineCol { line: 0, col: 0 };
519 let target =
520 u16::try_from(start_pc).map_err(|_| Error::TargetTooFar(end_pos, start_pc))?;
521 ctx.codegen.emit(bytecode::make_jump(target), end_pos);
522 ctx.codegen.next_pc()
523 }
524
525 DoGuard::PreUntil(guard) => {
526 let start_pc = ctx.codegen.next_pc();
527 let (cond_reg, guard_pos) = compile_guard(ctx, symtable, guard)?;
528 let jump_body_pc = ctx.codegen.emit(bytecode::make_nop(), guard_pos);
529 let jump_end_pc = ctx.codegen.emit(bytecode::make_nop(), guard_pos);
530 let body_addr = ctx.codegen.next_pc();
531 let body_target =
532 u16::try_from(body_addr).map_err(|_| Error::TargetTooFar(guard_pos, body_addr))?;
533 ctx.codegen.patch(jump_body_pc, bytecode::make_jump_if_false(cond_reg, body_target));
534
535 for stmt in span.body {
536 compile_stmt(ctx, symtable, stmt)?;
537 }
538 let start_target =
539 u16::try_from(start_pc).map_err(|_| Error::TargetTooFar(guard_pos, start_pc))?;
540 ctx.codegen.emit(bytecode::make_jump(start_target), guard_pos);
541 let end_addr = ctx.codegen.next_pc();
542 let end_target =
543 u16::try_from(end_addr).map_err(|_| Error::TargetTooFar(guard_pos, end_addr))?;
544 ctx.codegen.patch(jump_end_pc, bytecode::make_jump(end_target));
545 end_addr
546 }
547
548 DoGuard::PreWhile(guard) => {
549 let start_pc = ctx.codegen.next_pc();
550 let (cond_reg, guard_pos) = compile_guard(ctx, symtable, guard)?;
551 let jump_end_pc = ctx.codegen.emit(bytecode::make_nop(), guard_pos);
552

Callers 1

compile_stmtFunction · 0.85

Calls 6

compile_stmtFunction · 0.85
compile_guardFunction · 0.85
pushMethod · 0.80
next_pcMethod · 0.80
emitMethod · 0.80
patchMethod · 0.80

Tested by

no test coverage detected