PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 4.0.3
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v4.0.3
4.0.3 4.0.2 4.0.1 4.0.0 3.16.6 3.16.5 3.16.4 3.16.3 3.16.2 3.16.1 3.16.0 3.15.9 3.9.9 3.9.5 3.9.6 3.9.7 3.9.8 1.1.7 1.1.8 1.1.9 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 341 releases
← All changes | assets/lib/Mustache/Parser.php +139 -16 2.0.2 → 4.0.3 View file →
@@ -2,9 +2,9 @@
2 2
3 3 /*
4 4 * This file is part of Mustache.php.
5 5 *
6 - * (c) 2012 Justin Hileman
6 + * (c) 2010-2017 Justin Hileman
7 7 *
8 8 * For the full copyright and license information, please view the LICENSE
9 9 * file that was distributed with this source code.
10 10 */
@@ -17,9 +17,14 @@
17 17 class Mustache_Parser
18 18 {
19 19 private $lineNum;
20 20 private $lineTokens;
21 + private $pragmas;
22 + private $defaultPragmas = array();
21 23
24 + private $pragmaFilters;
25 + private $pragmaBlocks;
26 +
22 27 /**
23 28 * Process an array of Mustache tokens and convert them into a parse tree.
24 29 *
25 30 * @param array $tokens Set of Mustache tokens
@@ -29,23 +34,44 @@
29 34 public function parse(array $tokens = array())
30 35 {
31 36 $this->lineNum = -1;
32 37 $this->lineTokens = 0;
38 + $this->pragmas = $this->defaultPragmas;
33 39
40 + $this->pragmaFilters = isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS]);
41 + $this->pragmaBlocks = isset($this->pragmas[Mustache_Engine::PRAGMA_BLOCKS]);
42 +
34 43 return $this->buildTree($tokens);
35 44 }
36 45
37 46 /**
47 + * Enable pragmas across all templates, regardless of the presence of pragma
48 + * tags in the individual templates.
49 + *
50 + * @internal Users should set global pragmas in Mustache_Engine, not here :)
51 + *
52 + * @param string[] $pragmas
53 + */
54 + public function setPragmas(array $pragmas)
55 + {
56 + $this->pragmas = array();
57 + foreach ($pragmas as $pragma) {
58 + $this->enablePragma($pragma);
59 + }
60 + $this->defaultPragmas = $this->pragmas;
61 + }
62 +
63 + /**
38 64 * Helper method for recursively building a parse tree.
39 65 *
40 - * @throws Mustache_Exception_SyntaxException when nesting errors or mismatched section tags are encountered.
66 + * @throws Mustache_Exception_SyntaxException when nesting errors or mismatched section tags are encountered
41 67 *
42 68 * @param array &$tokens Set of Mustache tokens
43 - * @param array $parent Parent token (default: null)
69 + * @param array $parent Parent token (default: null)
44 70 *
45 71 * @return array Mustache Token parse tree
46 72 */
47 - private function buildTree(array &$tokens, array $parent = null)
73 + private function buildTree(array &$tokens, ?array $parent = null)
48 74 {
49 75 $nodes = array();
50 76
51 77 while (!empty($tokens)) {
@@ -57,15 +83,25 @@
57 83 $this->lineNum = $token[Mustache_Tokenizer::LINE];
58 84 $this->lineTokens = 0;
59 85 }
60 86
87 + if ($this->pragmaFilters && isset($token[Mustache_Tokenizer::NAME])) {
88 + list($name, $filters) = $this->getNameAndFilters($token[Mustache_Tokenizer::NAME]);
89 + if (!empty($filters)) {
90 + $token[Mustache_Tokenizer::NAME] = $name;
91 + $token[Mustache_Tokenizer::FILTERS] = $filters;
92 + }
93 + }
94 +
61 95 switch ($token[Mustache_Tokenizer::TYPE]) {
62 96 case Mustache_Tokenizer::T_DELIM_CHANGE:
97 + $this->checkIfTokenIsAllowedInParent($parent, $token);
63 98 $this->clearStandaloneLines($nodes, $tokens);
64 99 break;
65 100
66 101 case Mustache_Tokenizer::T_SECTION:
67 102 case Mustache_Tokenizer::T_INVERTED:
103 + $this->checkIfTokenIsAllowedInParent($parent, $token);
68 104 $this->clearStandaloneLines($nodes, $tokens);
69 105 $nodes[] = $this->buildTree($tokens, $token);
70 106 break;
71 107
@@ -70,14 +106,24 @@
70 106 break;
71 107
72 108 case Mustache_Tokenizer::T_END_SECTION:
73 109 if (!isset($parent)) {
74 - $msg = sprintf('Unexpected closing tag: /%s', $token[Mustache_Tokenizer::NAME]);
110 + $msg = sprintf(
111 + 'Unexpected closing tag: /%s on line %d',
112 + $token[Mustache_Tokenizer::NAME],
113 + $token[Mustache_Tokenizer::LINE]
114 + );
75 115 throw new Mustache_Exception_SyntaxException($msg, $token);
76 116 }
77 117
78 118 if ($token[Mustache_Tokenizer::NAME] !== $parent[Mustache_Tokenizer::NAME]) {
79 - $msg = sprintf('Nesting error: %s vs. %s', $parent[Mustache_Tokenizer::NAME], $token[Mustache_Tokenizer::NAME]);
119 + $msg = sprintf(
120 + 'Nesting error: %s (on line %d) vs. %s (on line %d)',
121 + $parent[Mustache_Tokenizer::NAME],
122 + $parent[Mustache_Tokenizer::LINE],
123 + $token[Mustache_Tokenizer::NAME],
124 + $token[Mustache_Tokenizer::LINE]
125 + );
80 126 throw new Mustache_Exception_SyntaxException($msg, $token);
81 127 }
82 128
83 129 $this->clearStandaloneLines($nodes, $tokens);
@@ -84,13 +130,12 @@
84 130 $parent[Mustache_Tokenizer::END] = $token[Mustache_Tokenizer::INDEX];
85 131 $parent[Mustache_Tokenizer::NODES] = $nodes;
86 132
87 133 return $parent;
88 - break;
89 134
90 135 case Mustache_Tokenizer::T_PARTIAL:
91 - case Mustache_Tokenizer::T_PARTIAL_2:
92 - // store the whitespace prefix for laters!
136 + $this->checkIfTokenIsAllowedInParent($parent, $token);
137 + //store the whitespace prefix for laters!
93 138 if ($indent = $this->clearStandaloneLines($nodes, $tokens)) {
94 139 $token[Mustache_Tokenizer::INDENT] = $indent[Mustache_Tokenizer::VALUE];
95 140 }
96 141 $nodes[] = $token;
@@ -95,9 +140,34 @@
95 140 }
96 141 $nodes[] = $token;
97 142 break;
98 143
144 + case Mustache_Tokenizer::T_PARENT:
145 + $this->checkIfTokenIsAllowedInParent($parent, $token);
146 + $nodes[] = $this->buildTree($tokens, $token);
147 + break;
148 +
149 + case Mustache_Tokenizer::T_BLOCK_VAR:
150 + if ($this->pragmaBlocks) {
151 + // BLOCKS pragma is enabled, let's do this!
152 + if (isset($parent) && $parent[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_PARENT) {
153 + $token[Mustache_Tokenizer::TYPE] = Mustache_Tokenizer::T_BLOCK_ARG;
154 + }
155 + $this->clearStandaloneLines($nodes, $tokens);
156 + $nodes[] = $this->buildTree($tokens, $token);
157 + } else {
158 + // pretend this was just a normal "escaped" token...
159 + $token[Mustache_Tokenizer::TYPE] = Mustache_Tokenizer::T_ESCAPED;
160 + // TODO: figure out how to figure out if there was a space after this dollar:
161 + $token[Mustache_Tokenizer::NAME] = '$' . $token[Mustache_Tokenizer::NAME];
162 + $nodes[] = $token;
163 + }
164 + break;
165 +
99 166 case Mustache_Tokenizer::T_PRAGMA:
167 + $this->enablePragma($token[Mustache_Tokenizer::NAME]);
168 + // no break
169 +
100 170 case Mustache_Tokenizer::T_COMMENT:
101 171 $this->clearStandaloneLines($nodes, $tokens);
102 172 $nodes[] = $token;
103 173 break;
@@ -108,9 +178,13 @@
108 178 }
109 179 }
110 180
111 181 if (isset($parent)) {
112 - $msg = sprintf('Missing closing tag: %s', $parent[Mustache_Tokenizer::NAME]);
182 + $msg = sprintf(
183 + 'Missing closing tag: %s opened on line %d',
184 + $parent[Mustache_Tokenizer::NAME],
185 + $parent[Mustache_Tokenizer::LINE]
186 + );
113 187 throw new Mustache_Exception_SyntaxException($msg, $parent);
114 188 }
115 189
116 190 return $nodes;
@@ -120,12 +194,12 @@
120 194 * Clear standalone line tokens.
121 195 *
122 196 * Returns a whitespace token for indenting partials, if applicable.
123 197 *
124 - * @param array $nodes Parsed nodes.
125 - * @param array $tokens Tokens to be parsed.
198 + * @param array $nodes Parsed nodes
199 + * @param array $tokens Tokens to be parsed
126 200 *
127 - * @return array Resulting indent token, if any.
201 + * @return array|null Resulting indent token, if any
128 202 */
129 203 private function clearStandaloneLines(array &$nodes, array &$tokens)
130 204 {
131 205 if ($this->lineTokens > 1) {
@@ -143,9 +217,8 @@
143 217 }
144 218 }
145 219 }
146 220
147 - $next = null;
148 221 if ($next = reset($tokens)) {
149 222 // If we're on a new line, bail.
150 223 if ($next[Mustache_Tokenizer::LINE] !== $this->lineNum) {
151 224 return;
@@ -180,15 +253,65 @@
180 253 * True if token type is T_TEXT and value is all whitespace characters.
181 254 *
182 255 * @param array $token
183 256 *
184 - * @return boolean True if token is a whitespace token
257 + * @return bool True if token is a whitespace token
185 258 */
186 259 private function tokenIsWhitespace(array $token)
187 260 {
188 - if ($token[Mustache_Tokenizer::TYPE] == Mustache_Tokenizer::T_TEXT) {
261 + if ($token[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_TEXT) {
189 262 return preg_match('/^\s*$/', $token[Mustache_Tokenizer::VALUE]);
190 263 }
191 264
192 265 return false;
266 + }
267 +
268 + /**
269 + * Check whether a token is allowed inside a parent tag.
270 + *
271 + * @throws Mustache_Exception_SyntaxException if an invalid token is found inside a parent tag
272 + *
273 + * @param array|null $parent
274 + * @param array $token
275 + */
276 + private function checkIfTokenIsAllowedInParent($parent, array $token)
277 + {
278 + if (isset($parent) && $parent[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_PARENT) {
279 + throw new Mustache_Exception_SyntaxException('Illegal content in < parent tag', $token);
280 + }
281 + }
282 +
283 + /**
284 + * Split a tag name into name and filters.
285 + *
286 + * @param string $name
287 + *
288 + * @return array [Tag name, Array of filters]
289 + */
290 + private function getNameAndFilters($name)
291 + {
292 + $filters = array_map('trim', explode('|', $name));
293 + $name = array_shift($filters);
294 +
295 + return array($name, $filters);
296 + }
297 +
298 + /**
299 + * Enable a pragma.
300 + *
301 + * @param string $name
302 + */
303 + private function enablePragma($name)
304 + {
305 + $this->pragmas[$name] = true;
306 +
307 + switch ($name) {
308 + case Mustache_Engine::PRAGMA_BLOCKS:
309 + $this->pragmaBlocks = true;
310 + break;
311 +
312 + case Mustache_Engine::PRAGMA_FILTERS:
313 + $this->pragmaFilters = true;
314 + break;
315 + }
193 316 }
194 317 }