Skip to content

Commit

Permalink
Create TokenIterator
Browse files Browse the repository at this point in the history
  • Loading branch information
koriym committed Nov 12, 2023
1 parent 5034104 commit 97fea1c
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 13 deletions.
23 changes: 10 additions & 13 deletions src/AopCodeGen.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@

namespace Ray\Aop;

use ArrayIterator;
use Ray\Aop\Exception\InvalidSourceClassException;
use ReflectionClass;

use function file_exists;
use function file_get_contents;
use function is_array;
use function sprintf;
use function token_get_all;

use const PHP_VERSION_ID;
Expand All @@ -36,36 +33,36 @@ public function generate(ReflectionClass $sourceClass, BindInterface $bind, stri
}

$code = (string) file_get_contents($fileName);

// array<int, array{int, string, int}|string> in phpstorm
// list<array{0: int, 1: string, 2: int}|string> in psalm
/** @var array<int, array{int, string, int}|string> $tokens */
$tokens = token_get_all($code);

$inClass = false;
$className = '';
$newCode = new GeneratedCode(new MethodSignatureString(PHP_VERSION_ID));
$iterator = new ArrayIterator($tokens);
$iterator = new TokenIterator($tokens);

for ($iterator->rewind(); $iterator->valid(); $iterator->next()) {
$token = $iterator->current();
[$id, $text] = is_array($token) ? $token : [null, $token];

[$id, $text] = $iterator->getToken();
$isClassKeyword = $id === T_CLASS;
if ($isClassKeyword) {
$inClass = true;
$newCode->add($text . ' ');
$newCode->add($text);
continue;
}

$isClassName = $inClass && $id === T_STRING && empty($className);
if ($isClassName) {
$className = $text;
$newClassName = $className . $postfix;
$newCode->add($newClassName . ' extends ' . $text . ' ');
$newCode->addClassName($className, $postfix);
continue;
}

$isExtendsKeyword = $id === T_EXTENDS;
if ($isExtendsKeyword) {
$iterator->next(); // Skip extends keyword
$iterator->next(); // Skip parent class name
$iterator->next(); // Skip space
$iterator->skipExtends();
continue;
}

Expand Down
6 changes: 6 additions & 0 deletions src/GeneratedCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ public function insert(string $code): void
$this->code = (string) preg_replace('/}\s*$/', $replacement, $this->code);
}

public function addClassName(string $className, string $postfix): void
{
$newClassName = $className . $postfix;
$this->add($newClassName . ' extends ' . $className . ' ');
}

public function implementsInterface(string $interfaceName): void
{
$pattern = '/(class\s+[\w\s]+extends\s+\w+)(?:\s+implements\s+(.+))?/';
Expand Down
33 changes: 33 additions & 0 deletions src/TokenIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Ray\Aop;

use ArrayIterator;

use function is_array;

/**
* @template TKey of array-key
* @template TValue of array{int, string, int}|string
* @template-extends ArrayIterator<TKey, TValue>
*/
final class TokenIterator extends ArrayIterator
{
/** @return array{int, string} */
public function getToken(): array
{
/** @var array{int, string, int}|string $token */
$token = $this->current();

return is_array($token) ? [$token[0], $token[1]] : [0, $token];
}

public function skipExtends(): void
{
$this->next(); // Skip extends keyword
$this->next(); // Skip parent class name
$this->next(); // Skip space
}
}

0 comments on commit 97fea1c

Please sign in to comment.