Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages

Expression.php

Go to the documentation of this file.
00001 <?php 00002 /* vim: set expandtab tabstop=4 shiftwidth=4: */ 00003 // 00004 // Copyright (c) 2003 Laurent Bedubourg 00005 // 00006 // This library is free software; you can redistribute it and/or 00007 // modify it under the terms of the GNU Lesser General Public 00008 // License as published by the Free Software Foundation; either 00009 // version 2.1 of the License, or (at your option) any later version. 00010 // 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 // Lesser General Public License for more details. 00015 // 00016 // You should have received a copy of the GNU Lesser General Public 00017 // License along with this library; if not, write to the Free Software 00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 // 00020 // Authors: Laurent Bedubourg <laurent.bedubourg@free.fr> 00021 // 00022 00023 define('_PHPTAL_ES_RECEIVER_IS_CONTEXT', 1); 00024 define('_PHPTAL_ES_RECEIVER_IS_NONE', 2); 00025 define('_PHPTAL_ES_RECEIVER_IS_TEMP', 4); 00026 define('_PHPTAL_ES_RECEIVER_IS_OUTPUT', 8); 00027 00028 00029 // Important note: 00030 // 00031 // The PHPTALES system works quite well but it's not yet fully optimized, it 00032 // should be refactored at some points of my TODO list. 00033 // 00034 00035 00036 class PHPTAL_Expression 00037 { 00038 var $_tag; 00039 var $_gen; 00040 var $_src; 00041 var $_subs = array(); 00042 var $_policy; 00043 var $_receiver = false; 00044 var $_prepared = false; 00045 var $_structure = false; 00046 00047 function PHPTAL_Expression(&$generator, &$tag, $str) 00048 { 00049 $this->_tag =& $tag; 00050 $this->_gen =& $generator; 00051 $this->_src = $str; 00052 } 00053 00054 function setPolicy($policy) 00055 { 00056 $this->_policy = $policy; 00057 } 00058 00068 function prepare() 00069 { 00070 if ($this->_prepared) { return; } 00071 $test = $this->_src; 00072 00073 // some sub expression detected 00074 while (preg_match('/^(.*?)(?<!;);(?!;)/sm', $test, $m)) { 00075 list($src, $exp) = $m; 00076 00077 $x = new PHPTAL_Expression($this->_gen, $this->_tag, $exp); 00078 $x->setPolicy($this->_policy); 00079 $x->setReceiver($this->getReceiver()); 00080 $err = $x->prepare(); 00081 if (PEAR::isError($err)) { 00082 return $err; 00083 } 00084 $this->_subs[] = $x; 00085 00086 $test = substr($test, strlen($src)); 00087 } 00088 // if subs, insert last one 00089 if ($this->countSubs() > 0 && strlen(trim($test)) > 0) { 00090 $exp = $test; 00091 $x = new PHPTAL_Expression($this->_gen, $this->_tag, $exp); 00092 $x->setPolicy($this->_policy); 00093 $x->setReceiver($this->getReceiver()); 00094 $err = $x->prepare(); 00095 if (PEAR::isError($err)) { 00096 return $err; 00097 } 00098 $this->_subs[] = $x; 00099 } else { 00100 // otherwise, just remove expression delimiters from source 00101 // and apply the receiver policy 00102 $exp = $test; 00103 $exp = str_replace(';;', ';', $exp); 00104 $this->_src = $exp; 00105 if (strlen($exp) == 0) return; 00106 00107 $err = $this->_extractReceiver(); 00108 if (PEAR::isError($err)){ 00109 return $err; 00110 } 00111 00112 if (!$this->_receiver 00113 && ($this->_policy & _PHPTAL_ES_RECEIVER_IS_CONTEXT 00114 || $this->_policy & _PHPTAL_ES_RECEIVER_IS_TEMP)) { 00115 $str = sprintf('Receiver required in expression \'%s\' from %s:%d', 00116 $this->_src, 00117 $this->_tag->_parser->_file, 00118 $this->_tag->line); 00119 $err = new PHPTAL_ExpressionError($str); 00120 return PEAR::raiseError($err); 00121 } 00122 00123 if ($this->_policy & _PHPTAL_ES_RECEIVER_IS_NONE && $this->_receiver) { 00124 $str = sprintf('Unexpected receiver \'%s\' in expression \'%s\' from %s:%d', 00125 $this->_receiver, 00126 $this->_src, 00127 $this->_tag->_parser->_file, 00128 $this->_tag->line); 00129 $err = new PHPTAL_ExpressionError($str); 00130 return PEAR::raiseError($err); 00131 } 00132 } 00133 00134 $this->_prepared = true; 00135 } 00136 00137 function _extractReceiver() 00138 { 00139 global $_phptal_es_namespaces; 00140 00141 $this->_src = preg_replace('/^\s+/sm', '', $this->_src); 00142 if (preg_match('/^([a-z:A-Z_0-9]+)\s+([^\|].*?)$/sm', $this->_src, $m)) { 00143 // the receiver looks like xxxx:aaaa 00144 // 00145 // we must ensure that it's not a known phptales namespaces 00146 if (preg_match('/^([a-zA-Z_0-9]+):/', $m[1], $sub)) { 00147 $ns = $sub[1]; 00148 // known namespace, just break 00149 if (function_exists('phptal_es_'.$ns)) { 00150 // in_array(strtolower($ns), $_phptal_es_namespaces)) { 00151 return; 00152 } 00153 } 00154 00155 if ($this->_receiver) { 00156 $str = sprintf('Receiver already set to \'%s\' in \'%s\'', 00157 $this->_receiver, 00158 $this->_src); 00159 $err = new PHPTAL_ExpressionError($str); 00160 return PEAR::raiseError($err); 00161 } 00162 00163 $this->_receiver = $m[1]; 00164 // 00165 // that the way to replace : in setters (usually this this should 00166 // only be used under tal:attributes tag !!!! 00167 // 00168 $this->_receiver = str_replace(':', '__phptales_dd__', $this->_receiver); 00169 $this->_src = $m[2]; 00170 if ($this->_receiver == "structure") { 00171 $this->_structure = true; 00172 $this->_receiver = false; 00173 $this->_extractReceiver(); 00174 } 00175 } 00176 } 00177 00181 function countSubs() 00182 { 00183 return count($this->_subs); 00184 } 00185 00186 function &subs() 00187 { 00188 return $this->_subs; 00189 } 00190 00194 function hasReceiver() 00195 { 00196 return $this->_receiver != false; 00197 } 00198 00202 function getReceiver() 00203 { 00204 return $this->_receiver; 00205 } 00206 00210 function setReceiver($name) 00211 { 00212 $this->_receiver = $name; 00213 } 00214 00218 function generate() 00219 { 00220 $err = $this->prepare(); 00221 if (PEAR::isError($err)) { 00222 return $err; 00223 } 00224 00225 if ($this->countSubs() > 0) { 00226 foreach ($this->_subs as $sub) { 00227 $err = $sub->generate(); 00228 if (PEAR::isError($err)) { 00229 return $err; 00230 } 00231 } 00232 } else { 00233 $exp = $this->_src; 00234 if (strlen($exp) == 0) return; 00235 00236 // expression may be composed of alternatives | list of expression 00237 // they are evaluated with a specific policy : _PHPTAL_ES_SEQUENCE 00238 // 00239 // 'string:' break the sequence as no alternative exists after a 00240 // string which is always true. 00241 if (preg_match('/\s*?\|\s*?string:/sm', $exp, $m)) { 00242 $search = $m[0]; 00243 $str = strpos($exp, $search); 00244 // $str = strpos($exp, ' | string:'); 00245 // if ($str !== false) { 00246 $seq = preg_split('/(\s*?\|\s*?)/sm', substr($exp, 0, $str)); 00247 $seq[]= substr($exp, $str + 2); 00248 } else { 00249 $seq = preg_split('/(\s*?\|\s*?)/sm', $exp); 00250 } 00251 00252 // not a sequence 00253 if (count($seq) == 1) { 00254 $code = PHPTAL_Expression::_GetCode($this, $exp); 00255 if (PEAR::isError($code)) { return $code; } 00256 00257 $temp = $this->_gen->newTemporaryVar(); 00258 $this->_gen->doAffectResult($temp, $code); 00259 return $this->_useResult($temp); 00260 } else { 00261 return $this->_evaluateSequence($seq); 00262 } 00263 } 00264 } 00265 00266 00267 function _evaluateSequence($seq) 00268 { 00269 $temp = $this->_gen->newTemporaryVar(); 00270 00271 $this->_gen->doDo(); 00272 foreach ($seq as $s) { 00273 // skip empty parts 00274 if (strlen(trim($s)) > 0) { 00275 $code = PHPTAL_Expression::_GetCode($this, $s); 00276 if (PEAR::isError($code)) { return $code; } 00277 00278 $this->_gen->doUnset($temp); 00279 $this->_gen->doAffectResult($temp, $code); 00280 $this->_gen->doIf('!PEAR::isError(' . $temp . ') && ' . 00281 // $temp .' != false && '. 00282 $temp . ' !== null'); 00283 $this->_gen->execute('$__ctx__->_errorRaised = false'); 00284 $this->_gen->execute('break'); 00285 $this->_gen->endBlock(); 00286 } 00287 } 00288 $this->_gen->doEndDoWhile('0'); 00289 // test errorRaised 00290 // error handling, disabled for performance.. 00291 /* $this->_gen->doIf('$__ctx__->_errorRaised'); 00292 $this->_gen->doAffectResult($temp, '$__ctx__->_errorRaised'); 00293 $this->_gen->execute('$__ctx__->_errorRaised = false'); 00294 $this->_gen->endBlock(); */ 00295 00296 $err = $this->_useResult($temp); 00297 00298 // $this->_gen->endBlock(); 00299 return $err; 00300 } 00301 00302 function _useResult($temp) 00303 { 00304 if ($this->_policy & _PHPTAL_ES_RECEIVER_IS_TEMP) { 00305 $this->_gen->doReference($this->_receiver, $temp); 00306 } else if ($this->_policy & _PHPTAL_ES_RECEIVER_IS_OUTPUT) { 00307 $this->_gen->doPrintVar($temp, $this->_structure); 00308 } else if ($this->_policy & _PHPTAL_ES_RECEIVER_IS_CONTEXT) { 00309 $this->_gen->doContextSet($this->_receiver, $temp); 00310 } else { 00311 $err = new PHPTAL_ExpressionError("Expression '$this->_src' Don't know what to do with result."); 00312 return PEAR::raiseError($err); 00313 } 00314 } 00315 00334 function _FindFunctionNamespace($str) 00335 { 00336 $str = preg_replace('/^\s/sm', '', $str); 00337 if (preg_match('/^([a-z0-9\-]+):(?!>:)(.*?)$/ism', $str, $m)) { 00338 list($ns, $path) = array_slice($m, 1); 00339 $ns = str_replace('-', '_', $ns); 00340 return array($ns, $path); 00341 } 00342 return array('path', $str); 00343 } 00344 00348 function _GetCode(&$exp, $str) 00349 { 00350 list($ns, $args) = PHPTAL_Expression::_FindFunctionNamespace($str); 00351 $func = "PHPTAL_ES_$ns"; 00352 if (!function_exists($func)) { 00353 $err = new PHPTAL_ExpressionError("Unknown function $func in '$str'"); 00354 return PEAR::raiseError($err); 00355 } 00356 return $func($exp, $args); 00357 } 00358 } 00359 00363 class PHPTAL_ExpressionError extends PEAR_Error 00364 { 00365 } 00366 00367 ?>

Generated on Tue Jun 29 23:40:03 2004 for Mediawiki by doxygen 1.3.7