2009-07-07 00:34:54 +04:00
|
|
|
<?php
|
2009-07-08 19:25:41 +04:00
|
|
|
/*
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* This software consists of voluntary contributions made by many individuals
|
|
|
|
* and is licensed under the LGPL. For more information, see
|
|
|
|
* <http://www.doctrine-project.org>.
|
|
|
|
*/
|
2009-07-07 00:34:54 +04:00
|
|
|
|
|
|
|
namespace Doctrine\Common\Annotations;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A simple parser for docblock annotations.
|
|
|
|
*
|
2009-08-08 01:47:21 +04:00
|
|
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
|
|
|
* @link www.doctrine-project.org
|
|
|
|
* @since 2.0
|
|
|
|
* @version $Revision: 3938 $
|
|
|
|
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
|
|
|
* @author Jonathan Wage <jonwage@gmail.com>
|
|
|
|
* @author Roman Borschel <roman@code-factory.org>
|
2009-10-30 03:36:21 +03:00
|
|
|
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
|
|
|
class Parser
|
|
|
|
{
|
2009-08-08 01:47:21 +04:00
|
|
|
/**
|
|
|
|
* Tags that are stripped prior to parsing in order to reduce parsing overhead.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
2009-07-07 00:34:54 +04:00
|
|
|
private static $_strippedInlineTags = array(
|
|
|
|
"{@example", "{@id", "{@internal", "{@inheritdoc",
|
|
|
|
"{@link", "{@source", "{@toc", "{@tutorial", "*/"
|
|
|
|
);
|
|
|
|
|
2009-08-08 01:47:21 +04:00
|
|
|
/**
|
|
|
|
* The lexer.
|
|
|
|
*
|
|
|
|
* @var Doctrine\Common\Annotations\Lexer
|
|
|
|
*/
|
2009-07-07 00:34:54 +04:00
|
|
|
private $_lexer;
|
2009-08-08 01:47:21 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Flag to control if the current Annotation is nested or not.
|
|
|
|
*
|
|
|
|
* @var boolean
|
|
|
|
*/
|
2009-07-07 00:34:54 +04:00
|
|
|
private $_isNestedAnnotation = false;
|
2009-08-08 01:47:21 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Default namespace for Annotations.
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
2009-07-07 00:34:54 +04:00
|
|
|
private $_defaultAnnotationNamespace = '';
|
2009-08-08 01:47:21 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Hashmap to store namespace aliases.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
2009-07-07 00:34:54 +04:00
|
|
|
private $_namespaceAliases = array();
|
2009-10-30 23:58:06 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
private $_context = '';
|
2009-07-07 00:34:54 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a new AnnotationParser.
|
2009-08-08 01:47:21 +04:00
|
|
|
*
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
|
|
|
public function __construct()
|
|
|
|
{
|
|
|
|
$this->_lexer = new Lexer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the default namespace that is assumed for an annotation that does not
|
|
|
|
* define a namespace prefix.
|
|
|
|
*
|
|
|
|
* @param $defaultNamespace
|
|
|
|
*/
|
|
|
|
public function setDefaultAnnotationNamespace($defaultNamespace)
|
|
|
|
{
|
|
|
|
$this->_defaultAnnotationNamespace = $defaultNamespace;
|
|
|
|
}
|
|
|
|
|
2009-07-07 15:25:58 +04:00
|
|
|
/**
|
|
|
|
* Sets an alias for an annotation namespace.
|
|
|
|
*
|
|
|
|
* @param $namespace
|
|
|
|
* @param $alias
|
|
|
|
*/
|
2009-07-07 00:34:54 +04:00
|
|
|
public function setAnnotationNamespaceAlias($namespace, $alias)
|
|
|
|
{
|
|
|
|
$this->_namespaceAliases[$alias] = $namespace;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses the given docblock string for annotations.
|
|
|
|
*
|
2009-10-30 23:58:06 +03:00
|
|
|
* @param string $docBlockString
|
|
|
|
* @param string $context
|
2009-08-08 01:47:21 +04:00
|
|
|
* @return array Array of Annotations. If no annotations are found, an empty array is returned.
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
2009-10-30 23:58:06 +03:00
|
|
|
public function parse($docBlockString, $context='')
|
2009-07-07 00:34:54 +04:00
|
|
|
{
|
2009-10-30 23:58:06 +03:00
|
|
|
$this->_context = $context;
|
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
// Strip out some known inline tags.
|
|
|
|
$input = str_replace(self::$_strippedInlineTags, '', $docBlockString);
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
// Cut of the beginning of the input until the first '@'.
|
|
|
|
$input = substr($input, strpos($input, '@'));
|
|
|
|
|
|
|
|
$this->_lexer->reset();
|
|
|
|
$this->_lexer->setInput(trim($input, '* /'));
|
|
|
|
$this->_lexer->moveNext();
|
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
if ($this->_lexer->isNextToken(Lexer::T_AT)) {
|
2009-07-08 19:25:41 +04:00
|
|
|
return $this->Annotations();
|
|
|
|
}
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-08 19:25:41 +04:00
|
|
|
return array();
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attempts to match the given token with the current lookahead token.
|
2009-08-08 01:47:21 +04:00
|
|
|
* If they match, updates the lookahead token; otherwise raises a syntax error.
|
2009-07-07 00:34:54 +04:00
|
|
|
*
|
|
|
|
* @param int|string token type or value
|
2009-08-08 01:47:21 +04:00
|
|
|
* @return bool True if tokens match; false otherwise.
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
|
|
|
public function match($token)
|
|
|
|
{
|
2009-11-04 04:52:40 +03:00
|
|
|
if ( ! ($this->_lexer->lookahead['type'] === $token)) {
|
|
|
|
$this->syntaxError($this->_lexer->getLiteral($token));
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
$this->_lexer->moveNext();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-08-08 01:47:21 +04:00
|
|
|
* Generates a new syntax error.
|
2009-07-07 00:34:54 +04:00
|
|
|
*
|
2009-08-08 01:47:21 +04:00
|
|
|
* @param string $expected Expected string.
|
|
|
|
* @param array $token Optional token.
|
2009-07-07 00:34:54 +04:00
|
|
|
* @throws Exception
|
|
|
|
*/
|
2009-08-08 01:47:21 +04:00
|
|
|
private function syntaxError($expected, $token = null)
|
2009-07-07 00:34:54 +04:00
|
|
|
{
|
2009-08-08 01:47:21 +04:00
|
|
|
if ($token === null) {
|
|
|
|
$token = $this->_lexer->lookahead;
|
|
|
|
}
|
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
$message = "Expected {$expected}, got ";
|
2009-08-08 01:47:21 +04:00
|
|
|
|
|
|
|
if ($this->_lexer->lookahead === null) {
|
2009-10-30 23:58:06 +03:00
|
|
|
$message .= 'end of string';
|
2009-08-08 01:47:21 +04:00
|
|
|
} else {
|
2009-10-30 23:58:06 +03:00
|
|
|
$message .= "'{$token['value']}' at position {$token['position']}";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(strlen($this->_context)) {
|
|
|
|
$message .= ' in '.$this->_context;
|
2009-08-08 01:47:21 +04:00
|
|
|
}
|
2009-10-30 23:58:06 +03:00
|
|
|
$message .= '.';
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-08-09 03:16:13 +04:00
|
|
|
throw AnnotationException::syntaxError($message);
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-08-08 01:47:21 +04:00
|
|
|
* Annotations ::= Annotation {[ "*" ]* [Annotation]}*
|
|
|
|
*
|
|
|
|
* @return array
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
|
|
|
public function Annotations()
|
|
|
|
{
|
|
|
|
$this->_isNestedAnnotation = false;
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
$annotations = array();
|
|
|
|
$annot = $this->Annotation();
|
2009-08-08 01:47:21 +04:00
|
|
|
|
|
|
|
if ($annot !== false) {
|
2009-07-07 00:34:54 +04:00
|
|
|
$annotations[get_class($annot)] = $annot;
|
|
|
|
}
|
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
while ($this->_lexer->lookahead !== null && $this->_lexer->isNextToken(Lexer::T_AT)) {
|
2009-08-08 01:47:21 +04:00
|
|
|
$this->_isNestedAnnotation = false;
|
|
|
|
|
|
|
|
$annot = $this->Annotation();
|
|
|
|
|
|
|
|
if ($annot !== false) {
|
|
|
|
$annotations[get_class($annot)] = $annot;
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $annotations;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-10-17 06:09:02 +04:00
|
|
|
* Annotation ::= "@" AnnotationName ["(" [Values] ")"]
|
2010-02-24 17:33:12 +03:00
|
|
|
* AnnotationName ::= QualifiedName | SimpleName | AliasedName
|
2009-08-08 01:47:21 +04:00
|
|
|
* QualifiedName ::= NameSpacePart "\" {NameSpacePart "\"}* SimpleName
|
2010-02-24 17:33:12 +03:00
|
|
|
* AliasedName ::= Alias ":" SimpleName
|
2009-08-08 01:47:21 +04:00
|
|
|
* NameSpacePart ::= identifier
|
|
|
|
* SimpleName ::= identifier
|
2010-02-24 17:33:12 +03:00
|
|
|
* Alias ::= identifier
|
2009-08-08 01:47:21 +04:00
|
|
|
*
|
|
|
|
* @return mixed False if it is not a valid Annotation; instance of Annotation subclass otherwise.
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
|
|
|
public function Annotation()
|
|
|
|
{
|
|
|
|
$values = array();
|
|
|
|
$nameParts = array();
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
$this->match(Lexer::T_AT);
|
2009-07-07 00:34:54 +04:00
|
|
|
$this->match(Lexer::T_IDENTIFIER);
|
|
|
|
$nameParts[] = $this->_lexer->token['value'];
|
2010-02-24 17:33:12 +03:00
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
while ($this->_lexer->isNextToken(Lexer::T_NAMESPACE_SEPARATOR)) {
|
|
|
|
$this->match(Lexer::T_NAMESPACE_SEPARATOR);
|
2009-07-07 00:34:54 +04:00
|
|
|
$this->match(Lexer::T_IDENTIFIER);
|
|
|
|
$nameParts[] = $this->_lexer->token['value'];
|
|
|
|
}
|
|
|
|
|
2009-08-08 01:47:21 +04:00
|
|
|
// Effectively pick the name of class (append default NS if none, grab from NS alias, etc)
|
2009-07-07 00:34:54 +04:00
|
|
|
if (count($nameParts) == 1) {
|
2010-02-24 17:33:12 +03:00
|
|
|
if (strpos($nameParts[0], ':')) {
|
|
|
|
list ($alias, $simpleName) = explode(':', $nameParts[0]);
|
|
|
|
$name = $this->_namespaceAliases[$alias] . $simpleName;
|
|
|
|
} else {
|
|
|
|
$name = $this->_defaultAnnotationNamespace . $nameParts[0];
|
|
|
|
}
|
2009-07-07 00:34:54 +04:00
|
|
|
} else {
|
2009-08-08 01:47:21 +04:00
|
|
|
$name = implode('\\', $nameParts);
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
|
|
|
|
2009-08-08 01:47:21 +04:00
|
|
|
// If it really an annotation class?
|
|
|
|
if (
|
2009-10-30 03:20:17 +03:00
|
|
|
(! $this->_isNestedAnnotation && $this->_lexer->lookahead != null &&
|
2009-11-04 04:52:40 +03:00
|
|
|
! $this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS) &&
|
|
|
|
! $this->_lexer->isNextToken(Lexer::T_AT)) ||
|
2009-11-03 21:30:21 +03:00
|
|
|
! class_exists($name, false) ||
|
2009-08-08 01:47:21 +04:00
|
|
|
! is_subclass_of($name, 'Doctrine\Common\Annotations\Annotation')
|
|
|
|
) {
|
2009-11-04 04:52:40 +03:00
|
|
|
$this->_lexer->skipUntil(Lexer::T_AT);
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-08-08 01:47:21 +04:00
|
|
|
// Next will be nested
|
|
|
|
$this->_isNestedAnnotation = true;
|
2009-07-07 00:34:54 +04:00
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
|
|
|
|
$this->match(Lexer::T_OPEN_PARENTHESIS);
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
if ( ! $this->_lexer->isNextToken(Lexer::T_CLOSE_PARENTHESIS)) {
|
2009-07-07 00:34:54 +04:00
|
|
|
$values = $this->Values();
|
|
|
|
}
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
$this->match(Lexer::T_CLOSE_PARENTHESIS);
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return new $name($values);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-10-17 06:09:02 +04:00
|
|
|
* Values ::= Array | Value {"," Value}*
|
2009-08-08 08:36:58 +04:00
|
|
|
*
|
|
|
|
* @return array
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
|
|
|
public function Values()
|
|
|
|
{
|
|
|
|
$values = array();
|
2009-08-17 21:58:16 +04:00
|
|
|
|
|
|
|
// Handle the case of a single array as value, i.e. @Foo({....})
|
2009-11-04 04:52:40 +03:00
|
|
|
if ($this->_lexer->isNextToken(Lexer::T_OPEN_CURLY_BRACES)) {
|
2009-08-17 21:58:16 +04:00
|
|
|
$values['value'] = $this->Value();
|
|
|
|
return $values;
|
|
|
|
}
|
|
|
|
|
2009-08-08 01:47:21 +04:00
|
|
|
$values[] = $this->Value();
|
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
|
|
|
|
$this->match(Lexer::T_COMMA);
|
2009-08-08 01:47:21 +04:00
|
|
|
$value = $this->Value();
|
|
|
|
|
|
|
|
if ( ! is_array($value)) {
|
2009-11-04 04:52:40 +03:00
|
|
|
$this->syntaxError('Value', $value);
|
2009-08-08 01:47:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
$values[] = $value;
|
|
|
|
}
|
2009-07-08 19:25:41 +04:00
|
|
|
|
2009-08-08 01:47:21 +04:00
|
|
|
foreach ($values as $k => $value) {
|
|
|
|
if (is_array($value) && is_string(key($value))) {
|
|
|
|
$key = key($value);
|
|
|
|
$values[$key] = $value[$key];
|
|
|
|
} else {
|
|
|
|
$values['value'] = $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
unset($values[$k]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $values;
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Value ::= PlainValue | FieldAssignment
|
2009-08-08 08:36:58 +04:00
|
|
|
*
|
|
|
|
* @return mixed
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
|
|
|
public function Value()
|
|
|
|
{
|
|
|
|
$peek = $this->_lexer->glimpse();
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
if ($peek['value'] === '=') {
|
|
|
|
return $this->FieldAssignment();
|
|
|
|
}
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
return $this->PlainValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-10-17 06:09:02 +04:00
|
|
|
* PlainValue ::= integer | string | float | boolean | Array | Annotation
|
2009-08-08 08:36:58 +04:00
|
|
|
*
|
|
|
|
* @return mixed
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
|
|
|
public function PlainValue()
|
|
|
|
{
|
2009-11-04 04:52:40 +03:00
|
|
|
if ($this->_lexer->isNextToken(Lexer::T_OPEN_CURLY_BRACES)) {
|
2009-08-08 01:47:21 +04:00
|
|
|
return $this->Arrayx();
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
if ($this->_lexer->isNextToken(Lexer::T_AT)) {
|
2009-07-07 00:34:54 +04:00
|
|
|
return $this->Annotation();
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ($this->_lexer->lookahead['type']) {
|
|
|
|
case Lexer::T_STRING:
|
|
|
|
$this->match(Lexer::T_STRING);
|
|
|
|
return $this->_lexer->token['value'];
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
case Lexer::T_INTEGER:
|
|
|
|
$this->match(Lexer::T_INTEGER);
|
|
|
|
return $this->_lexer->token['value'];
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
case Lexer::T_FLOAT:
|
|
|
|
$this->match(Lexer::T_FLOAT);
|
|
|
|
return $this->_lexer->token['value'];
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-08 19:25:41 +04:00
|
|
|
case Lexer::T_TRUE:
|
|
|
|
$this->match(Lexer::T_TRUE);
|
|
|
|
return true;
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-08 19:25:41 +04:00
|
|
|
case Lexer::T_FALSE:
|
|
|
|
$this->match(Lexer::T_FALSE);
|
|
|
|
return false;
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
default:
|
2009-10-30 03:36:21 +03:00
|
|
|
$this->syntaxError('PlainValue');
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-08-08 08:36:58 +04:00
|
|
|
* FieldAssignment ::= FieldName "=" PlainValue
|
|
|
|
* FieldName ::= identifier
|
|
|
|
*
|
|
|
|
* @return array
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
|
|
|
public function FieldAssignment()
|
|
|
|
{
|
|
|
|
$this->match(Lexer::T_IDENTIFIER);
|
|
|
|
$fieldName = $this->_lexer->token['value'];
|
2009-11-04 04:52:40 +03:00
|
|
|
$this->match(Lexer::T_EQUALS);
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
return array($fieldName => $this->PlainValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-08-08 01:47:21 +04:00
|
|
|
* Array ::= "{" ArrayEntry {"," ArrayEntry}* "}"
|
2009-08-08 08:36:58 +04:00
|
|
|
*
|
|
|
|
* @return array
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
2009-08-08 01:47:21 +04:00
|
|
|
public function Arrayx()
|
2009-07-07 00:34:54 +04:00
|
|
|
{
|
2009-08-08 08:36:58 +04:00
|
|
|
$array = $values = array();
|
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
$this->match(Lexer::T_OPEN_CURLY_BRACES);
|
2009-08-08 08:36:58 +04:00
|
|
|
$values[] = $this->ArrayEntry();
|
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
|
|
|
|
$this->match(Lexer::T_COMMA);
|
2009-08-08 08:36:58 +04:00
|
|
|
$values[] = $this->ArrayEntry();
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-11-04 04:52:40 +03:00
|
|
|
$this->match(Lexer::T_CLOSE_CURLY_BRACES);
|
2009-08-08 08:36:58 +04:00
|
|
|
|
|
|
|
foreach ($values as $value) {
|
|
|
|
$key = key($value);
|
|
|
|
|
|
|
|
if (is_string($key)) {
|
|
|
|
$array[$key] = $value[$key];
|
|
|
|
} else {
|
|
|
|
$array[] = $value[$key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
return $array;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ArrayEntry ::= Value | KeyValuePair
|
2009-10-17 06:09:02 +04:00
|
|
|
* KeyValuePair ::= Key "=" PlainValue
|
2009-07-07 00:34:54 +04:00
|
|
|
* Key ::= string | integer
|
2009-08-08 08:36:58 +04:00
|
|
|
*
|
|
|
|
* @return array
|
2009-07-07 00:34:54 +04:00
|
|
|
*/
|
2009-08-08 08:36:58 +04:00
|
|
|
public function ArrayEntry()
|
2009-07-07 00:34:54 +04:00
|
|
|
{
|
|
|
|
$peek = $this->_lexer->glimpse();
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
if ($peek['value'] == '=') {
|
2009-11-04 04:52:40 +03:00
|
|
|
$this->match(
|
|
|
|
$this->_lexer->isNextToken(Lexer::T_INTEGER) ? Lexer::T_INTEGER : Lexer::T_STRING
|
|
|
|
);
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-07-07 00:34:54 +04:00
|
|
|
$key = $this->_lexer->token['value'];
|
2009-11-04 04:52:40 +03:00
|
|
|
$this->match(Lexer::T_EQUALS);
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-10-17 06:09:02 +04:00
|
|
|
return array($key => $this->PlainValue());
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
2009-08-08 01:47:21 +04:00
|
|
|
|
2009-08-08 08:36:58 +04:00
|
|
|
return array($this->Value());
|
2009-07-07 00:34:54 +04:00
|
|
|
}
|
|
|
|
}
|