3 class Template_Syntax_Exception
extends Exception
9 const ATTR_STATE_NAME
= 0;
10 const ATTR_STATE_SEPARATOR
= 1;
11 const ATTR_STATE_VALUE
= 2;
13 const RESERVED_TPL_VAR_NAME
= '(?:smarty|tpl|templatelite)';
15 // Methods to extend and rewrite
16 // These are actually just rewriting your template to the same code, for testing purpose
17 public function processString($content)
19 if (is_array($content))
21 return '"'.implode('', $content).'"';
25 return '"'.$content.'"';
29 public function processModifier($name, $content, $arguments, $map_array)
31 return "$content|$name";
34 public function processVariable($name)
39 // These are parser methods, you should not extend or rewrite them
41 public function __construct()
43 // matches double quoted strings:
46 // "foobar" . "foo\"bar"
47 $this->_db_qstr_regexp
= '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
49 // matches single quoted strings:
52 $this->_si_qstr_regexp
= '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
54 // matches single or double quoted strings
55 $this->_qstr_regexp
= '(?:' . $this->_db_qstr_regexp
. '|' . $this->_si_qstr_regexp
. ')';
57 // matches bracket portion of vars
62 $this->_var_bracket_regexp
= '\[[\$|\#]?\w+\#?\]';
63 // $this->_var_bracket_regexp = '\[\$?[\w\.]+\]';
65 // matches section vars:
67 $this->_svar_regexp
= '\%\w+\.\w+\%';
69 // matches $ vars (not objects):
74 # $this->_dvar_regexp = '\$[a-zA-Z0-9_]{1,}(?:' . $this->_var_bracket_regexp . ')*(?:' . $this->_var_bracket_regexp . ')*';
75 $this->_dvar_regexp
= '\$[a-zA-Z0-9_]{1,}(?:' . $this->_var_bracket_regexp
. ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp
. ')*)*';
77 // matches config vars:
80 $this->_cvar_regexp
= '\#[a-zA-Z0-9_]{1,}(?:' . $this->_var_bracket_regexp
. ')*(?:' . $this->_var_bracket_regexp
. ')*\#';
82 // matches valid variable syntax:
86 $this->_var_regexp
= '(?:(?:' . $this->_dvar_regexp
. '|' . $this->_cvar_regexp
. ')|' . $this->_qstr_regexp
. ')';
88 // matches valid modifier syntax:
95 $this->_mod_regexp
= '(?:\|@?[0-9a-zA-Z_]+(?::(?>-?\w+|' . $this->_dvar_regexp
. '|' . $this->_qstr_regexp
.'))*)';
97 // matches valid function name:
100 $this->_func_regexp
= '(?:[a-zA-Z_]+\:\:)?[a-zA-Z_]+';
101 // $this->_func_regexp = '[a-zA-Z_]\w*';
104 protected function parseArguments($args_str)
108 $state = self
::ATTR_STATE_NAME
;
110 preg_match_all('/(?:' . $this->_qstr_regexp
. ' | (?>[^"\'=\s]+))+|[=]/x', $args_str, $match);
112 foreach ($match[0] as $value)
114 if ($state == self
::ATTR_STATE_NAME
)
116 if (!is_string($value))
117 throw new Template_Syntax_Exception("Invalid attribute name '".$value."'.");
120 $state = self
::ATTR_STATE_SEPARATOR
;
122 elseif ($state == self
::ATTR_STATE_SEPARATOR
)
125 throw new Template_Syntax_Exception("Expecting '=' after '".$last_value."'");
127 $state = self
::ATTR_STATE_VALUE
;
129 elseif ($state == self
::ATTR_STATE_VALUE
)
132 throw new Template_Syntax_Exception("Unexpected '=' after '".$last_value."'");
134 if ($value == 'yes' ||
$value == 'on' ||
$value == 'true')
136 elseif ($value == 'no' ||
$value == 'off' ||
$value == 'false')
138 elseif ($value == 'null')
141 if (preg_match_all('/(?:(' . $this->_var_regexp
. '|' . $this->_svar_regexp
. ')(' . $this->_mod_regexp
. '*))(?:\s+(.*))?/xs', $value, $variables))
143 list($value) = $this->parseVariables($variables[1], $variables[2]);
144 $result[$attr_name] = $value;
148 $result[$attr_name] = $value;
151 $state = self
::ATTR_STATE_NAME
;
154 $last_value = $value;
157 if ($state == self
::ATTR_STATE_SEPARATOR
)
158 throw new Template_Syntax_Exception("Expecting '=' after '".$last_value."'");
159 elseif ($state == self
::ATTR_STATE_VALUE
)
160 throw new Template_Syntax_Exception("Missing attribute value after '".$last_value."'");
165 protected function parseVariables($variables, $modifiers)
169 foreach($variables as $key => $value)
171 $tag_variable = trim($variables[$key]);
173 if(!empty($this->default_modifiers) && !preg_match('!(^|\|)templatelite:nodefaults($|\|)!',$modifiers[$key]))
175 $_default_mod_string = implode('|',(array)$this->default_modifiers);
176 $modifiers[$key] = empty($modifiers[$key]) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers[$key];
179 if (empty($modifiers[$key]))
181 $result[] = $this->parseVariable($tag_variable);
185 $result[] = $this->parseModifier($this->parseVariable($tag_variable), $modifiers[$key]);
192 protected function parseVariable($variable)
194 // replace variable with value
195 if ($variable[0] == '$')
197 // replace the variable
198 #return $this->_compile_variable($variable);
199 return $this->processVariable(substr($variable, 1));
201 elseif ($variable[0] == '#')
203 // replace the config variable
204 #return $this->_compile_config($variable);
205 return $this->processConfigVariable(substr($variable, 1));
207 elseif ($variable[0] == '"')
209 // Parse classic string
210 $variable = substr($variable, 1, -1);
213 // replace all quoted variables by simple variables
214 $variable = preg_replace('!`('.$this->_dvar_regexp
.')`!', '\\1', $variable);
216 // Split string between variables, if they are not escaped
217 // (will parse "hi $name" but no "hi \$name"
218 $parts = preg_split('!(^|[^\\])('.$this->_dvar_regexp
.')!', $variable, -1,
219 PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE | PREG_SPLIT_NO_EMPTY
);
221 foreach ($parts as $key=>$part)
223 if ($part[0][0] == '$')
224 $result[] = $this->processVariable(substr($part[0], 1));
226 $result[] = $part[0];
229 return $this->processString($result);
232 // expand the quotes to pull any variables out of it
233 // fortunately variables inside of a quote aren't fancy, no modifiers, no quotes
234 // just get everything from the $ to the ending space and parse it
235 // if the $ is escaped, then we won't expand it
236 //preg_match_all('/(?:[^\\\]' . $this->_dvar_regexp . ')/', $variable, $expand); // old match
237 // preg_match_all('/(?:[^\\\]' . $this->_dvar_regexp . '[^\\\])/', $variable, $_expand);
238 if (($pos = strpos($variable, '$')) !== false)
240 while ($pos !== false)
245 foreach($expand as $key => $value)
247 $expand[$key] = trim($value);
248 if (($pos = strpos($expand[$key], '$')) > 0)
250 $expand[$key] = substr($expand[$key], $pos);
255 foreach($expand as $value)
257 $value = trim($value);
258 $result = str_replace($value, '" . ' . $this->parseVariable($value) . ' . "', $result);
260 $result = str_replace("`", "", $result);
265 elseif ($variable[0] == "'")
267 // return the value just as it is
268 return $this->processString(substr($variable, 1, -1));
270 elseif ($variable[0] == '%')
272 return $this->parseSection($variable);
276 // return it as is; i believe that there was a reason before that i did not just return it as is,
277 // but i forgot what that reason is ...
278 // the reason i return the variable 'as is' right now is so that unquoted literals are allowed
279 return $this->processString($variable);
283 protected function parseModifier($variable, $modifiers)
285 $mods = array(); // stores all modifiers
286 $args = array(); // modifier arguments
288 preg_match_all('!\|(@?\w+)((?>:(?:'. $this->_qstr_regexp
. '|[^|]+))*)!', '|' . $modifiers, $match);
289 list(, $mods, $args) = $match;
291 $count_mods = count($mods);
292 for ($i = 0, $for_max = $count_mods; $i < $for_max; $i++
)
294 preg_match_all('!:(' . $this->_qstr_regexp
. '|[^:]+)!', $args[$i], $match);
297 if ($mods[$i]{0} == '@')
299 $mods[$i] = substr($mods[$i], 1);
307 foreach($arg as $key => $value)
309 $arg[$key] = $this->parseVariable($value);
312 //$variable = $this->callCompiler('modifier', array('name' => $mods[$i], 'content' => $variable, 'misc' => $map_array, 'args' => $arg));
313 $variable = $this->processModifier($mods[$i], $variable, $arg, $map_array);
315 if ($this->_plugin_exists($_mods[$i], "modifier") || function_exists($_mods[$i]))
317 if (count($_arg) > 0)
319 $_arg = ', '.implode(', ', $_arg);
326 $php_function = "PHP";
327 if ($this->_plugin_exists($_mods[$i], "modifier"))
329 $php_function = "plugin";
331 $variable = "\$this->_run_modifier($variable, '$_mods[$i]', '$php_function', $_map_array$_arg)";
335 $variable = "\$this->trigger_error(\"'" . $_mods[$i] . "' modifier does not exist\", E_USER_NOTICE, __FILE__, __LINE__);";