MIOLO20
Carregando...
Procurando...
Nenhuma entrada encontrada
Parser.php
Ir para a documentação deste ficheiro.
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
21
23
38class Parser
39{
45 private static $strippedTags = array(
46 "{@internal", "{@inheritdoc", "{@link"
47 );
48
54 private $lexer;
55
61 protected $isNestedAnnotation = false;
62
68 private $defaultAnnotationNamespace = '';
69
75 private $namespaceAliases = array();
76
80 private $context = '';
81
85 private $autoloadAnnotations = false;
86
90 private $annotationCreationFunction;
91
95 public function __construct(Lexer $lexer = null)
96 {
97 $this->lexer = $lexer ?: new Lexer;
98 }
99
105 public function getLexer()
106 {
107 return $this->lexer;
108 }
109
119 public function setAutoloadAnnotations($bool)
120 {
121 $this->autoloadAnnotations = $bool;
122 }
123
138 public function setAnnotationCreationFunction(Closure $func)
139 {
140 $this->annotationCreationFunction = $func;
141 }
142
149 public function getAutoloadAnnotations()
150 {
151 return $this->autoloadAnnotations;
152 }
153
160 public function setDefaultAnnotationNamespace($defaultNamespace)
161 {
162 $this->defaultAnnotationNamespace = $defaultNamespace;
163 }
164
171 public function setAnnotationNamespaceAlias($namespace, $alias)
172 {
173 $this->namespaceAliases[$alias] = $namespace;
174 }
175
181 public function getNamespaceAliases()
182 {
183 return $this->namespaceAliases;
184 }
185
193 public function parse($docBlockString, $context='')
194 {
195 $this->context = $context;
196
197 // Strip out some known inline tags.
198 $input = str_replace(self::$strippedTags, '', $docBlockString);
199
200 // Cut of the beginning of the input until the first '@'.
201 $input = substr($input, strpos($input, '@'));
202
203 $this->lexer->reset();
204 $this->lexer->setInput(trim($input, '* /'));
205 $this->lexer->moveNext();
206
207 if ($this->lexer->isNextToken(Lexer::T_AT)) {
208 return $this->Annotations();
209 }
210
211 return array();
212 }
213
221 public function match($token)
222 {
223 if ( ! ($this->lexer->lookahead['type'] === $token)) {
224 $this->syntaxError($this->lexer->getLiteral($token));
225 }
226 $this->lexer->moveNext();
227 }
228
236 private function syntaxError($expected, $token = null)
237 {
238 if ($token === null) {
239 $token = $this->lexer->lookahead;
240 }
241
242 $message = "Expected {$expected}, got ";
243
244 if ($this->lexer->lookahead === null) {
245 $message .= 'end of string';
246 } else {
247 $message .= "'{$token['value']}' at position {$token['position']}";
248 }
249
250 if (strlen($this->context)) {
251 $message .= ' in ' . $this->context;
252 }
253
254 $message .= '.';
255
256 throw AnnotationException::syntaxError($message);
257 }
258
264 public function Annotations()
265 {
266 $this->isNestedAnnotation = false;
267
268 $annotations = array();
269 $annot = $this->Annotation();
270
271 if ($annot !== false) {
272 $annotations[get_class($annot)] = $annot;
273 $this->lexer->skipUntil(Lexer::T_AT);
274 }
275
276 while ($this->lexer->lookahead !== null && $this->lexer->isNextToken(Lexer::T_AT)) {
277 $this->isNestedAnnotation = false;
278 $annot = $this->Annotation();
279
280 if ($annot !== false) {
281 $annotations[get_class($annot)] = $annot;
282 $this->lexer->skipUntil(Lexer::T_AT);
283 }
284 }
285
286 return $annotations;
287 }
288
300 public function Annotation()
301 {
302 $values = array();
303 $nameParts = array();
304
305 $this->match(Lexer::T_AT);
307 $nameParts[] = $this->lexer->token['value'];
308
309 while ($this->lexer->isNextToken(Lexer::T_NAMESPACE_SEPARATOR)) {
312 $nameParts[] = $this->lexer->token['value'];
313 }
314
315 // Effectively pick the name of the class (append default NS if none, grab from NS alias, etc)
316 if (strpos($nameParts[0], ':')) {
317 list ($alias, $nameParts[0]) = explode(':', $nameParts[0]);
318
319 // If the namespace alias doesnt exist, skip until next annotation
320 if ( ! isset($this->namespaceAliases[$alias])) {
321 $this->lexer->skipUntil(Lexer::T_AT);
322 return false;
323 }
324
325 $name = $this->namespaceAliases[$alias] . implode('\\', $nameParts);
326 } else if (count($nameParts) == 1) {
327 $name = $this->defaultAnnotationNamespace . $nameParts[0];
328 } else {
329 $name = implode('\\', $nameParts);
330 }
331
332 // Does the annotation class exist?
333 if ( ! class_exists($name, $this->autoloadAnnotations)) {
334 $this->lexer->skipUntil(Lexer::T_AT);
335 return false;
336 }
337
338 // Next will be nested
339 $this->isNestedAnnotation = true;
340
341 if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
343
344 if ( ! $this->lexer->isNextToken(Lexer::T_CLOSE_PARENTHESIS)) {
345 $values = $this->Values();
346 }
347
349 }
350
351 if ($this->annotationCreationFunction !== null) {
352 $func = $this->annotationCreationFunction;
353 $annot = $func($name, $values);
354 }
355
356 return isset($annot) ? $annot : $this->newAnnotation($name, $values);
357 }
358
364 public function Values()
365 {
366 $values = array();
367
368 // Handle the case of a single array as value, i.e. @Foo({....})
369 if ($this->lexer->isNextToken(Lexer::T_OPEN_CURLY_BRACES)) {
370 $values['value'] = $this->Value();
371 return $values;
372 }
373
374 $values[] = $this->Value();
375
376 while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
377 $this->match(Lexer::T_COMMA);
378 $value = $this->Value();
379
380 if ( ! is_array($value)) {
381 $this->syntaxError('Value', $value);
382 }
383
384 $values[] = $value;
385 }
386
387 foreach ($values as $k => $value) {
388 if (is_array($value) && is_string(key($value))) {
389 $key = key($value);
390 $values[$key] = $value[$key];
391 } else {
392 $values['value'] = $value;
393 }
394
395 unset($values[$k]);
396 }
397
398 return $values;
399 }
400
406 public function Value()
407 {
408 $peek = $this->lexer->glimpse();
409
410 if ($peek['value'] === '=') {
411 return $this->FieldAssignment();
412 }
413
414 return $this->PlainValue();
415 }
416
422 public function PlainValue()
423 {
424 if ($this->lexer->isNextToken(Lexer::T_OPEN_CURLY_BRACES)) {
425 return $this->Arrayx();
426 }
427
428 if ($this->lexer->isNextToken(Lexer::T_AT)) {
429 return $this->Annotation();
430 }
431
432 switch ($this->lexer->lookahead['type']) {
433 case Lexer::T_STRING:
434 $this->match(Lexer::T_STRING);
435 return $this->lexer->token['value'];
436
437 case Lexer::T_INTEGER:
438 $this->match(Lexer::T_INTEGER);
439 return $this->lexer->token['value'];
440
441 case Lexer::T_FLOAT:
442 $this->match(Lexer::T_FLOAT);
443 return $this->lexer->token['value'];
444
445 case Lexer::T_TRUE:
446 $this->match(Lexer::T_TRUE);
447 return true;
448
449 case Lexer::T_FALSE:
450 $this->match(Lexer::T_FALSE);
451 return false;
452
453 default:
454 $this->syntaxError('PlainValue');
455 }
456 }
457
464 public function FieldAssignment()
465 {
467 $fieldName = $this->lexer->token['value'];
468 $this->match(Lexer::T_EQUALS);
469
470 return array($fieldName => $this->PlainValue());
471 }
472
478 public function Arrayx()
479 {
480 $array = $values = array();
481
483 $values[] = $this->ArrayEntry();
484
485 while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
486 $this->match(Lexer::T_COMMA);
487 $values[] = $this->ArrayEntry();
488 }
489
491
492 foreach ($values as $value) {
493 list ($key, $val) = $value;
494
495 if ($key !== null) {
496 $array[$key] = $val;
497 } else {
498 $array[] = $val;
499 }
500 }
501
502 return $array;
503 }
504
512 public function ArrayEntry()
513 {
514 $peek = $this->lexer->glimpse();
515
516 if ($peek['value'] == '=') {
517 $this->match(
518 $this->lexer->isNextToken(Lexer::T_INTEGER) ? Lexer::T_INTEGER : Lexer::T_STRING
519 );
520
521 $key = $this->lexer->token['value'];
522 $this->match(Lexer::T_EQUALS);
523
524 return array($key, $this->PlainValue());
525 }
526
527 return array(null, $this->Value());
528 }
529
541 protected function newAnnotation($name, array $values)
542 {
543 return new $name($values);
544 }
545}
setAnnotationNamespaceAlias($namespace, $alias)
Definição Parser.php:171
parse($docBlockString, $context='')
Definição Parser.php:193
setAnnotationCreationFunction(Closure $func)
Definição Parser.php:138
setDefaultAnnotationNamespace($defaultNamespace)
Definição Parser.php:160
__construct(Lexer $lexer=null)
Definição Parser.php:95
newAnnotation($name, array $values)
Definição Parser.php:541