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
 * @package    twig
17
 * @author     Fabien Potencier <fabien@symfony.com>
18
 */
19
class Twig_Compiler implements Twig_CompilerInterface
20
{
21
    protected $lastLine;
22
    protected $source;
23
    protected $indentation;
24
    protected $env;
25
    protected $debugInfo;
26
    protected $sourceOffset;
27
    protected $sourceLine;
28
    protected $filename;
29

    
30
    /**
31
     * Constructor.
32
     *
33
     * @param Twig_Environment $env The twig environment instance
34
     */
35
    public function __construct(Twig_Environment $env)
36
    {
37
        $this->env = $env;
38
        $this->debugInfo = array();
39
    }
40

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

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

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

    
66
    /**
67
     * Compiles a node.
68
     *
69
     * @param Twig_NodeInterface $node        The node to compile
70
     * @param integer            $indentation The current indentation
71
     *
72
     * @return Twig_Compiler The current compiler instance
73
     */
74
    public function compile(Twig_NodeInterface $node, $indentation = 0)
75
    {
76
        $this->lastLine = null;
77
        $this->source = '';
78
        $this->sourceOffset = 0;
79
        // source code starts at 1 (as we then increment it when we encounter new lines)
80
        $this->sourceLine = 1;
81
        $this->indentation = $indentation;
82

    
83
        if ($node instanceof Twig_Node_Module) {
84
            $this->filename = $node->getAttribute('filename');
85
        }
86

    
87
        $node->compile($this);
88

    
89
        return $this;
90
    }
91

    
92
    public function subcompile(Twig_NodeInterface $node, $raw = true)
93
    {
94
        if (false === $raw) {
95
            $this->addIndentation();
96
        }
97

    
98
        $node->compile($this);
99

    
100
        return $this;
101
    }
102

    
103
    /**
104
     * Adds a raw string to the compiled code.
105
     *
106
     * @param string $string The string
107
     *
108
     * @return Twig_Compiler The current compiler instance
109
     */
110
    public function raw($string)
111
    {
112
        $this->source .= $string;
113

    
114
        return $this;
115
    }
116

    
117
    /**
118
     * Writes a string to the compiled code by adding indentation.
119
     *
120
     * @return Twig_Compiler The current compiler instance
121
     */
122
    public function write()
123
    {
124
        $strings = func_get_args();
125
        foreach ($strings as $string) {
126
            $this->addIndentation();
127
            $this->source .= $string;
128
        }
129

    
130
        return $this;
131
    }
132

    
133
    /**
134
     * Appends an indentation to the current PHP code after compilation.
135
     *
136
     * @return Twig_Compiler The current compiler instance
137
     */
138
    public function addIndentation()
139
    {
140
        $this->source .= str_repeat(' ', $this->indentation * 4);
141

    
142
        return $this;
143
    }
144

    
145
    /**
146
     * Adds a quoted string to the compiled code.
147
     *
148
     * @param string $value The string
149
     *
150
     * @return Twig_Compiler The current compiler instance
151
     */
152
    public function string($value)
153
    {
154
        $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
155

    
156
        return $this;
157
    }
158

    
159
    /**
160
     * Returns a PHP representation of a given value.
161
     *
162
     * @param mixed $value The value to convert
163
     *
164
     * @return Twig_Compiler The current compiler instance
165
     */
166
    public function repr($value)
167
    {
168
        if (is_int($value) || is_float($value)) {
169
            if (false !== $locale = setlocale(LC_NUMERIC, 0)) {
170
                setlocale(LC_NUMERIC, 'C');
171
            }
172

    
173
            $this->raw($value);
174

    
175
            if (false !== $locale) {
176
                setlocale(LC_NUMERIC, $locale);
177
            }
178
        } elseif (null === $value) {
179
            $this->raw('null');
180
        } elseif (is_bool($value)) {
181
            $this->raw($value ? 'true' : 'false');
182
        } elseif (is_array($value)) {
183
            $this->raw('array(');
184
            $i = 0;
185
            foreach ($value as $key => $value) {
186
                if ($i++) {
187
                    $this->raw(', ');
188
                }
189
                $this->repr($key);
190
                $this->raw(' => ');
191
                $this->repr($value);
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("// line {$node->getLine()}\n");
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
        return $this->debugInfo;
234
    }
235

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

    
247
        return $this;
248
    }
249

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

    
264
        $this->indentation -= $step;
265

    
266
        return $this;
267
    }
268
}
(2-2/34)