Project

General

Profile

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 = array();
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
    }
38

    
39
    public function getFilename()
40
    {
41
        return $this->filename;
42
    }
43

    
44
    /**
45
     * Returns the environment instance related to this compiler.
46
     *
47
     * @return Twig_Environment The environment instance
48
     */
49
    public function getEnvironment()
50
    {
51
        return $this->env;
52
    }
53

    
54
    /**
55
     * Gets the current PHP code after compilation.
56
     *
57
     * @return string The PHP code
58
     */
59
    public function getSource()
60
    {
61
        return $this->source;
62
    }
63

    
64
    /**
65
     * Compiles a node.
66
     *
67
     * @param Twig_NodeInterface $node        The node to compile
68
     * @param int                $indentation The current indentation
69
     *
70
     * @return Twig_Compiler The current compiler instance
71
     */
72
    public function compile(Twig_NodeInterface $node, $indentation = 0)
73
    {
74
        $this->lastLine = null;
75
        $this->source = '';
76
        $this->debugInfo = array();
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
            $first = true;
184
            foreach ($value as $key => $v) {
185
                if (!$first) {
186
                    $this->raw(', ');
187
                }
188
                $first = false;
189
                $this->repr($key);
190
                $this->raw(' => ');
191
                $this->repr($v);
192
            }
193
            $this->raw(')');
194
        } else {
195
            $this->string($value);
196
        }
197

    
198
        return $this;
199
    }
200

    
201
    /**
202
     * Adds debugging information.
203
     *
204
     * @param Twig_NodeInterface $node The related twig node
205
     *
206
     * @return Twig_Compiler The current compiler instance
207
     */
208
    public function addDebugInfo(Twig_NodeInterface $node)
209
    {
210
        if ($node->getLine() != $this->lastLine) {
211
            $this->write(sprintf("// line %d\n", $node->getLine()));
212

    
213
            // when mbstring.func_overload is set to 2
214
            // mb_substr_count() replaces substr_count()
215
            // but they have different signatures!
216
            if (((int) ini_get('mbstring.func_overload')) & 2) {
217
                // this is much slower than the "right" version
218
                $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
219
            } else {
220
                $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
221
            }
222
            $this->sourceOffset = strlen($this->source);
223
            $this->debugInfo[$this->sourceLine] = $node->getLine();
224

    
225
            $this->lastLine = $node->getLine();
226
        }
227

    
228
        return $this;
229
    }
230

    
231
    public function getDebugInfo()
232
    {
233
        ksort($this->debugInfo);
234

    
235
        return $this->debugInfo;
236
    }
237

    
238
    /**
239
     * Indents the generated code.
240
     *
241
     * @param int $step The number of indentation to add
242
     *
243
     * @return Twig_Compiler The current compiler instance
244
     */
245
    public function indent($step = 1)
246
    {
247
        $this->indentation += $step;
248

    
249
        return $this;
250
    }
251

    
252
    /**
253
     * Outdents the generated code.
254
     *
255
     * @param int $step The number of indentation to remove
256
     *
257
     * @return Twig_Compiler The current compiler instance
258
     *
259
     * @throws LogicException When trying to outdent too much so the indentation would become negative
260
     */
261
    public function outdent($step = 1)
262
    {
263
        // can't outdent by more steps than the current indentation level
264
        if ($this->indentation < $step) {
265
            throw new LogicException('Unable to call outdent() as the indentation would become negative');
266
        }
267

    
268
        $this->indentation -= $step;
269

    
270
        return $this;
271
    }
272

    
273
    public function getVarName()
274
    {
275
        return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
276
    }
277
}
(4-4/43)