1
|
|
|
<?php |
2
|
|
|
/* @description Transformation Style Sheets - Revolutionising PHP templating * |
3
|
|
|
* @author Tom Butler [email protected] * |
4
|
|
|
* @copyright 2017 Tom Butler <[email protected]> | https://r.je/ * |
5
|
|
|
* @license http://www.opensource.org/licenses/bsd-license.php BSD License * |
6
|
|
|
* @version 1.2 */ |
7
|
|
|
namespace Transphporm\Parser; |
8
|
|
|
class Tokens implements \Iterator, \Countable { |
9
|
|
|
private $tokens = []; |
10
|
|
|
private $iterator = 0; |
11
|
|
|
|
12
|
|
|
public function __construct($tokens = []) { |
13
|
|
|
$this->tokens = $tokens; |
14
|
|
|
} |
15
|
|
|
|
16
|
|
|
public function count() { |
17
|
|
|
return count($this->tokens); |
18
|
|
|
} |
19
|
|
|
|
20
|
|
|
// Iterator Functions |
21
|
|
|
public function current() { |
22
|
|
|
return $this->tokens[$this->iterator]; |
23
|
|
|
} |
24
|
|
|
|
25
|
|
|
public function key() { |
26
|
|
|
return $this->iterator; |
27
|
|
|
} |
28
|
|
|
|
29
|
|
|
public function next() { |
30
|
|
|
++$this->iterator; |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
public function valid() { |
34
|
|
|
return isset($this->tokens[$this->iterator]); |
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
public function rewind() { |
38
|
|
|
$this->iterator = 0; |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
public function add($token) { |
42
|
|
|
if ($token instanceof Tokens) $this->tokens = array_merge($this->tokens, $token->tokens); |
43
|
|
|
else $this->tokens[] = $token; |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
|
47
|
|
|
public function end() { |
48
|
|
|
return end($this->tokens); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
private function getKeysOfTokenType($tokenType) { |
52
|
|
|
return array_keys(array_column($this->tokens, 'type'), $tokenType); |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
private function getKeyToSlice($tokenType) { |
56
|
|
|
$keys = $this->getKeysOfTokenType($tokenType); |
57
|
|
|
if (empty($keys)) return false; |
58
|
|
|
$key = $keys[0]; |
59
|
|
|
for ($i = 0; $key < $this->iterator && isset($keys[$i]); $i++) $key = $keys[$i]; |
60
|
|
|
return $key; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
public function from($tokenType, $inclusive = false) { |
64
|
|
|
return $this->sliceTokens($tokenType, "from", !$inclusive); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
public function to($tokenType, $inclusive = false) { |
68
|
|
|
return $this->sliceTokens($tokenType, "to", $inclusive); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
private function sliceTokens($tokenType, $type, $increment = false) { |
72
|
|
|
$key = $this->getKeyToSlice($tokenType); |
73
|
|
|
if ($key === false) return new Tokens([]); |
74
|
|
|
if ($increment) $key++; |
75
|
|
|
if ($type === "from") return new Tokens(array_slice($this->tokens, $key)); |
76
|
|
|
else return new Tokens(array_slice($this->tokens, $this->iterator, $key)); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
public function skip($count) { |
80
|
|
|
$this->iterator += $count; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
public function splitOnToken($tokenType) { |
84
|
|
|
$splitTokens = []; |
85
|
|
|
$i = 0; |
86
|
|
|
foreach ($this->tokens as $token) { |
87
|
|
|
if ($token['type'] === $tokenType) $i++; |
88
|
|
|
else $splitTokens[$i][] = $token; |
89
|
|
|
} |
90
|
|
|
return array_map(function ($tokens) { |
91
|
|
|
return new Tokens($tokens); |
92
|
|
|
}, $splitTokens); |
93
|
|
|
//return $splitTokens; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
public function trim() { |
97
|
|
|
$tokens = $this->tokens; |
98
|
|
|
$tokensToTrim = [Tokenizer::WHITESPACE, Tokenizer::NEW_LINE]; |
99
|
|
|
// Remove end whitespace |
100
|
|
|
while ($tokens && in_array(end($tokens)['type'], $tokensToTrim)) { |
|
|
|
|
101
|
|
|
array_pop($tokens); |
102
|
|
|
} |
103
|
|
|
// Remove begining whitespace |
104
|
|
|
while (isset($tokens[0]) && in_array($tokens[0]['type'], $tokensToTrim)) { |
105
|
|
|
array_shift($tokens); |
106
|
|
|
} |
107
|
|
|
return new Tokens($tokens); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
public function removeLine() { |
111
|
|
|
$tokens = $this->tokens; |
112
|
|
|
foreach ($tokens as &$token) unset($token['line']); |
113
|
|
|
return new Tokens($tokens); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
public function read($offset = 0) { |
117
|
|
|
return isset($this->tokens[$offset]) ? $this->tokens[$offset]['value'] : false; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
public function type($offset = 0) { |
121
|
|
|
return isset($this->tokens[$offset]) ? $this->tokens[$offset]['type'] : false; |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.