From: Andrey Kutejko Date: Fri, 28 Jun 2013 12:27:52 +0000 (+0300) Subject: template scopes (foreach) X-Git-Url: https://git.andy128k.dev/?a=commitdiff_plain;h=8b6d0dc5db91fa75ae79141db4a4363b10ab314d;p=ipf-template.git template scopes (foreach) --- diff --git a/ipf/template/compiler.php b/ipf/template/compiler.php index e55df54..9b648ef 100644 --- a/ipf/template/compiler.php +++ b/ipf/template/compiler.php @@ -11,7 +11,7 @@ class IPF_Template_Compiler { $vartype = array(T_CHARACTER, T_CONSTANT_ENCAPSED_STRING, T_DNUMBER, T_ENCAPSED_AND_WHITESPACE, T_LNUMBER, T_OBJECT_OPERATOR, T_STRING, - T_WHITESPACE, T_ARRAY); + T_WHITESPACE, T_ARRAY, T_VARIABLE); $assignOp = array(T_AND_EQUAL, T_DIV_EQUAL, T_MINUS_EQUAL, T_MOD_EQUAL, T_MUL_EQUAL, T_OR_EQUAL, T_PLUS_EQUAL, T_PLUS_EQUAL, T_SL_EQUAL, @@ -25,7 +25,7 @@ class IPF_Template_Compiler self::$allowedInVar = array_merge($vartype, $op); self::$allowedInExpr = array_merge($vartype, $op); self::$allowedAssign = array_merge($vartype, $op, $assignOp); - self::$allowedForeach = array(T_AS, T_DOUBLE_ARROW, T_STRING, T_OBJECT_OPERATOR); + self::$allowedForeach = array_merge(self::$allowedInExpr, array(T_AS)); } protected $_modifier = array( @@ -268,11 +268,26 @@ class IPF_Template_Compiler $res = 'elseif('.$this->_parseFinal($args, self::$allowedInExpr).'):'; break; case 'foreach': + $tokens = $this->tokenize($args, self::$allowedForeach, array(';')); + $asFound = false; + $scopeVars = array('foreach_counter0', 'foreach_counter', 'foreach_first'); + foreach ($tokens as $token) { + if (!is_array($token)) + continue; + if ($asFound) { + if ($token[0] == T_VARIABLE) + $scopeVars[] = substr($token[1], 1); + } else { + if ($token[0] == T_AS) + $asFound = true; + } + } $res = + '$t->push(\'' . implode('\', \'', $scopeVars) . '\'); ' . '$t->_vars[\'foreach_counter0\'] = 0;' . '$t->_vars[\'foreach_counter\'] = 1;' . '$t->_vars[\'foreach_first\'] = true;' . - 'foreach ('.$this->_parseFinal($args, self::$allowedForeach, array(';','!')).'): '; + 'foreach ('.$this->compileExpression($tokens).'): '; $this->_blockStack[] = 'foreach'; break; case 'while': @@ -288,7 +303,8 @@ class IPF_Template_Compiler '$t->_vars[\'foreach_counter0\'] = $t->_vars[\'foreach_counter0\'] + 1;' . '$t->_vars[\'foreach_counter\'] = $t->_vars[\'foreach_counter\'] + 1;' . '$t->_vars[\'foreach_first\'] = false;' . - 'endforeach; '; + 'endforeach; ' . + '$t->pop(); '; break; case '/if': case '/while': @@ -425,38 +441,52 @@ class IPF_Template_Compiler } private function _parseFinal($string, &$allowed, $exceptchar=array(';')) + { + $tokens = $this->tokenize($string, $allowed, $exceptchar); + return $this->compileExpression($tokens); + } + + private function tokenize($string, $allowed, $exceptchar) { $tokens = token_get_all(''); - $result = ''; - $inDot = false; + $result = array(); foreach ($tokens as $tok) { if (is_array($tok)) { list($type, $str) = $tok; - if ($type == T_OPEN_TAG || $type == T_CLOSE_TAG) - continue; - - if ($type == T_STRING && $inDot) { - $result .= $str; - } elseif ($type == T_VARIABLE) { - $result .= '$t->_vars[\''.substr($str, 1).'\']'; - } elseif ($type == T_WHITESPACE || in_array($type, $allowed)) { - $result .= $str; + if ($type == T_OPEN_TAG || $type == T_CLOSE_TAG) { + // skip + } elseif (in_array($type, $allowed)) { + $result[] = $tok; } else { - trigger_error(sprintf(__('Invalid syntax: (%s) %s.'), $string, $str), E_USER_ERROR); - return ''; + throw new IPF_Exception_Template(sprintf(__('Invalid syntax: (%s) %s.'), $string, $str)); } } else { if (in_array($tok, $exceptchar)) { trigger_error(sprintf(__('Invalid character: (%s) %s.'), $string, $tok), E_USER_ERROR); - } elseif ($tok == '.') { - $inDot = true; + } else { + $result[] = $tok; + } + } + } + return $result; + } + + private function compileExpression($tokens) + { + $result = ''; + foreach ($tokens as $tok) { + if (is_array($tok)) { + list($type, $str) = $tok; + if ($type == T_VARIABLE) { + $result .= '$t->_vars[\''.substr($str, 1).'\']'; + } else { + $result .= $str; + } + } else { + if ($tok == '.') { $result .= '->'; } elseif ($tok == '~') { $result .= '.'; - } elseif ($tok =='[') { - $result.=$tok; - } elseif ($tok ==']') { - $result.=$tok; } else { $result .= $tok; } diff --git a/ipf/template/context.php b/ipf/template/context.php index 1973bb6..c6fd6c0 100644 --- a/ipf/template/context.php +++ b/ipf/template/context.php @@ -3,6 +3,7 @@ class IPF_Template_Context { public $_vars; + private $stack = array(); function __construct($vars=array()) { @@ -21,5 +22,22 @@ class IPF_Template_Context { $this->_vars[$var] = $value; } + + public function push() + { + $vars = func_get_args(); + $frame = array(); + foreach ($vars as $var) { + $frame[$var] = $this->get($var); + } + $this->stack[] = $frame; + } + + public function pop() + { + $frame = array_pop($this->stack); + foreach ($frame as $var => $val) + $this->set($var, $val); + } }