source: pro-violet-viettel/sourcecode/application/libraries/Doctrine/Common/Lexer.php @ 345

Last change on this file since 345 was 345, checked in by quyenla, 11 years ago

collaborator page

File size: 7.1 KB
Line 
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 LGPL. For more information, see
17 * <http://www.doctrine-project.org>.
18 */
19
20namespace 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 */
31abstract 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 $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}
Note: See TracBrowser for help on using the repository browser.