Completed
Push — master ( f06ad0...9cb85d )
by Nico
06:26
created

BaseNode::getNode()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1
ccs 0
cts 0
cp 0
c 0
b 0
f 0
nc 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @license     http://opensource.org/licenses/mit-license.php MIT
7
 * @link        https://github.com/nicoSWD
8
 * @author      Nicolas Oelgart <[email protected]>
9
 */
10
namespace nicoSWD\Rules\TokenStream\Nodes;
11
12
use nicoSWD\Rules\TokenStream\TokenCollection;
13
use nicoSWD\Rules\Exceptions\ParserException;
14
use nicoSWD\Rules\Grammar\CallableFunction;
15
use nicoSWD\Rules\TokenStream\TokenStream;
16
use nicoSWD\Rules\Tokens\TokenType;
17
use nicoSWD\Rules\Tokens;
18
19
abstract class BaseNode
20
{
21
    /** @var TokenStream */
22
    protected $tokenStream;
23
24
    /** @var string */
25
    protected $methodName = '';
26
27
    /** @var int */
28
    protected $methodOffset = 0;
29
30 202
    public function __construct(TokenStream $tokenStream)
31
    {
32 202
        $this->tokenStream = $tokenStream;
33 202
    }
34
35
    abstract public function getNode(): Tokens\BaseToken;
36
37
    /**
38
     * Looks ahead, but does not move the pointer.
39
     */
40 190
    protected function hasMethodCall(): bool
41
    {
42 190
        $stackClone = $this->tokenStream->getStack()->getClone();
43
44 190
        while ($stackClone->valid()) {
45 190
            $stackClone->next();
46
47 190
            if (!$token = $stackClone->current()) {
48 98
                break;
49 188
            } elseif ($token->isWhitespace()) {
50 128
                continue;
51 188
            } elseif ($token instanceof Tokens\TokenMethod) {
52 108
                $this->methodName = $token->getValue();
53 108
                $this->methodOffset = $token->getOffset();
54
55 108
                return true;
56
            } else {
57 168
                break;
58
            }
59
        }
60
61 170
        return false;
62
    }
63
64 108
    public function getMethod(Tokens\BaseToken $token): CallableFunction
65
    {
66 108
        return $this->tokenStream->getMethod($this->getMethodName(), $token);
67
    }
68
69 108
    private function getMethodName(): string
70
    {
71
        do {
72 108
            $this->tokenStream->next();
73 108
        } while ($this->getCurrentNode()->getOffset() < $this->methodOffset);
74
75 108
        return trim(ltrim(rtrim($this->methodName, "\r\n("), '.'));
76
    }
77
78 26
    public function getFunction(): \Closure
79
    {
80 26
        return $this->tokenStream->getFunction($this->getFunctionName());
81
    }
82
83 26
    private function getFunctionName(): string
84
    {
85 26
        return rtrim($this->getCurrentNode()->getValue(), " \r\n(");
86
    }
87
88 52
    public function getArrayItems(): TokenCollection
89
    {
90 52
        return $this->getCommaSeparatedValues(TokenType::SQUARE_BRACKETS);
91
    }
92
93 124
    public function getArguments(): TokenCollection
94
    {
95 124
        return $this->getCommaSeparatedValues(TokenType::PARENTHESIS);
96
    }
97
98 198
    public function getCurrentNode()
99
    {
100 198
        return $this->tokenStream->getStack()->current();
101
    }
102
103 146
    private function getCommaSeparatedValues(int $stopAt): TokenCollection
104
    {
105 146
        $commaExpected = false;
106 146
        $items = new TokenCollection();
107
108
        do {
109 146
            $this->tokenStream->next();
110
111 146
            if (!$current = $this->tokenStream->current()) {
112 4
                throw new ParserException('Unexpected end of string');
113
            }
114
115 146
            if ($current->getType() === TokenType::VALUE) {
116 122
                if ($commaExpected) {
117 4
                    throw ParserException::unexpectedToken($current);
118
                }
119
120 122
                $commaExpected = true;
121 122
                $items->attach($current);
122 146
            } elseif ($current instanceof Tokens\TokenComma) {
123 60
                if (!$commaExpected) {
124 4
                    throw ParserException::unexpectedToken($current);
125
                }
126
127 60
                $commaExpected = false;
128 146
            } elseif ($current->getType() === $stopAt) {
129 130
                break;
130 64
            } elseif (!$current->isWhitespace()) {
131 4
                throw ParserException::unexpectedToken($current);
132
            }
133 122
        } while ($this->tokenStream->valid());
134
135 130
        if (!$commaExpected && $items->count() > 0) {
136 6
            throw new ParserException(sprintf(
137 6
                'Unexpected "," at position %d on line %d',
138 6
                $current->getPosition(),
139 6
                $current->getLine()
140
            ));
141
        }
142
143 124
        $items->rewind();
144
145 124
        return $items;
146
    }
147
}
148