Rajout de doctrine/orm
[zf2.biz/galerie.git] / vendor / doctrine / common / lib / Doctrine / Common / Lexer.php
1 <?php
2 /*
3  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * This software consists of voluntary contributions made by many individuals
16  * and is licensed under the MIT license. For more information, see
17  * <http://www.doctrine-project.org>.
18  */
19
20 namespace Doctrine\Common;
21
22 /**
23  * Base class for writing simple lexers, i.e. for creating small DSLs.
24  *
25  * @since   2.0
26  * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
27  * @author  Jonathan Wage <jonwage@gmail.com>
28  * @author  Roman Borschel <roman@code-factory.org>
29  * @todo Rename: AbstractLexer
30  */
31 abstract class Lexer
32 {
33     /**
34      * @var array Array of scanned tokens
35      */
36     private $tokens = array();
37
38     /**
39      * @var integer Current lexer position in input string
40      */
41     private $position = 0;
42
43     /**
44      * @var integer Current peek of current lexer position
45      */
46     private $peek = 0;
47
48     /**
49      * @var array The next token in the input.
50      */
51     public $lookahead;
52
53     /**
54      * @var array The last matched/seen token.
55      */
56     public $token;
57
58     /**
59      * Sets the input data to be tokenized.
60      *
61      * The Lexer is immediately reset and the new input tokenized.
62      * Any unprocessed tokens from any previous input are lost.
63      *
64      * @param string $input The input to be tokenized.
65      */
66     public function setInput($input)
67     {
68         $this->tokens = array();
69         $this->reset();
70         $this->scan($input);
71     }
72
73     /**
74      * Resets the lexer.
75      */
76     public function reset()
77     {
78         $this->lookahead = null;
79         $this->token = null;
80         $this->peek = 0;
81         $this->position = 0;
82     }
83
84     /**
85      * Resets the peek pointer to 0.
86      */
87     public function resetPeek()
88     {
89         $this->peek = 0;
90     }
91
92     /**
93      * Resets the lexer position on the input to the given position.
94      *
95      * @param integer $position Position to place the lexical scanner
96      */
97     public function resetPosition($position = 0)
98     {
99         $this->position = $position;
100     }
101
102     /**
103      * Checks whether a given token matches the current lookahead.
104      *
105      * @param integer|string $token
106      * @return boolean
107      */
108     public function isNextToken($token)
109     {
110         return null !== $this->lookahead && $this->lookahead['type'] === $token;
111     }
112
113     /**
114      * Checks whether any of the given tokens matches the current lookahead
115      *
116      * @param array $tokens
117      * @return boolean
118      */
119     public function isNextTokenAny(array $tokens)
120     {
121         return null !== $this->lookahead && in_array($this->lookahead['type'], $tokens, true);
122     }
123
124     /**
125      * Moves to the next token in the input string.
126      *
127      * A token is an associative array containing three items:
128      *  - 'value'    : the string value of the token in the input string
129      *  - 'type'     : the type of the token (identifier, numeric, string, input
130      *                 parameter, none)
131      *  - 'position' : the position of the token in the input string
132      *
133      * @return array|null the next token; null if there is no more tokens left
134      */
135     public function moveNext()
136     {
137         $this->peek = 0;
138         $this->token = $this->lookahead;
139         $this->lookahead = (isset($this->tokens[$this->position]))
140             ? $this->tokens[$this->position++] : null;
141
142         return $this->lookahead !== null;
143     }
144
145     /**
146      * Tells the lexer to skip input tokens until it sees a token with the given value.
147      *
148      * @param string $type The token type to skip until.
149      */
150     public function skipUntil($type)
151     {
152         while ($this->lookahead !== null && $this->lookahead['type'] !== $type) {
153             $this->moveNext();
154         }
155     }
156
157     /**
158      * Checks if given value is identical to the given token
159      *
160      * @param mixed $value
161      * @param integer $token
162      * @return boolean
163      */
164     public function isA($value, $token)
165     {
166         return $this->getType($value) === $token;
167     }
168
169     /**
170      * Moves the lookahead token forward.
171      *
172      * @return array | null The next token or NULL if there are no more tokens ahead.
173      */
174     public function peek()
175     {
176         if (isset($this->tokens[$this->position + $this->peek])) {
177             return $this->tokens[$this->position + $this->peek++];
178         } else {
179             return null;
180         }
181     }
182
183     /**
184      * Peeks at the next token, returns it and immediately resets the peek.
185      *
186      * @return array|null The next token or NULL if there are no more tokens ahead.
187      */
188     public function glimpse()
189     {
190         $peek = $this->peek();
191         $this->peek = 0;
192         return $peek;
193     }
194
195     /**
196      * Scans the input string for tokens.
197      *
198      * @param string $input a query string
199      */
200     protected function scan($input)
201     {
202         static $regex;
203
204         if ( ! isset($regex)) {
205             $regex = '/(' . implode(')|(', $this->getCatchablePatterns()) . ')|'
206                    . implode('|', $this->getNonCatchablePatterns()) . '/i';
207         }
208
209         $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
210         $matches = preg_split($regex, $input, -1, $flags);
211
212         foreach ($matches as $match) {
213             // Must remain before 'value' assignment since it can change content
214             $type = $this->getType($match[0]);
215
216             $this->tokens[] = array(
217                 'value' => $match[0],
218                 'type'  => $type,
219                 'position' => $match[1],
220             );
221         }
222     }
223
224     /**
225      * Gets the literal for a given token.
226      *
227      * @param integer $token
228      * @return string
229      */
230     public function getLiteral($token)
231     {
232         $className = get_class($this);
233         $reflClass = new \ReflectionClass($className);
234         $constants = $reflClass->getConstants();
235
236         foreach ($constants as $name => $value) {
237             if ($value === $token) {
238                 return $className . '::' . $name;
239             }
240         }
241
242         return $token;
243     }
244
245     /**
246      * Lexical catchable patterns.
247      *
248      * @return array
249      */
250     abstract protected function getCatchablePatterns();
251
252     /**
253      * Lexical non-catchable patterns.
254      *
255      * @return array
256      */
257     abstract protected function getNonCatchablePatterns();
258
259     /**
260      * Retrieve token type. Also processes the token value if necessary.
261      *
262      * @param string $value
263      * @return integer
264      */
265     abstract protected function getType(&$value);
266 }