1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Latte;
9:
10:
11: 12: 13: 14:
15: class TokenIterator
16: {
17: use Strict;
18:
19:
20: public $tokens;
21:
22:
23: public $position = -1;
24:
25:
26: public $ignored = [];
27:
28:
29: 30: 31:
32: public function __construct(array $tokens)
33: {
34: $this->tokens = $tokens;
35: }
36:
37:
38: 39: 40: 41:
42: public function currentToken()
43: {
44: return isset($this->tokens[$this->position])
45: ? $this->tokens[$this->position]
46: : null;
47: }
48:
49:
50: 51: 52: 53:
54: public function currentValue()
55: {
56: return isset($this->tokens[$this->position])
57: ? $this->tokens[$this->position][Tokenizer::VALUE]
58: : null;
59: }
60:
61:
62: 63: 64: 65: 66:
67: public function nextToken()
68: {
69: return $this->scan(func_get_args(), true, true);
70: }
71:
72:
73: 74: 75: 76: 77:
78: public function nextValue()
79: {
80: return $this->scan(func_get_args(), true, true, true);
81: }
82:
83:
84: 85: 86: 87: 88:
89: public function nextAll()
90: {
91: return $this->scan(func_get_args(), false, true);
92: }
93:
94:
95: 96: 97: 98: 99:
100: public function nextUntil($arg)
101: {
102: return $this->scan(func_get_args(), false, true, false, true);
103: }
104:
105:
106: 107: 108: 109: 110:
111: public function joinAll()
112: {
113: return $this->scan(func_get_args(), false, true, true);
114: }
115:
116:
117: 118: 119: 120: 121:
122: public function joinUntil($arg)
123: {
124: return $this->scan(func_get_args(), false, true, true, true);
125: }
126:
127:
128: 129: 130: 131: 132:
133: public function isCurrent($arg)
134: {
135: if (!isset($this->tokens[$this->position])) {
136: return false;
137: }
138: $args = func_get_args();
139: $token = $this->tokens[$this->position];
140: return in_array($token[Tokenizer::VALUE], $args, true)
141: || (isset($token[Tokenizer::TYPE]) && in_array($token[Tokenizer::TYPE], $args, true));
142: }
143:
144:
145: 146: 147: 148: 149:
150: public function isNext()
151: {
152: return (bool) $this->scan(func_get_args(), true, false);
153: }
154:
155:
156: 157: 158: 159: 160:
161: public function isPrev()
162: {
163: return (bool) $this->scan(func_get_args(), true, false, false, false, true);
164: }
165:
166:
167: 168: 169: 170: 171: 172:
173: public function expectNextValue()
174: {
175: if ($token = $this->scan(func_get_args(), true, true)) {
176: return $token[Tokenizer::VALUE];
177: }
178: $pos = $this->position + 1;
179: while (($next = isset($this->tokens[$pos]) ? $this->tokens[$pos] : null) && in_array($next[Tokenizer::TYPE], $this->ignored, true)) {
180: $pos++;
181: }
182: throw new CompileException($next ? "Unexpected token '" . $next[Tokenizer::VALUE] . "'." : 'Unexpected end.');
183: }
184:
185:
186: 187: 188:
189: public function reset()
190: {
191: $this->position = -1;
192: return $this;
193: }
194:
195:
196: 197: 198:
199: protected function next()
200: {
201: $this->position++;
202: }
203:
204:
205: 206: 207: 208: 209: 210: 211: 212: 213: 214:
215: protected function scan($wanted, $onlyFirst, $advance, $strings = false, $until = false, $prev = false)
216: {
217: $res = $onlyFirst ? null : ($strings ? '' : []);
218: $pos = $this->position + ($prev ? -1 : 1);
219: do {
220: if (!isset($this->tokens[$pos])) {
221: return $res;
222: }
223:
224: $token = $this->tokens[$pos];
225: $type = isset($token[Tokenizer::TYPE]) ? $token[Tokenizer::TYPE] : null;
226: if (!$wanted || (in_array($token[Tokenizer::VALUE], $wanted, true) || in_array($type, $wanted, true)) ^ $until) {
227: while ($advance && !$prev && $pos > $this->position) {
228: $this->next();
229: }
230:
231: if ($onlyFirst) {
232: return $strings ? $token[Tokenizer::VALUE] : $token;
233: } elseif ($strings) {
234: $res .= $token[Tokenizer::VALUE];
235: } else {
236: $res[] = $token;
237: }
238:
239: } elseif ($until || !in_array($type, $this->ignored, true)) {
240: return $res;
241: }
242: $pos += $prev ? -1 : 1;
243: } while (true);
244: }
245: }
246: