1<?php declare(strict_types=1);
2
3namespace PhpParser\Lexer\TokenEmulator;
4
5abstract class KeywordEmulator extends TokenEmulator
6{
7    abstract function getKeywordString(): string;
8    abstract function getKeywordToken(): int;
9
10    public function isEmulationNeeded(string $code): bool
11    {
12        return strpos(strtolower($code), $this->getKeywordString()) !== false;
13    }
14
15    public function emulate(string $code, array $tokens): array
16    {
17        $keywordString = $this->getKeywordString();
18        foreach ($tokens as $i => $token) {
19            if ($token[0] === T_STRING && strtolower($token[1]) === $keywordString) {
20                $previousNonSpaceToken = $this->getPreviousNonSpaceToken($tokens, $i);
21                if ($previousNonSpaceToken !== null && $previousNonSpaceToken[0] === \T_OBJECT_OPERATOR) {
22                    continue;
23                }
24
25                $tokens[$i][0] = $this->getKeywordToken();
26            }
27        }
28
29        return $tokens;
30    }
31
32    /**
33     * @param mixed[] $tokens
34     * @return mixed[]|null
35     */
36    private function getPreviousNonSpaceToken(array $tokens, int $start)
37    {
38        for ($i = $start - 1; $i >= 0; --$i) {
39            if ($tokens[$i][0] === T_WHITESPACE) {
40                continue;
41            }
42
43            return $tokens[$i];
44        }
45
46        return null;
47    }
48
49    public function reverseEmulate(string $code, array $tokens): array
50    {
51        $keywordToken = $this->getKeywordToken();
52        foreach ($tokens as $i => $token) {
53            if ($token[0] === $keywordToken) {
54                $tokens[$i][0] = \T_STRING;
55            }
56        }
57
58        return $tokens;
59    }
60}
61