1<?php 2 3/* 4 * This file is part of Twig. 5 * 6 * (c) Fabien Potencier 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Twig\Node; 13 14use Twig\Compiler; 15use Twig\Error\SyntaxError; 16 17/** 18 * Represents a macro node. 19 * 20 * @author Fabien Potencier <fabien@symfony.com> 21 */ 22class MacroNode extends Node 23{ 24 public const VARARGS_NAME = 'varargs'; 25 26 public function __construct(string $name, Node $body, Node $arguments, int $lineno, string $tag = null) 27 { 28 foreach ($arguments as $argumentName => $argument) { 29 if (self::VARARGS_NAME === $argumentName) { 30 throw new SyntaxError(sprintf('The argument "%s" in macro "%s" cannot be defined because the variable "%s" is reserved for arbitrary arguments.', self::VARARGS_NAME, $name, self::VARARGS_NAME), $argument->getTemplateLine(), $argument->getSourceContext()); 31 } 32 } 33 34 parent::__construct(['body' => $body, 'arguments' => $arguments], ['name' => $name], $lineno, $tag); 35 } 36 37 public function compile(Compiler $compiler) 38 { 39 $compiler 40 ->addDebugInfo($this) 41 ->write(sprintf('public function macro_%s(', $this->getAttribute('name'))) 42 ; 43 44 $count = \count($this->getNode('arguments')); 45 $pos = 0; 46 foreach ($this->getNode('arguments') as $name => $default) { 47 $compiler 48 ->raw('$__'.$name.'__ = ') 49 ->subcompile($default) 50 ; 51 52 if (++$pos < $count) { 53 $compiler->raw(', '); 54 } 55 } 56 57 if ($count) { 58 $compiler->raw(', '); 59 } 60 61 $compiler 62 ->raw('...$__varargs__') 63 ->raw(")\n") 64 ->write("{\n") 65 ->indent() 66 ->write("\$macros = \$this->macros;\n") 67 ->write("\$context = \$this->env->mergeGlobals([\n") 68 ->indent() 69 ; 70 71 foreach ($this->getNode('arguments') as $name => $default) { 72 $compiler 73 ->write('') 74 ->string($name) 75 ->raw(' => $__'.$name.'__') 76 ->raw(",\n") 77 ; 78 } 79 80 $compiler 81 ->write('') 82 ->string(self::VARARGS_NAME) 83 ->raw(' => ') 84 ; 85 86 $compiler 87 ->raw("\$__varargs__,\n") 88 ->outdent() 89 ->write("]);\n\n") 90 ->write("\$blocks = [];\n\n") 91 ; 92 if ($compiler->getEnvironment()->isDebug()) { 93 $compiler->write("ob_start();\n"); 94 } else { 95 $compiler->write("ob_start(function () { return ''; });\n"); 96 } 97 $compiler 98 ->write("try {\n") 99 ->indent() 100 ->subcompile($this->getNode('body')) 101 ->raw("\n") 102 ->write("return ('' === \$tmp = ob_get_contents()) ? '' : new Markup(\$tmp, \$this->env->getCharset());\n") 103 ->outdent() 104 ->write("} finally {\n") 105 ->indent() 106 ->write("ob_end_clean();\n") 107 ->outdent() 108 ->write("}\n") 109 ->outdent() 110 ->write("}\n\n") 111 ; 112 } 113} 114 115class_alias('Twig\Node\MacroNode', 'Twig_Node_Macro'); 116