public function compile($compiler)
{
$compiler
->addDebugInfo($this)
// the (array) cast bypasses a PHP 5.2.6 bug
->write('$context[\'_parent\'] = (array) $context;'."\n")
;
if (null !== $this->getNode('else')) {
$compiler->write("\$context['_iterated'] = false;\n");
}
$compiler
->write("\$context['_seq'] = twig_iterator_to_array(")
->subcompile($this->getNode('seq'))
->raw(");\n")
;
if ($this->getAttribute('with_loop')) {
$compiler
->write("\$countable = is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable);\n")
->write("\$length = \$countable ? count(\$context['_seq']) : null;\n")
->write("\$context['loop'] = array(\n")
->write(" 'parent' => \$context['_parent'],\n")
->write(" 'index0' => 0,\n")
->write(" 'index' => 1,\n")
->write(" 'first' => true,\n")
->write(");\n")
->write("if (\$countable) {\n")
->indent()
->write("\$context['loop']['revindex0'] = \$length - 1;\n")
->write("\$context['loop']['revindex'] = \$length;\n")
->write("\$context['loop']['length'] = \$length;\n")
->write("\$context['loop']['last'] = 1 === \$length;\n")
->outdent()
->write("}\n")
;
}
if (null !== $this->getNode('joined_with')) {
$compiler->write("\$context['_first_iteration'] = true;\n");
}
$compiler
->write("foreach (\$context['_seq'] as ")
->subcompile($this->getNode('key_target'))
->raw(" => ")
->subcompile($this->getNode('value_target'))
->raw(") {\n")
->indent()
;
if (null !== $this->getNode('else')) {
$compiler->write("\$context['_iterated'] = true;\n");
}
if (null !== $this->getNode('joined_with')) {
$compiler
->write("if (\$context['_first_iteration']) {\n")
->indent()
->write("\$context['_first_iteration'] = false;\n")
->outdent()
->write("} else {\n")
->indent()
->write("echo ")
->subcompile($this->getNode('joined_with'))
->raw(";\n")
->outdent()
->write("}\n");
}
$compiler->subcompile($this->getNode('body'));
if ($this->getAttribute('with_loop')) {
$compiler
->write("++\$context['loop']['index0'];\n")
->write("++\$context['loop']['index'];\n")
->write("\$context['loop']['first'] = false;\n")
->write("if (\$countable) {\n")
->indent()
->write("--\$context['loop']['revindex0'];\n")
->write("--\$context['loop']['revindex'];\n")
->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
->outdent()
->write("}\n")
;
}
$compiler
->outdent()
->write("}\n")
;
if (null !== $this->getNode('else')) {
$compiler
->write("if (!\$context['_iterated']) {\n")
->indent()
->subcompile($this->getNode('else'))
->outdent()
->write("}\n")
;
}
$compiler->write('$_parent = $context[\'_parent\'];'."\n");
// remove some "private" loop variables (needed for nested loops)
$compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
/// keep the values set in the inner context for variables defined in the outer context
$compiler->write('$context = array_merge($_parent, array_intersect_key($context, $_parent));'."\n");
}