support nested function calls in IF statements

This commit is contained in:
mohrt
2002-12-23 22:52:42 +00:00
parent 0a216a69d6
commit de93c33525
2 changed files with 116 additions and 74 deletions

View File

@@ -116,7 +116,7 @@ class Smarty_Compiler extends Smarty {
// |foo:"bar":$foobar // |foo:"bar":$foobar
// |foo|bar // |foo|bar
// |foo // |foo
$this->_mod_regexp = '(?>\|@?\w+(?::(?>\w+|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)*'; $this->_mod_regexp = '(?:\|@?\w+(?::(?>\w+|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';
// matches valid variable syntax: // matches valid variable syntax:
// $foo // $foo
@@ -135,9 +135,19 @@ class Smarty_Compiler extends Smarty {
// $foo->bar($foo|bar, "foo"|bar) // $foo->bar($foo|bar, "foo"|bar)
// $foo->bar->foo() // $foo->bar->foo()
// $foo->bar->foo->bar() // $foo->bar->foo->bar()
$this->_obj_call_regexp = '(?:\$\w+(?:\.\w+)*(?:\->\w+)+(?:\((?:\w+|' $this->_obj_start_regexp = '(?:\$\w+(?:\.\w+)*(?:\->\w+)+)';
. $this->_var_regexp . $this->_mod_regexp . '(?:\s*,\s*(?:(?:\w+|'
. $this->_var_regexp . $this->_mod_regexp . ')))*)?\))?)'; // matches valid object call (no objects allowed in parameters):
// $foo->bar
// $foo->bar()
// $foo->bar("text")
// $foo->bar($foo, $bar, "text")
// $foo->bar($foo|bar, "foo"|bar)
// $foo->bar->foo()
// $foo->bar->foo->bar()
$this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:\((?:\w+|'
. $this->_var_regexp . '(?>' . $this->_mod_regexp . ')*(?:\s*,\s*(?:(?:\w+|'
. $this->_var_regexp . '(?>' . $this->_mod_regexp . ')*)))*)?\))?)';
// matches valid function name: // matches valid function name:
// foo123 // foo123
@@ -153,15 +163,16 @@ class Smarty_Compiler extends Smarty {
// "text" // "text"
// "text"|bar // "text"|bar
// $foo->bar() // $foo->bar()
$this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '|\w+)' . $this->_mod_regexp . '\s*)'; $this->_param_regexp = '(?:\s*(?:\(array|int\)\s*)?(?:' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '|\w+)(?>' . $this->_mod_regexp . ')*\s*)';
// matches valid parenthesised function parameters: // matches valid parenthesised function parameters:
// //
// "text" // "text"
// $foo, $bar, "text" // $foo, $bar, "text"
// $foo|bar, "foo"|bar, $foo->bar($foo)|bar // $foo|bar, "foo"|bar, $foo->bar($foo)|bar
$this->_parenth_param_regexp = '(?:\((?:' . $this->_param_regexp $this->_parenth_param_regexp = '(?:\((?:\w+|'
. '(?:,(?:' . $this->_param_regexp . '))*)?\))'; . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
. $this->_param_regexp . ')))*)?\))';
// matches valid function call: // matches valid function call:
// foo() // foo()
@@ -344,7 +355,7 @@ class Smarty_Compiler extends Smarty {
return ''; return '';
/* Split tag into two three parts: command, command modifiers and the arguments. */ /* Split tag into two three parts: command, command modifiers and the arguments. */
if(! preg_match('/^(?:(' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . ')) if(! preg_match('/^(?:(' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . ')*)
(?:\s+(.*))?$ (?:\s+(.*))?$
/xs', $template_tag, $match)) { /xs', $template_tag, $match)) {
$this->_syntax_error("unrecognized tag: $template_tag"); $this->_syntax_error("unrecognized tag: $template_tag");
@@ -357,9 +368,8 @@ class Smarty_Compiler extends Smarty {
/* If the tag name is not a function, we process it. */ /* If the tag name is not a function, we process it. */
if (!preg_match('!^\/?' . $this->_func_regexp . '$!', $tag_command)) { if (!preg_match('!^\/?' . $this->_func_regexp . '$!', $tag_command)) {
$array_tag_command = array($tag_command . $tag_modifier); $return = $this->_parse_var_props($tag_command . $tag_modifier);
$this->_parse_vars_props($array_tag_command); return "<?php echo $return; ?>\n";
return "<?php echo $array_tag_command[0]; ?>\n";
} }
switch ($tag_command) { switch ($tag_command) {
@@ -956,16 +966,21 @@ class Smarty_Compiler extends Smarty {
/* Tokenize args for 'if' tag. */ /* Tokenize args for 'if' tag. */
preg_match_all('/(?> preg_match_all('/(?>
' . $this->_func_call_regexp . ' | # valid function call ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . ')* | # valid object call
' . $this->_obj_call_regexp . $this->_mod_regexp . ' | # valid object call ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')* | # var or quoted string
' . $this->_var_regexp . $this->_mod_regexp . ' | # var or quoted string \d+|!==|<=>|==|!=|<=|=>|\&\&|\|\||\(|\)|,|\!|\^|=|<|>|\||\% | # valid non-word token
\d+|!==|<=>|==|!=|<=|=>|\&\&|\|\||\(|\)|,|\!|\^|=|<|>|\||\% | # valid non-word token \b\w+\b | # valid word token
\b(even|odd|neq|lte|gte|and|not|mod|div|eq|ne|lt|le|gt|ge|or|is|by)\b | # valid word token
\S+ # anything else \S+ # anything else
)/x', $tag_args, $match); )/x', $tag_args, $match);
$tokens = $match[0]; $tokens = $match[0];
// make sure we have balanced parenthesis
$token_count = array_count_values($tokens);
if(isset($token_count['(']) && $token_count['('] != $token_count[')']) {
$this->_syntax_error("unbalanced parenthesis");
}
$is_arg_stack = array(); $is_arg_stack = array();
for ($i = 0; $i < count($tokens); $i++) { for ($i = 0; $i < count($tokens); $i++) {
@@ -1059,20 +1074,26 @@ class Smarty_Compiler extends Smarty {
break; break;
case ')': case ')':
case ',':
break; break;
default: default:
if(preg_match('!^(' . $this->_func_regexp . ')(' . $this->_parenth_param_regexp . ')$!', $token, $match)) { if(preg_match('!^' . $this->_func_regexp . '$!', $token) ) {
// function call // function call
if($this->security && if($this->security &&
$i+1 < count($tokens) && !in_array($token, $this->security_settings['IF_FUNCS'])) {
$tokens[$i+1] == '(' && $this->_syntax_error("(secure mode) '$token' not allowed in if statement");
!in_array($match[1], $this->security_settings['IF_FUNCS'])) {
$this->_syntax_error("(secure mode) '".$tokens[$i]."' not allowed in if statement");
} }
$token = str_replace($match[2], $this->_parse_parenth_args($match[2]), $token); } elseif(preg_match('!^' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$!', $token)) {
} else { // variable
$token = $this->_parse_var_props($token); $token = $this->_parse_var_props($token);
} elseif(preg_match('!^' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . ')*$!', $token)) {
// object
$token = $this->_parse_var_props($token);
} elseif(is_numeric($token)) {
// number, skip it
} else {
$this->_syntax_error("unidentified token '$token'");
} }
break; break;
} }
@@ -1236,32 +1257,32 @@ class Smarty_Compiler extends Smarty {
$val = trim($val); $val = trim($val);
if(preg_match('!^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')' . $this->_mod_regexp . '$!', $val)) { if(preg_match('!^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(?:' . $this->_mod_regexp . ')*$!', $val)) {
// $ variable or object // $ variable or object
return $this->_parse_var($val); return $this->_parse_var($val);
} }
elseif(preg_match('!^' . $this->_db_qstr_regexp . $this->_mod_regexp . '$!', $val)) { elseif(preg_match('!^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . ')*$!', $val)) {
// double quoted text // double quoted text
preg_match('!^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . ')$!', $val, $match); preg_match('!^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . ')*$!', $val, $match);
$return = $this->_expand_quoted_text($match[1]); $return = $this->_expand_quoted_text($match[1]);
if($match[2] != '') { if($match[2] != '') {
$this->_parse_modifiers($return, $match[2]); $this->_parse_modifiers($return, $match[2]);
} }
return $return; return $return;
} }
elseif(preg_match('!^' . $this->_si_qstr_regexp . $this->_mod_regexp . '$!', $val)) { elseif(preg_match('!^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . ')*$!', $val)) {
// single quoted text // single quoted text
preg_match('!^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . ')$!', $val, $match); preg_match('!^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . ')*$!', $val, $match);
if($match[2] != '') { if($match[2] != '') {
$this->_parse_modifiers($match[1], $match[2]); $this->_parse_modifiers($match[1], $match[2]);
return $match[1]; return $match[1];
} }
} }
elseif(preg_match('!^' . $this->_cvar_regexp . $this->_mod_regexp . '$!', $val)) { elseif(preg_match('!^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . ')*$!', $val)) {
// config var // config var
return $this->_parse_conf_var($val); return $this->_parse_conf_var($val);
} }
elseif(preg_match('!^' . $this->_svar_regexp . $this->_mod_regexp . '$!', $val)) { elseif(preg_match('!^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . ')*$!', $val)) {
// section var // section var
return $this->_parse_section_prop($val); return $this->_parse_section_prop($val);
} }
@@ -1298,7 +1319,7 @@ class Smarty_Compiler extends Smarty {
function _parse_var($var_expr) function _parse_var($var_expr)
{ {
preg_match('!(' . $this->_obj_call_regexp . '|' . $this->_var_regexp . ')(' . $this->_mod_regexp . ')$!', $var_expr, $match); preg_match('!(' . $this->_obj_call_regexp . '|' . $this->_var_regexp . ')(' . $this->_mod_regexp . ')*$!', $var_expr, $match);
$var_ref = substr($match[1],1); $var_ref = substr($match[1],1);
$modifiers = $match[2]; $modifiers = $match[2];

View File

@@ -116,7 +116,7 @@ class Smarty_Compiler extends Smarty {
// |foo:"bar":$foobar // |foo:"bar":$foobar
// |foo|bar // |foo|bar
// |foo // |foo
$this->_mod_regexp = '(?>\|@?\w+(?::(?>\w+|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)*'; $this->_mod_regexp = '(?:\|@?\w+(?::(?>\w+|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';
// matches valid variable syntax: // matches valid variable syntax:
// $foo // $foo
@@ -135,9 +135,19 @@ class Smarty_Compiler extends Smarty {
// $foo->bar($foo|bar, "foo"|bar) // $foo->bar($foo|bar, "foo"|bar)
// $foo->bar->foo() // $foo->bar->foo()
// $foo->bar->foo->bar() // $foo->bar->foo->bar()
$this->_obj_call_regexp = '(?:\$\w+(?:\.\w+)*(?:\->\w+)+(?:\((?:\w+|' $this->_obj_start_regexp = '(?:\$\w+(?:\.\w+)*(?:\->\w+)+)';
. $this->_var_regexp . $this->_mod_regexp . '(?:\s*,\s*(?:(?:\w+|'
. $this->_var_regexp . $this->_mod_regexp . ')))*)?\))?)'; // matches valid object call (no objects allowed in parameters):
// $foo->bar
// $foo->bar()
// $foo->bar("text")
// $foo->bar($foo, $bar, "text")
// $foo->bar($foo|bar, "foo"|bar)
// $foo->bar->foo()
// $foo->bar->foo->bar()
$this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:\((?:\w+|'
. $this->_var_regexp . '(?>' . $this->_mod_regexp . ')*(?:\s*,\s*(?:(?:\w+|'
. $this->_var_regexp . '(?>' . $this->_mod_regexp . ')*)))*)?\))?)';
// matches valid function name: // matches valid function name:
// foo123 // foo123
@@ -153,15 +163,16 @@ class Smarty_Compiler extends Smarty {
// "text" // "text"
// "text"|bar // "text"|bar
// $foo->bar() // $foo->bar()
$this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '|\w+)' . $this->_mod_regexp . '\s*)'; $this->_param_regexp = '(?:\s*(?:\(array|int\)\s*)?(?:' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '|\w+)(?>' . $this->_mod_regexp . ')*\s*)';
// matches valid parenthesised function parameters: // matches valid parenthesised function parameters:
// //
// "text" // "text"
// $foo, $bar, "text" // $foo, $bar, "text"
// $foo|bar, "foo"|bar, $foo->bar($foo)|bar // $foo|bar, "foo"|bar, $foo->bar($foo)|bar
$this->_parenth_param_regexp = '(?:\((?:' . $this->_param_regexp $this->_parenth_param_regexp = '(?:\((?:\w+|'
. '(?:,(?:' . $this->_param_regexp . '))*)?\))'; . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
. $this->_param_regexp . ')))*)?\))';
// matches valid function call: // matches valid function call:
// foo() // foo()
@@ -344,7 +355,7 @@ class Smarty_Compiler extends Smarty {
return ''; return '';
/* Split tag into two three parts: command, command modifiers and the arguments. */ /* Split tag into two three parts: command, command modifiers and the arguments. */
if(! preg_match('/^(?:(' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . ')) if(! preg_match('/^(?:(' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . ')*)
(?:\s+(.*))?$ (?:\s+(.*))?$
/xs', $template_tag, $match)) { /xs', $template_tag, $match)) {
$this->_syntax_error("unrecognized tag: $template_tag"); $this->_syntax_error("unrecognized tag: $template_tag");
@@ -357,9 +368,8 @@ class Smarty_Compiler extends Smarty {
/* If the tag name is not a function, we process it. */ /* If the tag name is not a function, we process it. */
if (!preg_match('!^\/?' . $this->_func_regexp . '$!', $tag_command)) { if (!preg_match('!^\/?' . $this->_func_regexp . '$!', $tag_command)) {
$array_tag_command = array($tag_command . $tag_modifier); $return = $this->_parse_var_props($tag_command . $tag_modifier);
$this->_parse_vars_props($array_tag_command); return "<?php echo $return; ?>\n";
return "<?php echo $array_tag_command[0]; ?>\n";
} }
switch ($tag_command) { switch ($tag_command) {
@@ -956,16 +966,21 @@ class Smarty_Compiler extends Smarty {
/* Tokenize args for 'if' tag. */ /* Tokenize args for 'if' tag. */
preg_match_all('/(?> preg_match_all('/(?>
' . $this->_func_call_regexp . ' | # valid function call ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . ')* | # valid object call
' . $this->_obj_call_regexp . $this->_mod_regexp . ' | # valid object call ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')* | # var or quoted string
' . $this->_var_regexp . $this->_mod_regexp . ' | # var or quoted string \d+|!==|<=>|==|!=|<=|=>|\&\&|\|\||\(|\)|,|\!|\^|=|<|>|\||\% | # valid non-word token
\d+|!==|<=>|==|!=|<=|=>|\&\&|\|\||\(|\)|,|\!|\^|=|<|>|\||\% | # valid non-word token \b\w+\b | # valid word token
\b(even|odd|neq|lte|gte|and|not|mod|div|eq|ne|lt|le|gt|ge|or|is|by)\b | # valid word token
\S+ # anything else \S+ # anything else
)/x', $tag_args, $match); )/x', $tag_args, $match);
$tokens = $match[0]; $tokens = $match[0];
// make sure we have balanced parenthesis
$token_count = array_count_values($tokens);
if(isset($token_count['(']) && $token_count['('] != $token_count[')']) {
$this->_syntax_error("unbalanced parenthesis");
}
$is_arg_stack = array(); $is_arg_stack = array();
for ($i = 0; $i < count($tokens); $i++) { for ($i = 0; $i < count($tokens); $i++) {
@@ -1059,20 +1074,26 @@ class Smarty_Compiler extends Smarty {
break; break;
case ')': case ')':
case ',':
break; break;
default: default:
if(preg_match('!^(' . $this->_func_regexp . ')(' . $this->_parenth_param_regexp . ')$!', $token, $match)) { if(preg_match('!^' . $this->_func_regexp . '$!', $token) ) {
// function call // function call
if($this->security && if($this->security &&
$i+1 < count($tokens) && !in_array($token, $this->security_settings['IF_FUNCS'])) {
$tokens[$i+1] == '(' && $this->_syntax_error("(secure mode) '$token' not allowed in if statement");
!in_array($match[1], $this->security_settings['IF_FUNCS'])) {
$this->_syntax_error("(secure mode) '".$tokens[$i]."' not allowed in if statement");
} }
$token = str_replace($match[2], $this->_parse_parenth_args($match[2]), $token); } elseif(preg_match('!^' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$!', $token)) {
} else { // variable
$token = $this->_parse_var_props($token); $token = $this->_parse_var_props($token);
} elseif(preg_match('!^' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . ')*$!', $token)) {
// object
$token = $this->_parse_var_props($token);
} elseif(is_numeric($token)) {
// number, skip it
} else {
$this->_syntax_error("unidentified token '$token'");
} }
break; break;
} }
@@ -1236,32 +1257,32 @@ class Smarty_Compiler extends Smarty {
$val = trim($val); $val = trim($val);
if(preg_match('!^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')' . $this->_mod_regexp . '$!', $val)) { if(preg_match('!^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(?:' . $this->_mod_regexp . ')*$!', $val)) {
// $ variable or object // $ variable or object
return $this->_parse_var($val); return $this->_parse_var($val);
} }
elseif(preg_match('!^' . $this->_db_qstr_regexp . $this->_mod_regexp . '$!', $val)) { elseif(preg_match('!^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . ')*$!', $val)) {
// double quoted text // double quoted text
preg_match('!^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . ')$!', $val, $match); preg_match('!^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . ')*$!', $val, $match);
$return = $this->_expand_quoted_text($match[1]); $return = $this->_expand_quoted_text($match[1]);
if($match[2] != '') { if($match[2] != '') {
$this->_parse_modifiers($return, $match[2]); $this->_parse_modifiers($return, $match[2]);
} }
return $return; return $return;
} }
elseif(preg_match('!^' . $this->_si_qstr_regexp . $this->_mod_regexp . '$!', $val)) { elseif(preg_match('!^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . ')*$!', $val)) {
// single quoted text // single quoted text
preg_match('!^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . ')$!', $val, $match); preg_match('!^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . ')*$!', $val, $match);
if($match[2] != '') { if($match[2] != '') {
$this->_parse_modifiers($match[1], $match[2]); $this->_parse_modifiers($match[1], $match[2]);
return $match[1]; return $match[1];
} }
} }
elseif(preg_match('!^' . $this->_cvar_regexp . $this->_mod_regexp . '$!', $val)) { elseif(preg_match('!^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . ')*$!', $val)) {
// config var // config var
return $this->_parse_conf_var($val); return $this->_parse_conf_var($val);
} }
elseif(preg_match('!^' . $this->_svar_regexp . $this->_mod_regexp . '$!', $val)) { elseif(preg_match('!^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . ')*$!', $val)) {
// section var // section var
return $this->_parse_section_prop($val); return $this->_parse_section_prop($val);
} }
@@ -1298,7 +1319,7 @@ class Smarty_Compiler extends Smarty {
function _parse_var($var_expr) function _parse_var($var_expr)
{ {
preg_match('!(' . $this->_obj_call_regexp . '|' . $this->_var_regexp . ')(' . $this->_mod_regexp . ')$!', $var_expr, $match); preg_match('!(' . $this->_obj_call_regexp . '|' . $this->_var_regexp . ')(' . $this->_mod_regexp . ')*$!', $var_expr, $match);
$var_ref = substr($match[1],1); $var_ref = substr($match[1],1);
$modifiers = $match[2]; $modifiers = $match[2];