diff --git a/minijinja/src/compiler/codegen.rs b/minijinja/src/compiler/codegen.rs index bebbb61d..c253c303 100644 --- a/minijinja/src/compiler/codegen.rs +++ b/minijinja/src/compiler/codegen.rs @@ -136,16 +136,13 @@ impl<'source> CodeGenerator<'source> { } /// Ends the open for loop - pub fn end_for_loop(&mut self, push_did_iterate: bool) { + pub fn end_for_loop(&mut self, push_did_not_iterate: bool) { match self.pending_block.pop() { Some(PendingBlock::Loop(iter_instr)) => { self.add(Instruction::Jump(iter_instr)); let loop_end = self.next_instruction(); - if push_did_iterate { - self.add(Instruction::Lookup("loop")); - self.add(Instruction::GetAttr("index0")); - self.add(Instruction::LoadConst(Value::from(0))); - self.add(Instruction::Eq); + if push_did_not_iterate { + self.add(Instruction::PushDidNotIterate); }; self.add(Instruction::PopFrame); if let Some(Instruction::Iterate(ref mut jump_target)) = diff --git a/minijinja/src/compiler/instructions.rs b/minijinja/src/compiler/instructions.rs index d4df9de6..5a4be3f2 100644 --- a/minijinja/src/compiler/instructions.rs +++ b/minijinja/src/compiler/instructions.rs @@ -138,6 +138,9 @@ pub enum Instruction<'source> { /// ends and must point to a `PopFrame` instruction. Iterate(usize), + /// Push a bool that indicates that the loop iterated. + PushDidNotIterate, + /// Pops the topmost frame PopFrame, diff --git a/minijinja/src/vm/mod.rs b/minijinja/src/vm/mod.rs index fd7e3c26..a5954240 100644 --- a/minijinja/src/vm/mod.rs +++ b/minijinja/src/vm/mod.rs @@ -350,7 +350,7 @@ impl<'env> Vm<'env> { ctx_ok!(self.push_loop(state, a, *flags, pc, next_loop_recursion_jump.take())); } Instruction::Iterate(jump_target) => { - let l = state.ctx.current_loop().expect("not inside a loop"); + let l = state.ctx.current_loop().unwrap(); l.object.idx.fetch_add(1, Ordering::Relaxed); match l.iterator.next() { Some(item) => stack.push(item), @@ -360,6 +360,10 @@ impl<'env> Vm<'env> { } }; } + Instruction::PushDidNotIterate => { + let l = state.ctx.current_loop().unwrap(); + stack.push(Value::from(l.object.idx.load(Ordering::Relaxed) == 0)); + } Instruction::Jump(jump_target) => { pc = *jump_target; continue;