Skip to content

Commit f93934f

Browse files
committed
Make Continue have the target it's continuing to
1 parent 3280a16 commit f93934f

3 files changed

Lines changed: 45 additions & 39 deletions

File tree

bytecode/src/bytecode.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ pub enum Instruction {
225225
},
226226
Duplicate,
227227
GetIter,
228-
Continue,
228+
Continue {
229+
target: Label,
230+
},
229231
Break,
230232
Jump {
231233
target: Label,
@@ -598,7 +600,8 @@ impl<C: Constant> CodeObject<C> {
598600
| SetupExcept { handler: l }
599601
| SetupWith { end: l }
600602
| SetupAsyncWith { end: l }
601-
| SetupLoop { end: l } => {
603+
| SetupLoop { end: l }
604+
| Continue { target: l } => {
602605
label_targets.insert(*l);
603606
}
604607

@@ -838,7 +841,7 @@ impl Instruction {
838841
Rotate { amount } => w!(Rotate, amount),
839842
Duplicate => w!(Duplicate),
840843
GetIter => w!(GetIter),
841-
Continue => w!(Continue),
844+
Continue { target } => w!(Continue, target),
842845
Break => w!(Break),
843846
Jump { target } => w!(Jump, target),
844847
JumpIfTrue { target } => w!(JumpIfTrue, target),

compiler/src/compile.rs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ impl CodeInfo {
8888
| SetupExcept { handler: l }
8989
| SetupWith { end: l }
9090
| SetupAsyncWith { end: l }
91-
| SetupLoop { end: l } => {
91+
| SetupLoop { end: l }
92+
| Continue { target: l } => {
9293
*l = label_map[l.0].expect("label never set");
9394
}
9495

@@ -131,7 +132,7 @@ impl Default for CompileOpts {
131132

132133
#[derive(Debug, Clone, Copy)]
133134
struct CompileContext {
134-
in_loop: bool,
135+
loop_data: Option<(Label, Label)>,
135136
in_class: bool,
136137
func: FunctionContext,
137138
}
@@ -144,6 +145,9 @@ enum FunctionContext {
144145
}
145146

146147
impl CompileContext {
148+
fn in_loop(self) -> bool {
149+
self.loop_data.is_some()
150+
}
147151
fn in_func(self) -> bool {
148152
self.func != FunctionContext::NoFunction
149153
}
@@ -236,7 +240,7 @@ impl Compiler {
236240
current_qualified_path: None,
237241
done_with_future_stmts: false,
238242
ctx: CompileContext {
239-
in_loop: false,
243+
loop_data: None,
240244
in_class: false,
241245
func: FunctionContext::NoFunction,
242246
},
@@ -737,19 +741,21 @@ impl Compiler {
737741
}
738742
}
739743
Break => {
740-
if !self.ctx.in_loop {
744+
if !self.ctx.in_loop() {
741745
return Err(self.error_loc(CompileErrorType::InvalidBreak, statement.location));
742746
}
743747
self.emit(Instruction::Break);
744748
}
745-
Continue => {
746-
if !self.ctx.in_loop {
749+
Continue => match self.ctx.loop_data {
750+
Some((start, _)) => {
751+
self.emit(Instruction::Continue { target: start });
752+
}
753+
None => {
747754
return Err(
748755
self.error_loc(CompileErrorType::InvalidContinue, statement.location)
749756
);
750757
}
751-
self.emit(Instruction::Continue);
752-
}
758+
},
753759
Return { value } => {
754760
if !self.ctx.in_func() {
755761
return Err(self.error_loc(CompileErrorType::InvalidReturn, statement.location));
@@ -1052,7 +1058,7 @@ impl Compiler {
10521058
let prev_ctx = self.ctx;
10531059

10541060
self.ctx = CompileContext {
1055-
in_loop: false,
1061+
loop_data: None,
10561062
in_class: prev_ctx.in_class,
10571063
func: if is_async {
10581064
FunctionContext::AsyncFunction
@@ -1258,7 +1264,7 @@ impl Compiler {
12581264
self.ctx = CompileContext {
12591265
func: FunctionContext::NoFunction,
12601266
in_class: true,
1261-
in_loop: false,
1267+
loop_data: None,
12621268
};
12631269

12641270
let qualified_name = self.create_qualified_name(name, "");
@@ -1399,10 +1405,10 @@ impl Compiler {
13991405

14001406
self.compile_jump_if(test, false, else_label)?;
14011407

1402-
let was_in_loop = self.ctx.in_loop;
1403-
self.ctx.in_loop = true;
1408+
let was_in_loop = self.ctx.loop_data;
1409+
self.ctx.loop_data = Some((start_label, end_label));
14041410
self.compile_statements(body)?;
1405-
self.ctx.in_loop = was_in_loop;
1411+
self.ctx.loop_data = was_in_loop;
14061412
self.emit(Instruction::Jump {
14071413
target: start_label,
14081414
});
@@ -1428,6 +1434,8 @@ impl Compiler {
14281434
let else_label = self.new_label();
14291435
let end_label = self.new_label();
14301436

1437+
self.emit(Instruction::SetupLoop { end: end_label });
1438+
14311439
// The thing iterated:
14321440
self.compile_expression(iter)?;
14331441

@@ -1437,7 +1445,6 @@ impl Compiler {
14371445

14381446
self.emit(Instruction::GetAIter);
14391447

1440-
self.emit(Instruction::SetupLoop { end: end_label });
14411448
self.set_label(start_label);
14421449
self.emit(Instruction::SetupExcept {
14431450
handler: check_asynciter_label,
@@ -1459,26 +1466,25 @@ impl Compiler {
14591466
self.emit(Instruction::JumpIfTrue { target: else_label });
14601467
self.emit(Instruction::Raise { argc: 0 });
14611468

1462-
let was_in_loop = self.ctx.in_loop;
1463-
self.ctx.in_loop = true;
1469+
let was_in_loop = self.ctx.loop_data;
1470+
self.ctx.loop_data = Some((start_label, end_label));
14641471
self.set_label(body_label);
14651472
self.compile_statements(body)?;
1466-
self.ctx.in_loop = was_in_loop;
1473+
self.ctx.loop_data = was_in_loop;
14671474
} else {
14681475
// Retrieve Iterator
14691476
self.emit(Instruction::GetIter);
14701477

1471-
self.emit(Instruction::SetupLoop { end: end_label });
14721478
self.set_label(start_label);
14731479
self.emit(Instruction::ForIter { target: else_label });
14741480

14751481
// Start of loop iteration, set targets:
14761482
self.compile_store(target)?;
14771483

1478-
let was_in_loop = self.ctx.in_loop;
1479-
self.ctx.in_loop = true;
1484+
let was_in_loop = self.ctx.loop_data;
1485+
self.ctx.loop_data = Some((start_label, end_label));
14801486
self.compile_statements(body)?;
1481-
self.ctx.in_loop = was_in_loop;
1487+
self.ctx.loop_data = was_in_loop;
14821488
}
14831489

14841490
self.emit(Instruction::Jump {
@@ -2009,7 +2015,7 @@ impl Compiler {
20092015
Lambda { args, body } => {
20102016
let prev_ctx = self.ctx;
20112017
self.ctx = CompileContext {
2012-
in_loop: false,
2018+
loop_data: Option::None,
20132019
in_class: prev_ctx.in_class,
20142020
func: FunctionContext::Function,
20152021
};
@@ -2182,7 +2188,7 @@ impl Compiler {
21822188
let prev_ctx = self.ctx;
21832189

21842190
self.ctx = CompileContext {
2185-
in_loop: false,
2191+
loop_data: None,
21862192
in_class: prev_ctx.in_class,
21872193
func: FunctionContext::Function,
21882194
};

vm/src/frame.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ struct Block {
4242
#[derive(Clone, Debug)]
4343
enum BlockType {
4444
Loop {
45-
start: bytecode::Label,
4645
end: bytecode::Label,
4746
},
4847
TryExcept {
@@ -77,7 +76,7 @@ enum UnwindReason {
7776
Break,
7877

7978
/// We are unwinding blocks since we hit a continue statements.
80-
Continue,
79+
Continue { target: bytecode::Label },
8180
}
8281

8382
#[derive(Debug)]
@@ -328,7 +327,7 @@ impl ExecutingFrame<'_> {
328327
loop {
329328
let idx = self.lasti.fetch_add(1, Ordering::Relaxed);
330329
let instr = &self.code.instructions[idx];
331-
let result = self.execute_instruction(instr, idx, vm);
330+
let result = self.execute_instruction(instr, vm);
332331
match result {
333332
Ok(None) => continue,
334333
Ok(Some(value)) => {
@@ -422,7 +421,6 @@ impl ExecutingFrame<'_> {
422421
fn execute_instruction(
423422
&mut self,
424423
instruction: &bytecode::Instruction,
425-
current_idx: usize,
426424
vm: &VirtualMachine,
427425
) -> FrameResult {
428426
vm.check_signals()?;
@@ -671,10 +669,7 @@ impl ExecutingFrame<'_> {
671669
Ok(None)
672670
}
673671
bytecode::Instruction::SetupLoop { end } => {
674-
self.push_block(BlockType::Loop {
675-
start: bytecode::Label(current_idx + 1),
676-
end: *end,
677-
});
672+
self.push_block(BlockType::Loop { end: *end });
678673
Ok(None)
679674
}
680675
bytecode::Instruction::SetupExcept { handler } => {
@@ -871,7 +866,9 @@ impl ExecutingFrame<'_> {
871866
bytecode::Instruction::Raise { argc } => self.execute_raise(vm, *argc),
872867

873868
bytecode::Instruction::Break => self.unwind_blocks(vm, UnwindReason::Break),
874-
bytecode::Instruction::Continue => self.unwind_blocks(vm, UnwindReason::Continue),
869+
bytecode::Instruction::Continue { target } => {
870+
self.unwind_blocks(vm, UnwindReason::Continue { target: *target })
871+
}
875872
bytecode::Instruction::PrintExpr => {
876873
let expr = self.pop_value();
877874

@@ -1040,14 +1037,14 @@ impl ExecutingFrame<'_> {
10401037
// First unwind all existing blocks on the block stack:
10411038
while let Some(block) = self.current_block() {
10421039
match block.typ {
1043-
BlockType::Loop { start, end } => match &reason {
1040+
BlockType::Loop { end } => match &reason {
10441041
UnwindReason::Break => {
10451042
self.pop_block();
10461043
self.jump(end);
10471044
return Ok(None);
10481045
}
1049-
UnwindReason::Continue => {
1050-
self.jump(start);
1046+
UnwindReason::Continue { target } => {
1047+
self.jump(*target);
10511048
return Ok(None);
10521049
}
10531050
_ => {
@@ -1094,7 +1091,7 @@ impl ExecutingFrame<'_> {
10941091
match reason {
10951092
UnwindReason::Raising { exception } => Err(exception),
10961093
UnwindReason::Returning { value } => Ok(Some(ExecutionResult::Return(value))),
1097-
UnwindReason::Break | UnwindReason::Continue => {
1094+
UnwindReason::Break | UnwindReason::Continue { .. } => {
10981095
panic!("Internal error: break or continue must occur within a loop block.")
10991096
} // UnwindReason::NoWorries => Ok(None),
11001097
}

0 commit comments

Comments
 (0)