Skip to content

Commit

Permalink
entity/tokenizer: defer keyword & constant processing from lexing to …
Browse files Browse the repository at this point in the history
…parsing (fixed type error in Nette 3.0)
  • Loading branch information
hrach committed Jan 6, 2019
1 parent ef37580 commit 7286d46
Showing 1 changed file with 40 additions and 38 deletions.
78 changes: 40 additions & 38 deletions src/Entity/Reflection/ModifierParser.php
Expand Up @@ -14,6 +14,7 @@
use Nette\Tokenizer\Tokenizer;
use Nette\Utils\Reflection;
use Nextras\Orm\InvalidModifierDefinitionException;
use Nextras\Orm\InvalidStateException;
use ReflectionClass;


Expand Down Expand Up @@ -65,15 +66,15 @@ public function matchModifiers(string $input): array
*/
public function parse(string $string, ReflectionClass $reflectionClass): array
{
$iterator = $this->lex($string, $reflectionClass);
$iterator = $this->lex($string);
return [
$name = $this->processName($iterator),
$this->processArgs($iterator, $name, false),
$this->processArgs($iterator, $reflectionClass, $name, false),
];
}


private function lex(string $input, ReflectionClass $reflectionClass): Stream
private function lex(string $input): Stream
{
try {
$tokens = $this->tokenizer->tokenize($input)->tokens;
Expand All @@ -85,33 +86,7 @@ private function lex(string $input, ReflectionClass $reflectionClass): Stream
return $token->type !== self::TOKEN_WHITESPACE;
});
$tokens = array_values($tokens);

$expanded = [];
foreach ($tokens as $token) {
if ($token->type === self::TOKEN_STRING) {
$token->value = stripslashes(substr($token->value, 1, -1));
$expanded[] = $token;

} elseif ($token->type === self::TOKEN_KEYWORD) {
$values = $this->processKeyword($token->value, $reflectionClass);
if (is_array($values)) {
$count = count($values) - 1;
foreach ($values as $i => $value) {
$expanded[] = new Token($value, $token->type, $token->offset);
if ($i !== $count) {
$expanded[] = new Token(',', self::TOKEN_SEPARATOR, -1);
}
}
} else {
$expanded[] = new Token($values, $token->type, $token->offset);
}

} else {
$expanded[] = $token;
}
}

return new Stream($expanded);
return new Stream($tokens);
}


Expand All @@ -135,13 +110,12 @@ private function processName(Stream $iterator): string
}


private function processArgs(Stream $iterator, string $modifierName, bool $inArray)
private function processArgs(Stream $iterator, \ReflectionClass $reflectionClass, string $modifierName, bool $inArray)
{
$result = [];
while (($currentToken = $iterator->nextToken()) !== null) {
assert($currentToken !== null);
$type = $currentToken->type;
$value = $currentToken->value;

if ($type === self::TOKEN_RBRACKET) {
if ($inArray) {
Expand All @@ -160,25 +134,36 @@ private function processArgs(Stream $iterator, string $modifierName, bool $inArr
$nextTokenType = $nextToken ? $nextToken->type : null;

if ($nextTokenType === self::TOKEN_LBRACKET) {
$result[$value] = $this->processArgs($iterator, $modifierName, true);
$value = $this->processValue($currentToken, $reflectionClass);
assert(!is_array($value));
$result[$value] = $this->processArgs($iterator, $reflectionClass, $modifierName, true);
} elseif ($nextTokenType === self::TOKEN_STRING || $nextTokenType === self::TOKEN_KEYWORD) {
$result[$value] = $iterator->currentValue();
$value = $this->processValue($currentToken, $reflectionClass);
assert(!is_array($value));
$result[$value] = $this->processValue($nextToken, $reflectionClass);
} elseif ($nextTokenType !== null) {
throw new InvalidModifierDefinitionException("Modifier {{$modifierName}} has invalid token after =.");
}
} else {
$iterator->position--;
$result[] = $value;
$value = $this->processValue($currentToken, $reflectionClass);
if (is_array($value)) {
foreach ($value as $subValue) {
$result[] = $subValue;
}
} else {
$result[] = $value;
}
}
} elseif ($type === self::TOKEN_LBRACKET) {
$result[] = $this->processArgs($iterator, $modifierName, true);
$result[] = $this->processArgs($iterator, $reflectionClass, $modifierName, true);
} else {
throw new InvalidModifierDefinitionException("Modifier {{$modifierName}} has invalid token, expected string, keyword, or array.");
}

$iterator->position++;
$currentToken = $iterator->currentToken();
$type = $currentToken ? $currentToken->type : null;
$currentToken2 = $iterator->currentToken();
$type = $currentToken2 ? $currentToken2->type : null;
if ($type === self::TOKEN_RBRACKET && $inArray) {
return $result;
} elseif ($type !== null && $type !== self::TOKEN_SEPARATOR) {
Expand All @@ -194,6 +179,23 @@ private function processArgs(Stream $iterator, string $modifierName, bool $inArr
}


/**
* @return mixed
*/
private function processValue(Token $token, \ReflectionClass $reflectionClass)
{
if ($token->type === self::TOKEN_STRING) {
return stripslashes(substr($token->value, 1, -1));

} elseif ($token->type === self::TOKEN_KEYWORD) {
return $this->processKeyword($token->value, $reflectionClass);

} else {
throw new InvalidStateException();
}
}


private function processKeyword(string $value, ReflectionClass $reflectionClass)
{
if (strcasecmp($value, 'true') === 0) {
Expand Down

0 comments on commit 7286d46

Please sign in to comment.