Skip to content

Commit

Permalink
Add offsets to type tokenisation
Browse files Browse the repository at this point in the history
Ref #1832
  • Loading branch information
muglug committed Jun 23, 2019
1 parent 78588ce commit 31c8a2e
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 140 deletions.
4 changes: 2 additions & 2 deletions examples/plugins/ClassUnqualifier.php
Expand Up @@ -35,10 +35,10 @@ public static function afterClassLikeExistenceCheck(
$type_tokens = Type::tokenize($candidate_type, false);

foreach ($type_tokens as &$type_token) {
if ($type_token === ('\\' . $fq_class_name)
if ($type_token[0] === ('\\' . $fq_class_name)
&& isset($aliases[strtolower($fq_class_name)])
) {
$type_token = $aliases[strtolower($fq_class_name)];
$type_token[0] = $aliases[strtolower($fq_class_name)];
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/Psalm/Internal/Analyzer/CommentAnalyzer.php
Expand Up @@ -24,7 +24,7 @@ class CommentAnalyzer

/**
* @param array<string, array<string, array{Type\Union}>>|null $template_type_map
* @param array<string, array<int, string>> $type_aliases
* @param array<string, array<int, array{0: string, 1: int}>> $type_aliases
*
* @throws DocblockParseException if there was a problem parsing the docblock
*
Expand Down Expand Up @@ -115,7 +115,7 @@ public static function getTypeFromComment(
$defined_type = Type::parseTokens($var_type_tokens, null, $template_type_map ?: []);
} catch (TypeParseTreeException $e) {
throw new DocblockParseException(
implode('', $var_type_tokens) .
$line_parts[0] .
' is not a valid type' .
' (from ' .
$source->getFilePath() .
Expand Down Expand Up @@ -159,11 +159,11 @@ public static function getTypeFromComment(

/**
* @param Aliases $aliases
* @param array<string, array<int, string>> $type_aliases
* @param array<string, array<int, array{0: string, 1: int}>> $type_aliases
*
* @throws DocblockParseException if there was a problem parsing the docblock
*
* @return array<string, array<int, string>>
* @return array<string, array<int, array{0: string, 1: int}>>
*/
public static function getTypeAliasesFromComment(
PhpParser\Comment\Doc $comment,
Expand All @@ -186,11 +186,11 @@ public static function getTypeAliasesFromComment(
/**
* @param array<string> $type_alias_comment_lines
* @param Aliases $aliases
* @param array<string, array<int, string>> $type_aliases
* @param array<string, array<int, array{0: string, 1: int}>> $type_aliases
*
* @throws DocblockParseException if there was a problem parsing the docblock
*
* @return array<string, array<int, string>>
* @return array<string, array<int, array{0: string, 1: int}>>
*/
private static function getTypeAliasesFromCommentLines(
array $type_alias_comment_lines,
Expand Down
Expand Up @@ -753,12 +753,12 @@ public static function analyzeInstance(
$type_tokens = Type::tokenize((string)$class_property_type);

foreach ($type_tokens as &$type_token) {
if (isset($class_template_params[$type_token])) {
$type_token = $class_template_params[$type_token];
if (isset($class_template_params[$type_token[0]])) {
$type_token[0] = $class_template_params[$type_token[0]];
}
}

$class_property_type = Type::parseString(implode('', $type_tokens));
$class_property_type = Type::parseTokens($type_tokens);
}
}
}
Expand Down
103 changes: 53 additions & 50 deletions src/Psalm/Internal/Type/ParseTree.php
Expand Up @@ -39,7 +39,7 @@ public function __destruct()
/**
* Create a parse tree from a tokenised type
*
* @param array<int, string> $type_tokens
* @param array<int, array{0: string, 1: int}> $type_tokens
*
* @return self
*/
Expand All @@ -55,38 +55,38 @@ public static function createFromTokens(array $type_tokens)
$type_token = $type_tokens[$i];
$next_token = $i + 1 < $c ? $type_tokens[$i + 1] : null;

switch ($type_token) {
switch ($type_token[0]) {
case '<':
case '{':
case ']':
throw new TypeParseTreeException('Unexpected token ' . $type_token);
throw new TypeParseTreeException('Unexpected token ' . $type_token[0]);

case '[':
if ($current_leaf instanceof ParseTree\Root) {
throw new TypeParseTreeException('Unexpected token ' . $type_token);
throw new TypeParseTreeException('Unexpected token ' . $type_token[0]);
}

$indexed_access = false;

if ($next_token !== ']') {
if (!$next_token || $next_token[0] !== ']') {
$next_next_token = $i + 2 < $c ? $type_tokens[$i + 2] : null;

if ($next_next_token === ']') {
if ($next_next_token !== null && $next_next_token[0] === ']') {
$indexed_access = true;
++$i;
} else {
throw new TypeParseTreeException('Unexpected token ' . $type_token);
throw new TypeParseTreeException('Unexpected token ' . $type_token[0]);
}
}

$current_parent = $current_leaf->parent;

if ($indexed_access) {
if (!$next_token) {
throw new TypeParseTreeException('Unexpected token ' . $next_token);
if ($next_token === null) {
throw new TypeParseTreeException('Unexpected token ' . $type_token[0]);
}

$new_parent_leaf = new ParseTree\IndexedAccessTree($next_token, $current_parent);
$new_parent_leaf = new ParseTree\IndexedAccessTree($next_token[0], $current_parent);
} else {
$new_parent_leaf = new ParseTree\GenericTree('array', $current_parent);
}
Expand Down Expand Up @@ -129,7 +129,10 @@ public static function createFromTokens(array $type_tokens)
break;

case ')':
if ($last_token === '(' && $current_leaf instanceof ParseTree\CallableTree) {
if ($last_token !== null
&& $last_token[0] === '('
&& $current_leaf instanceof ParseTree\CallableTree
) {
break;
}

Expand Down Expand Up @@ -169,7 +172,7 @@ public static function createFromTokens(array $type_tokens)

case ',':
if ($current_leaf instanceof ParseTree\Root) {
throw new TypeParseTreeException('Unexpected token ' . $type_token);
throw new TypeParseTreeException('Unexpected token ' . $type_token[0]);
}

if (!$current_leaf->parent) {
Expand Down Expand Up @@ -205,13 +208,13 @@ public static function createFromTokens(array $type_tokens)

case '...':
case '=':
if ($last_token === '...' || $last_token === '=') {
if ($last_token && ($last_token[0] === '...' || $last_token[0] === '=')) {
throw new TypeParseTreeException('Cannot have duplicate tokens');
}

$current_parent = $current_leaf->parent;

if ($current_leaf instanceof ParseTree\MethodTree && $type_token === '...') {
if ($current_leaf instanceof ParseTree\MethodTree && $type_token[0] === '...') {
self::createMethodParam($current_leaf, $current_leaf, $type_tokens, $type_token, $i);
break;
}
Expand All @@ -225,16 +228,16 @@ public static function createFromTokens(array $type_tokens)
}

if (!$current_parent || !$current_leaf) {
throw new TypeParseTreeException('Unexpected token ' . $type_token);
throw new TypeParseTreeException('Unexpected token ' . $type_token[0]);
}

if ($current_parent instanceof ParseTree\CallableParamTree) {
throw new TypeParseTreeException('Cannot have variadic param with a default');
}

$new_leaf = new ParseTree\CallableParamTree($current_parent);
$new_leaf->has_default = $type_token === '=';
$new_leaf->variadic = $type_token === '...';
$new_leaf->has_default = $type_token[0] === '=';
$new_leaf->variadic = $type_token[0] === '...';
$new_leaf->children = [$current_leaf];

$current_leaf->parent = $new_leaf;
Expand All @@ -248,7 +251,7 @@ public static function createFromTokens(array $type_tokens)

case ':':
if ($current_leaf instanceof ParseTree\Root) {
throw new TypeParseTreeException('Unexpected token ' . $type_token);
throw new TypeParseTreeException('Unexpected token ' . $type_token[0]);
}

$current_parent = $current_leaf->parent;
Expand Down Expand Up @@ -302,7 +305,7 @@ public static function createFromTokens(array $type_tokens)
}

$new_parent_leaf = new ParseTree\ObjectLikePropertyTree($current_leaf->value, $current_parent);
$new_parent_leaf->possibly_undefined = $last_token === '?';
$new_parent_leaf->possibly_undefined = $last_token !== null && $last_token[0] === '?';
$current_leaf->parent = $new_parent_leaf;

array_pop($current_parent->children);
Expand Down Expand Up @@ -335,7 +338,7 @@ public static function createFromTokens(array $type_tokens)
break;

case '?':
if ($next_token !== ':') {
if ($next_token === null || $next_token[0] !== ':') {
$new_parent = !$current_leaf instanceof ParseTree\Root ? $current_leaf : null;

$new_leaf = new ParseTree\NullableTree(
Expand All @@ -358,7 +361,7 @@ public static function createFromTokens(array $type_tokens)

case '|':
if ($current_leaf instanceof ParseTree\Root) {
throw new TypeParseTreeException('Unexpected token ' . $type_token);
throw new TypeParseTreeException('Unexpected token ' . $type_token[0]);
}

$current_parent = $current_leaf->parent;
Expand All @@ -374,7 +377,7 @@ public static function createFromTokens(array $type_tokens)
}

if ($current_leaf instanceof ParseTree\UnionTree) {
throw new TypeParseTreeException('Unexpected token ' . $type_token);
throw new TypeParseTreeException('Unexpected token ' . $type_token[0]);
}

if ($current_parent && $current_parent instanceof ParseTree\UnionTree) {
Expand Down Expand Up @@ -439,40 +442,40 @@ public static function createFromTokens(array $type_tokens)
default:
$new_parent = !$current_leaf instanceof ParseTree\Root ? $current_leaf : null;

if ($current_leaf instanceof ParseTree\MethodTree && $type_token[0] === '$') {
if ($current_leaf instanceof ParseTree\MethodTree && $type_token[0][0] === '$') {
self::createMethodParam($current_leaf, $current_leaf, $type_tokens, $type_token, $i);
break;
}

switch ($next_token) {
switch ($next_token[0] ?? null) {
case '<':
$new_leaf = new ParseTree\GenericTree(
$type_token,
$type_token[0],
$new_parent
);
++$i;
break;

case '{':
$new_leaf = new ParseTree\ObjectLikeTree(
$type_token,
$type_token[0],
$new_parent
);
++$i;
break;

case '(':
if (in_array(strtolower($type_token), ['closure', 'callable', '\closure'])) {
if (in_array(strtolower($type_token[0]), ['closure', 'callable', '\closure'])) {
$new_leaf = new ParseTree\CallableTree(
$type_token,
$type_token[0],
$new_parent
);
} elseif ($type_token !== 'array'
&& $type_token[0] !== '\\'
} elseif ($type_token[0] !== 'array'
&& $type_token[0][0] !== '\\'
&& $current_leaf instanceof ParseTree\Root
) {
$new_leaf = new ParseTree\MethodTree(
$type_token,
$type_token[0],
$new_parent
);
} else {
Expand All @@ -488,16 +491,16 @@ public static function createFromTokens(array $type_tokens)
$nexter_token = $i + 2 < $c ? $type_tokens[$i + 2] : null;

if (!$nexter_token
|| (!preg_match('/^[A-Z_][A-Z_0-9]*$/', $nexter_token)
&& strtolower($nexter_token) !== 'class')
|| (!preg_match('/^[A-Z_][A-Z_0-9]*$/', $nexter_token[0])
&& strtolower($nexter_token[0]) !== 'class')
) {
throw new TypeParseTreeException(
'Invalid class constant ' . $nexter_token
'Invalid class constant'
);
}

$new_leaf = new ParseTree\Value(
$type_token . '::' . $nexter_token,
$type_token[0] . '::' . $nexter_token[0],
$new_parent
);

Expand All @@ -506,12 +509,12 @@ public static function createFromTokens(array $type_tokens)
break;

default:
if ($type_token === '$this') {
$type_token = 'static';
if ($type_token[0] === '$this') {
$type_token[0] = 'static';
}

$new_leaf = new ParseTree\Value(
$type_token,
$type_token[0],
$new_parent
);
break;
Expand Down Expand Up @@ -547,8 +550,8 @@ public static function createFromTokens(array $type_tokens)
/**
* @param ParseTree &$current_leaf
* @param ParseTree $current_parent
* @param array<int, string> $type_tokens
* @param string $current_token
* @param array<int, array{0: string, 1: int}> $type_tokens
* @param array{0: string, 1: int} $current_token
* @param int &$i
*
* @return void
Expand All @@ -557,7 +560,7 @@ private static function createMethodParam(
ParseTree &$current_leaf,
ParseTree $current_parent,
array $type_tokens,
$current_token,
array $current_token,
&$i
) {
$byref = false;
Expand All @@ -567,23 +570,23 @@ private static function createMethodParam(

$c = count($type_tokens);

if ($current_token === '&') {
if ($current_token[0] === '&') {
throw new TypeParseTreeException('Magic args cannot be passed by reference');
}

if ($current_token === '...') {
if ($current_token[0] === '...') {
$variadic = true;

++$i;
$current_token = $i < $c ? $type_tokens[$i] : null;
}

if (!$current_token || $current_token[0] !== '$') {
throw new TypeParseTreeException('Unexpected token after space ' . $current_token);
if (!$current_token || $current_token[0][0] !== '$') {
throw new TypeParseTreeException('Unexpected token after space');
}

$new_parent_leaf = new ParseTree\MethodParamTree(
$current_token,
$current_token[0],
$byref,
$variadic,
$current_parent
Expand All @@ -592,18 +595,18 @@ private static function createMethodParam(
for ($j = $i + 1; $j < $c; ++$j) {
$ahead_type_token = $type_tokens[$j];

if ($ahead_type_token === ','
|| ($ahead_type_token === ')' && $type_tokens[$j - 1] !== '(')
if ($ahead_type_token[0] === ','
|| ($ahead_type_token[0] === ')' && $type_tokens[$j - 1][0] !== '(')
) {
$i = $j - 1;
break;
}

if ($has_default) {
$default .= $ahead_type_token;
$default .= $ahead_type_token[0];
}

if ($ahead_type_token === '=') {
if ($ahead_type_token[0] === '=') {
$has_default = true;
continue;
}
Expand Down

0 comments on commit 31c8a2e

Please sign in to comment.