diff options
Diffstat (limited to 'inc/Twig/Compiler.php')
-rw-r--r-- | inc/Twig/Compiler.php | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/inc/Twig/Compiler.php b/inc/Twig/Compiler.php new file mode 100644 index 00000000..99aecbcc --- /dev/null +++ b/inc/Twig/Compiler.php | |||
@@ -0,0 +1,267 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of Twig. | ||
5 | * | ||
6 | * (c) 2009 Fabien Potencier | ||
7 | * (c) 2009 Armin Ronacher | ||
8 | * | ||
9 | * For the full copyright and license information, please view the LICENSE | ||
10 | * file that was distributed with this source code. | ||
11 | */ | ||
12 | |||
13 | /** | ||
14 | * Compiles a node to PHP code. | ||
15 | * | ||
16 | * @author Fabien Potencier <fabien@symfony.com> | ||
17 | */ | ||
18 | class Twig_Compiler implements Twig_CompilerInterface | ||
19 | { | ||
20 | protected $lastLine; | ||
21 | protected $source; | ||
22 | protected $indentation; | ||
23 | protected $env; | ||
24 | protected $debugInfo; | ||
25 | protected $sourceOffset; | ||
26 | protected $sourceLine; | ||
27 | protected $filename; | ||
28 | |||
29 | /** | ||
30 | * Constructor. | ||
31 | * | ||
32 | * @param Twig_Environment $env The twig environment instance | ||
33 | */ | ||
34 | public function __construct(Twig_Environment $env) | ||
35 | { | ||
36 | $this->env = $env; | ||
37 | $this->debugInfo = array(); | ||
38 | } | ||
39 | |||
40 | public function getFilename() | ||
41 | { | ||
42 | return $this->filename; | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * Returns the environment instance related to this compiler. | ||
47 | * | ||
48 | * @return Twig_Environment The environment instance | ||
49 | */ | ||
50 | public function getEnvironment() | ||
51 | { | ||
52 | return $this->env; | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * Gets the current PHP code after compilation. | ||
57 | * | ||
58 | * @return string The PHP code | ||
59 | */ | ||
60 | public function getSource() | ||
61 | { | ||
62 | return $this->source; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * Compiles a node. | ||
67 | * | ||
68 | * @param Twig_NodeInterface $node The node to compile | ||
69 | * @param integer $indentation The current indentation | ||
70 | * | ||
71 | * @return Twig_Compiler The current compiler instance | ||
72 | */ | ||
73 | public function compile(Twig_NodeInterface $node, $indentation = 0) | ||
74 | { | ||
75 | $this->lastLine = null; | ||
76 | $this->source = ''; | ||
77 | $this->sourceOffset = 0; | ||
78 | // source code starts at 1 (as we then increment it when we encounter new lines) | ||
79 | $this->sourceLine = 1; | ||
80 | $this->indentation = $indentation; | ||
81 | |||
82 | if ($node instanceof Twig_Node_Module) { | ||
83 | $this->filename = $node->getAttribute('filename'); | ||
84 | } | ||
85 | |||
86 | $node->compile($this); | ||
87 | |||
88 | return $this; | ||
89 | } | ||
90 | |||
91 | public function subcompile(Twig_NodeInterface $node, $raw = true) | ||
92 | { | ||
93 | if (false === $raw) { | ||
94 | $this->addIndentation(); | ||
95 | } | ||
96 | |||
97 | $node->compile($this); | ||
98 | |||
99 | return $this; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * Adds a raw string to the compiled code. | ||
104 | * | ||
105 | * @param string $string The string | ||
106 | * | ||
107 | * @return Twig_Compiler The current compiler instance | ||
108 | */ | ||
109 | public function raw($string) | ||
110 | { | ||
111 | $this->source .= $string; | ||
112 | |||
113 | return $this; | ||
114 | } | ||
115 | |||
116 | /** | ||
117 | * Writes a string to the compiled code by adding indentation. | ||
118 | * | ||
119 | * @return Twig_Compiler The current compiler instance | ||
120 | */ | ||
121 | public function write() | ||
122 | { | ||
123 | $strings = func_get_args(); | ||
124 | foreach ($strings as $string) { | ||
125 | $this->addIndentation(); | ||
126 | $this->source .= $string; | ||
127 | } | ||
128 | |||
129 | return $this; | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * Appends an indentation to the current PHP code after compilation. | ||
134 | * | ||
135 | * @return Twig_Compiler The current compiler instance | ||
136 | */ | ||
137 | public function addIndentation() | ||
138 | { | ||
139 | $this->source .= str_repeat(' ', $this->indentation * 4); | ||
140 | |||
141 | return $this; | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * Adds a quoted string to the compiled code. | ||
146 | * | ||
147 | * @param string $value The string | ||
148 | * | ||
149 | * @return Twig_Compiler The current compiler instance | ||
150 | */ | ||
151 | public function string($value) | ||
152 | { | ||
153 | $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\")); | ||
154 | |||
155 | return $this; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * Returns a PHP representation of a given value. | ||
160 | * | ||
161 | * @param mixed $value The value to convert | ||
162 | * | ||
163 | * @return Twig_Compiler The current compiler instance | ||
164 | */ | ||
165 | public function repr($value) | ||
166 | { | ||
167 | if (is_int($value) || is_float($value)) { | ||
168 | if (false !== $locale = setlocale(LC_NUMERIC, 0)) { | ||
169 | setlocale(LC_NUMERIC, 'C'); | ||
170 | } | ||
171 | |||
172 | $this->raw($value); | ||
173 | |||
174 | if (false !== $locale) { | ||
175 | setlocale(LC_NUMERIC, $locale); | ||
176 | } | ||
177 | } elseif (null === $value) { | ||
178 | $this->raw('null'); | ||
179 | } elseif (is_bool($value)) { | ||
180 | $this->raw($value ? 'true' : 'false'); | ||
181 | } elseif (is_array($value)) { | ||
182 | $this->raw('array('); | ||
183 | $i = 0; | ||
184 | foreach ($value as $key => $value) { | ||
185 | if ($i++) { | ||
186 | $this->raw(', '); | ||
187 | } | ||
188 | $this->repr($key); | ||
189 | $this->raw(' => '); | ||
190 | $this->repr($value); | ||
191 | } | ||
192 | $this->raw(')'); | ||
193 | } else { | ||
194 | $this->string($value); | ||
195 | } | ||
196 | |||
197 | return $this; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * Adds debugging information. | ||
202 | * | ||
203 | * @param Twig_NodeInterface $node The related twig node | ||
204 | * | ||
205 | * @return Twig_Compiler The current compiler instance | ||
206 | */ | ||
207 | public function addDebugInfo(Twig_NodeInterface $node) | ||
208 | { | ||
209 | if ($node->getLine() != $this->lastLine) { | ||
210 | $this->write("// line {$node->getLine()}\n"); | ||
211 | |||
212 | // when mbstring.func_overload is set to 2 | ||
213 | // mb_substr_count() replaces substr_count() | ||
214 | // but they have different signatures! | ||
215 | if (((int) ini_get('mbstring.func_overload')) & 2) { | ||
216 | // this is much slower than the "right" version | ||
217 | $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n"); | ||
218 | } else { | ||
219 | $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); | ||
220 | } | ||
221 | $this->sourceOffset = strlen($this->source); | ||
222 | $this->debugInfo[$this->sourceLine] = $node->getLine(); | ||
223 | |||
224 | $this->lastLine = $node->getLine(); | ||
225 | } | ||
226 | |||
227 | return $this; | ||
228 | } | ||
229 | |||
230 | public function getDebugInfo() | ||
231 | { | ||
232 | return $this->debugInfo; | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * Indents the generated code. | ||
237 | * | ||
238 | * @param integer $step The number of indentation to add | ||
239 | * | ||
240 | * @return Twig_Compiler The current compiler instance | ||
241 | */ | ||
242 | public function indent($step = 1) | ||
243 | { | ||
244 | $this->indentation += $step; | ||
245 | |||
246 | return $this; | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * Outdents the generated code. | ||
251 | * | ||
252 | * @param integer $step The number of indentation to remove | ||
253 | * | ||
254 | * @return Twig_Compiler The current compiler instance | ||
255 | */ | ||
256 | public function outdent($step = 1) | ||
257 | { | ||
258 | // can't outdent by more steps than the current indentation level | ||
259 | if ($this->indentation < $step) { | ||
260 | throw new LogicException('Unable to call outdent() as the indentation would become negative'); | ||
261 | } | ||
262 | |||
263 | $this->indentation -= $step; | ||
264 | |||
265 | return $this; | ||
266 | } | ||
267 | } | ||