]>
Commit | Line | Data |
---|---|---|
a4565e88 NL |
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 | } |