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

Function compile_select

core/src/compiler/top.rs:392–492  ·  view source on GitHub ↗

Compiles a `SELECT` statement and emits bytecode into `ctx`.

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

Source from the content-addressed store, hash-verified

390
391/// Compiles a `SELECT` statement and emits bytecode into `ctx`.
392fn compile_select(
393 ctx: &mut Context,
394 symtable: &mut LocalSymtable<'_>,
395 span: SelectSpan,
396) -> Result<()> {
397 let end_pos = span.end_pos;
398 let ncases = span.cases.len();
399 let select_cases = span.cases;
400 let select_expr = span.expr;
401 let select_expr_pos = select_expr.start_pos();
402
403 /// Captures the data needed to materialize a `CASE` body after dispatch generation.
404 struct PendingCase {
405 body: Vec<Statement>,
406 body_jump_pcs: Vec<(usize, LineCol)>,
407 has_next_case: bool,
408 }
409
410 let mut pending_cases = Vec::with_capacity(ncases);
411 let mut pending_next_case_jump: Option<(usize, LineCol)> = None;
412
413 symtable.with_reserved_temp(
414 |e| Error::from_syms(e, select_expr_pos),
415 |test_reg, frozen| {
416 let test_type = compile_expr(&mut ctx.codegen, frozen, test_reg, select_expr)?;
417
418 for (i, case) in select_cases.into_iter().enumerate() {
419 let has_next_case = i < ncases - 1;
420 let mut body_jump_pcs = vec![];
421 let case_dispatch_addr = ctx.codegen.next_pc();
422 if let Some((jump_pc, pos)) = pending_next_case_jump.take() {
423 let target = u16::try_from(case_dispatch_addr)
424 .map_err(|_| Error::TargetTooFar(pos, case_dispatch_addr))?;
425 ctx.codegen.patch(jump_pc, bytecode::make_jump(target));
426 }
427
428 if case.guards.is_empty() {
429 let jump_body_pc = ctx.codegen.emit(bytecode::make_nop(), end_pos);
430 body_jump_pcs.push((jump_body_pc, end_pos));
431 } else {
432 for guard in case.guards {
433 let (cond_reg, pos) =
434 compile_case_guard(ctx, frozen, test_reg, test_type, guard)?;
435 let jump_next_guard_pc = ctx.codegen.emit(bytecode::make_nop(), pos);
436 let jump_body_pc = ctx.codegen.emit(bytecode::make_nop(), pos);
437 body_jump_pcs.push((jump_body_pc, pos));
438
439 let next_addr = ctx.codegen.next_pc();
440 let target = u16::try_from(next_addr)
441 .map_err(|_| Error::TargetTooFar(pos, next_addr))?;
442 ctx.codegen.patch(
443 jump_next_guard_pc,
444 bytecode::make_jump_if_false(cond_reg, target),
445 );
446 }
447
448 let jump_next_case_pc = ctx.codegen.emit(bytecode::make_nop(), end_pos);
449 pending_next_case_jump = Some((jump_next_case_pc, end_pos));

Callers 1

compile_stmtFunction · 0.85

Calls 12

compile_exprFunction · 0.85
compile_case_guardFunction · 0.85
compile_stmtFunction · 0.85
start_posMethod · 0.80
with_reserved_tempMethod · 0.80
next_pcMethod · 0.80
patchMethod · 0.80
emitMethod · 0.80
pushMethod · 0.80
lenMethod · 0.45
enumerateMethod · 0.45
is_emptyMethod · 0.45

Tested by

no test coverage detected