Source for file Compiler.php

Documentation is available at Compiler.php

  1. <?php
  2.  
  3. include 'Dwoo/Compilation/Exception.php';
  4.  
  5. /**
  6.  * default dwoo compiler class, compiles dwoo templates into php
  7.  *
  8.  * This software is provided 'as-is', without any express or implied warranty.
  9.  * In no event will the authors be held liable for any damages arising from the use of this software.
  10.  *
  11.  * This file is released under the LGPL
  12.  * "GNU Lesser General Public License"
  13.  * More information can be found here:
  14.  * {@link http://www.gnu.org/copyleft/lesser.html}
  15.  *
  16.  * @author     Jordi Boggiano <j.boggiano@seld.be>
  17.  * @copyright  Copyright (c) 2008, Jordi Boggiano
  18.  * @license    http://www.gnu.org/copyleft/lesser.html  GNU Lesser General Public License
  19.  * @link       http://dwoo.org/
  20.  * @version    0.9.1
  21.  * @date       2008-05-30
  22.  * @package    Dwoo
  23.  */
  24. class Dwoo_Compiler implements Dwoo_ICompiler
  25. {
  26.     /**
  27.      * constant that represents a php opening tag
  28.      *
  29.      * use it in case it needs to be adjusted
  30.      *
  31.      * @var string 
  32.      */
  33.     const PHP_OPEN "<?php ";
  34.  
  35.     /**
  36.      * constant that represents a php closing tag
  37.      *
  38.      * use it in case it needs to be adjusted
  39.      *
  40.      * @var string 
  41.      */
  42.     const PHP_CLOSE "?>";
  43.  
  44.     /**
  45.      * boolean flag to enable or disable debugging output
  46.      *
  47.      * @var bool 
  48.      */
  49.     public $debug = false;
  50.  
  51.     /**
  52.      * left script delimiter
  53.      *
  54.      * @var string 
  55.      */
  56.     protected $ld = '{';
  57.  
  58.     /**
  59.      * left script delimiter with escaped regex meta characters
  60.      *
  61.      * @var string 
  62.      */
  63.     protected $ldr = '\\{';
  64.  
  65.     /**
  66.      * right script delimiter
  67.      *
  68.      * @var string 
  69.      */
  70.     protected $rd = '}';
  71.  
  72.     /**
  73.      * right script delimiter with escaped regex meta characters
  74.      *
  75.      * @var string 
  76.      */
  77.     protected $rdr = '\\}';
  78.  
  79.     /**
  80.      * defines whether opening and closing tags can contain spaces before valid data or not
  81.      *
  82.      * turn to true if you want to be sloppy with the syntax, but when set to false it allows
  83.      * to skip javascript and css tags as long as they are in the form "{ something", which is
  84.      * nice. default is false.
  85.      *
  86.      * @var bool 
  87.      */
  88.     protected $allowLooseOpenings = false;
  89.  
  90.     /**
  91.      * defines whether the compiler will automatically html-escape variables or not
  92.      *
  93.      * default is false
  94.      *
  95.      * @var bool 
  96.      */
  97.     protected $autoEscape = false;
  98.  
  99.     /**
  100.      * security policy object
  101.      *
  102.      * @var Dwoo_Security_Policy 
  103.      */
  104.     protected $securityPolicy;
  105.  
  106.     /**
  107.      * storage for parse errors/warnings
  108.      *
  109.      * will be deprecated when proper exceptions are added
  110.      *
  111.      * @var array 
  112.      */
  113.     protected $errors = array();
  114.  
  115.     /**
  116.      * stores the custom plugins registered with this compiler
  117.      *
  118.      * @var array 
  119.      */
  120.     protected $customPlugins = array();
  121.  
  122.     /**
  123.      * stores the pre- and post-processors callbacks
  124.      *
  125.      * @var array 
  126.      */
  127.     protected $processors = array('pre'=>array()'post'=>array());
  128.  
  129.     /**
  130.      * stores a list of plugins that are used in the currently compiled
  131.      * template, and that are not compilable. these plugins will be loaded
  132.      * during the template's runtime if required.
  133.      *
  134.      * it is a 1D array formatted as key:pluginName value:pluginType
  135.      *
  136.      * @var array 
  137.      */
  138.     protected $usedPlugins;
  139.  
  140.     /**
  141.      * stores the template undergoing compilation
  142.      *
  143.      * @var string 
  144.      */
  145.     protected $template;
  146.  
  147.     /**
  148.      * stores the current pointer position inside the template
  149.      *
  150.      * @var int 
  151.      */
  152.     protected $pointer;
  153.  
  154.     /**
  155.      * stores the data within which the scope moves
  156.      *
  157.      * @var array 
  158.      */
  159.     protected $data;
  160.  
  161.     /**
  162.      * variable scope of the compiler, set to null if
  163.      * it can not be resolved to a static string (i.e. if some
  164.      * plugin defines a new scope based on a variable array key)
  165.      *
  166.      * @var mixed 
  167.      */
  168.     protected $scope;
  169.  
  170.     /**
  171.      * variable scope tree, that allows to rebuild the current
  172.      * scope if required, i.e. when going to a parent level
  173.      *
  174.      * @var array 
  175.      */
  176.     protected $scopeTree;
  177.  
  178.     /**
  179.      * block plugins stack, accessible through some methods
  180.      *
  181.      * @see findBlock
  182.      * @see getCurrentBlock
  183.      * @see addBlock
  184.      * @see addCustomBlock
  185.      * @see injectBlock
  186.      * @see removeBlock
  187.      * @see removeTopBlock
  188.      *
  189.      * @var array 
  190.      */
  191.     protected $stack = array();
  192.  
  193.     /**
  194.      * current block at the top of the block plugins stack,
  195.      * accessible through getCurrentBlock
  196.      *
  197.      * @see getCurrentBlock
  198.      *
  199.      * @var Dwoo_Block_Plugin 
  200.      */
  201.     protected $curBlock;
  202.  
  203.     /**
  204.      * holds an instance of this class, used by getInstance when you don't
  205.      * provide a custom compiler in order to save resources
  206.      *
  207.      * @var Dwoo_Compiler 
  208.      */
  209.     protected static $instance;
  210.  
  211.     /**
  212.      * sets the delimiters to use in the templates
  213.      *
  214.      * delimiters can be multi-character strings but should not be one of those as they will
  215.      * make it very hard to work with templates or might even break the compiler entirely : "\", "$", "|", ":" and finally "#" only if you intend to use config-vars with the #var# syntax.
  216.      *
  217.      * @param string $left left delimiter
  218.      * @param string $right right delimiter
  219.      */
  220.     public function setDelimiters($left$right)
  221.     {
  222.         $this->ld = $left;
  223.         $this->rd = $right;
  224.         $this->ldr = preg_quote($left'/');
  225.         $this->rdr = preg_quote($right'/');
  226.     }
  227.  
  228.     /**
  229.      * returns the left and right template delimiters
  230.      *
  231.      * @return array containing the left and the right delimiters
  232.      */
  233.     public function getDelimiters()
  234.     {
  235.         return array($this->ld$this->rd);
  236.     }
  237.  
  238.     /**
  239.      * sets the tag openings handling strictness, if set to true, template tags can
  240.      * contain spaces before the first function/string/variable such as { $foo} is valid.
  241.      *
  242.      * if set to false (default setting), { $foo} is invalid but that is however a good thing
  243.      * as it allows css (i.e. #foo { color:red; }) to be parsed silently without triggering
  244.      * an error, same goes for javascript.
  245.      *
  246.      * @param bool $allow true to allow loose handling, false to restore default setting
  247.      */
  248.     public function setLooseOpeningHandling($allow false)
  249.     {
  250.         $this->allowLooseOpenings = (bool) $allow;
  251.     }
  252.  
  253.     /**
  254.      * returns the tag openings handling strictness setting
  255.      *
  256.      * @see setLooseOpeningHandling
  257.      * @return bool true if loose tags are allowed
  258.      */
  259.     public function getLooseOpeningHandling()
  260.     {
  261.         return $this->allowLooseOpenings;
  262.     }
  263.  
  264.     /**
  265.      * changes the auto escape setting
  266.      *
  267.      * if enabled, the compiler will automatically html-escape variables,
  268.      * unless they are passed through the safe function such as {$var|safe}
  269.      * or {safe $var}
  270.      *
  271.      * default setting is disabled/false
  272.      *
  273.      * @param bool $enabled set to true to enable, false to disable
  274.      */
  275.     public function setAutoEscape($enabled)
  276.     {
  277.         $this->autoEscape = $enabled;
  278.     }
  279.  
  280.     /**
  281.      * returns the auto escape setting
  282.      *
  283.      * default setting is disabled/false
  284.      *
  285.      * @return bool 
  286.      */
  287.     public function getAutoEscape()
  288.     {
  289.         return $this->autoEscape;
  290.     }
  291.  
  292.     /**
  293.      * adds a preprocessor to the compiler, it will be called
  294.      * before the template is compiled
  295.      *
  296.      * @param mixed $callback either a valid callback to the preprocessor or a simple name if the autoload is set to true
  297.      * @param bool $autoload if set to true, the preprocessor is auto-loaded from one of the plugin directories, else you must provide a valid callback
  298.      */
  299.     public function addPreProcessor($callback$autoload false)
  300.     {
  301.         if ($autoload{
  302.             $name str_replace('Dwoo_Processor_'''$callback);
  303.             $class 'Dwoo_Processor_'.$name;
  304.  
  305.             if (class_exists($classfalse)) {
  306.                 $callback array(new $class($this)'process');
  307.             elseif (function_exists($class)) {
  308.                 $callback $class;
  309.             else {
  310.                 $callback array('autoload'=>true'class'=>$class'name'=>$name);
  311.             }
  312.  
  313.             $this->processors['pre'][$callback;
  314.         else {
  315.             $this->processors['pre'][$callback;
  316.         }
  317.     }
  318.  
  319.     /**
  320.      * removes a preprocessor from the compiler
  321.      *
  322.      * @param mixed $callback either a valid callback to the preprocessor or a simple name if it was autoloaded
  323.      */
  324.     public function removePreProcessor($callback)
  325.     {
  326.         if (($index array_search($callback$this->processors['pre']true)) !== false{
  327.             unset($this->processors['pre'][$index]);
  328.         elseif (($index array_search('Dwoo_Processor_'.str_replace('Dwoo_Processor_'''$callback)$this->processors['pre']true)) !== false{
  329.             unset($this->processors['pre'][$index]);
  330.         else {
  331.             $class 'Dwoo_Processor_' str_replace('Dwoo_Processor_'''$callback);
  332.             foreach ($this->processors['pre'as $index=>$proc{
  333.                 if (is_array($proc&& ($proc[0instanceof $class|| (isset($proc['class']&& $proc['class'== $class)) {
  334.                     unset($this->processors['pre'][$index]);
  335.                     break;
  336.                 }
  337.             }
  338.         }
  339.     }
  340.  
  341.     /**
  342.      * adds a postprocessor to the compiler, it will be called
  343.      * before the template is compiled
  344.      *
  345.      * @param mixed $callback either a valid callback to the postprocessor or a simple name if the autoload is set to true
  346.      * @param bool $autoload if set to true, the postprocessor is auto-loaded from one of the plugin directories, else you must provide a valid callback
  347.      */
  348.     public function addPostProcessor($callback$autoload false)
  349.     {
  350.         if ($autoload{
  351.             $name str_replace('Dwoo_Processor_'''$callback);
  352.             $class 'Dwoo_Processor_'.$name;
  353.  
  354.             if (class_exists($classfalse)) {
  355.                 $callback array(new $class($this)'process');
  356.             elseif (function_exists($class)) {
  357.                 $callback $class;
  358.             else {
  359.                 $callback array('autoload'=>true'class'=>$class'name'=>$name);
  360.             }
  361.  
  362.             $this->processors['post'][$callback;
  363.         else {
  364.             $this->processors['post'][$callback;
  365.         }
  366.     }
  367.     
  368.     /**
  369.      * removes a postprocessor from the compiler
  370.      *
  371.      * @param mixed $callback either a valid callback to the postprocessor or a simple name if it was autoloaded
  372.      */
  373.     public function removePostProcessor($callback)
  374.     {
  375.         if (($index array_search($callback$this->processors['post']true)) !== false{
  376.             unset($this->processors['post'][$index]);
  377.         elseif (($index array_search('Dwoo_Processor_'.str_replace('Dwoo_Processor_'''$callback)$this->processors['post']true)) !== false{
  378.             unset($this->processors['post'][$index]);
  379.         else    {
  380.             $class 'Dwoo_Processor_' str_replace('Dwoo_Processor_'''$callback);
  381.             foreach ($this->processors['post'as $index=>$proc{
  382.                 if (is_array($proc&& ($proc[0instanceof $class|| (isset($proc['class']&& $proc['class'== $class)) {
  383.                     unset($this->processors['post'][$index]);
  384.                     break;
  385.                 }
  386.             }
  387.         }
  388.     }
  389.     
  390.     /**
  391.      * internal function to autoload processors at runtime if required
  392.      * 
  393.      * @param string $class the class/function name
  394.      * @param string $name the plugin name (without Dwoo_Plugin_ prefix)
  395.      */
  396.     protected function loadProcessor($class$name)
  397.     {
  398.         if (!class_exists($classfalse&& !function_exists($class)) {
  399.             try {
  400.                 $this->dwoo->getLoader()->loadPlugin($name);
  401.             catch (Dwoo_Exception $e{
  402.                 throw new Dwoo_Exception('Processor '.$name.' could not be found in your plugin directories, please ensure it is in a file named '.$name.'.php in the plugin directory');
  403.             }
  404.         }
  405.         
  406.         if (class_exists($classfalse)) {
  407.             return array(new $class($this)'process');
  408.         
  409.  
  410.         if (function_exists($class)) {
  411.             return $class;
  412.         
  413.         
  414.         throw new Dwoo_Exception('Wrong processor name, when using autoload the processor must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Processor_name"');
  415.     }
  416.  
  417.     /**
  418.      * adds the custom plugins loaded into Dwoo to the compiler so it can load them
  419.      *
  420.      * @see Dwoo::addPlugin
  421.      * @param array $customPlugins an array of custom plugins
  422.      */
  423.     public function setCustomPlugins(array $customPlugins)
  424.     {
  425.         $this->customPlugins $customPlugins;
  426.     }
  427.  
  428.     /**
  429. /**
  430.      * sets the security policy object to enforce some php security settings
  431.      *
  432.      * use this if untrusted persons can modify templates,
  433.      * set it on the Dwoo object as it will be passed onto the compiler automatically
  434.      *
  435.      * @param Dwoo_Security_Policy $policy the security policy object
  436.      */
  437.     public function setSecurityPolicy(Dwoo_Security_Policy $policy null)
  438.     {
  439.         $this->securityPolicy = $policy;
  440.     }
  441.  
  442.     /**
  443.      * returns the current security policy object or null by default
  444.      *
  445.      * @return Dwoo_Security_Policy|nullthe security policy object if any
  446.      */
  447.     public function getSecurityPolicy()
  448.     {
  449.         return $this->securityPolicy;
  450.     }
  451.  
  452.     /**
  453.      * sets the pointer position
  454.      *
  455.      * @param int $position the new pointer position
  456.      * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
  457.      */
  458.     public function setPointer($position$isOffset false)
  459.     {
  460.         if ($isOffset{
  461.             $this->pointer += $position;
  462.         else {
  463.             $this->pointer = $position;
  464.         }
  465.     }
  466.  
  467.     /**
  468.      * returns the current pointer position, only available during compilation of a template
  469.      *
  470.      * @return int 
  471.      */
  472.     public function getPointer()
  473.     {
  474.         return $this->pointer;
  475.     }
  476.  
  477.     /**
  478.      * sets the line number
  479.      *
  480.      * @param int $number the new line number
  481.      * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
  482.      */
  483.     public function setLine($number$isOffset false)
  484.     {
  485.         if ($isOffset{
  486.             $this->line += $number;
  487.         else {
  488.             $this->line $number;
  489.         }
  490.     }
  491.  
  492.     /**
  493.      * returns the current line number, only available during compilation of a template
  494.      *
  495.      * @return int 
  496.      */
  497.     public function getLine()
  498.     {
  499.         return $this->line;
  500.     }
  501.  
  502.     /**
  503.      * returns the dwoo object that initiated this template compilation, only available during compilation of a template
  504.      *
  505.      * @return Dwoo 
  506.      */
  507.     public function getDwoo()
  508.     {
  509.         return $this->dwoo;
  510.     }
  511.  
  512.     /**
  513.      * overwrites the template that is being compiled
  514.      *
  515.      * @param string $newSource the template source that must replace the current one
  516.      * @param bool $fromPointer if set to true, only the source from the current pointer position is replaced
  517.      * @return string the template or partial template
  518.      */
  519.     public function setTemplateSource($newSource$fromPointer false)
  520.     {
  521.         if ($fromPointer === true{
  522.             $this->templateSource substr($this->templateSource0$this->pointer$newSource;
  523.         else {
  524.             $this->templateSource $newSource;
  525.         }
  526.     }
  527.  
  528.     /**
  529.      * returns the template that is being compiled
  530.      *
  531.      * @param bool $fromPointer if set to true, only the source from the current pointer position is returned
  532.      * @return string the template or partial template
  533.      */
  534.     public function getTemplateSource($fromPointer false)
  535.     {
  536.         if ($fromPointer{
  537.             return substr($this->templateSource$this->pointer);
  538.         else {
  539.             return $this->templateSource;
  540.         }
  541.     }
  542.  
  543.     /**
  544.      * compiles the provided string down to php code
  545.      *
  546.      * @param string $tpl the template to compile
  547.      * @return string a compiled php string
  548.      */
  549.     public function compile(Dwoo $dwooDwoo_ITemplate $template)
  550.     {
  551.         // init vars
  552.         $tpl $template->getSource();
  553.         $ptr 0;
  554.         $this->dwoo $dwoo;
  555.         $this->template = $template;
  556.         $this->templateSource =$tpl;
  557.         $this->pointer =$ptr;
  558.  
  559.         if ($this->debugecho 'PROCESSING PREPROCESSORS<br>';
  560.  
  561.         // runs preprocessors
  562.         foreach ($this->processors['pre'as $preProc{
  563.             if (is_array($preProc&& isset($preProc['autoload'])) {
  564.                 $preProc $this->loadProcessor($preProc['class']$preProc['name']);
  565.             }
  566.             if (is_array($preProc&& $preProc[0instanceof Dwoo_Processor{
  567.                 $tpl call_user_func($preProc$tpl);
  568.             else {
  569.                 $tpl call_user_func($preProc$this$tpl);
  570.             }
  571.         }
  572.         unset($preProc);
  573.  
  574.         if ($this->debugecho '<pre>'.print_r(htmlentities($tpl)true).'</pre><hr />';
  575.  
  576.         // strips comments
  577.         if (strstr($tpl$this->ld.'*'!== false{
  578.             $tpl preg_replace('/'.$this->ldr.'\*.*?\*'.$this->rdr.'/s'''$tpl);
  579.         }
  580.  
  581.         // strips php tags if required by the security policy
  582.         if ($this->securityPolicy !== null{
  583.             $search array('{<\?php.*?\?>}');
  584.             if (ini_get('short_open_tags')) {
  585.                 $search array('{<\?.*?\?>}''{<%.*?%>}');
  586.             }
  587.             switch($this->securityPolicy->getPhpHandling()) {
  588.  
  589.             case Dwoo_Security_Policy::PHP_ALLOW:
  590.                 break;
  591.             case Dwoo_Security_Policy::PHP_ENCODE:
  592.                 $tpl preg_replace_callback($searcharray($this'phpTagEncodingHelper')$tpl);
  593.                 break;
  594.             case Dwoo_Security_Policy::PHP_REMOVE:
  595.                 $tpl preg_replace($search''$tpl);
  596.  
  597.             }
  598.         }
  599.  
  600.         while (true{
  601.             // if pointer is at the beginning, reset everything, that allows a plugin to externally reset the compiler if everything must be reparsed
  602.             if ($ptr===0{
  603.                 // resets variables
  604.                 $this->usedPlugins = array();
  605.                 $this->data = array();
  606.                 $this->scope =$this->data;
  607.                 $this->scopeTree = array();
  608.                 $this->stack = array();
  609.                 $this->line 1;
  610.                 // add top level block
  611.                 $compiled $this->addBlock('topLevelBlock'array()0);
  612.                 $this->stack[0]['buffer''';
  613.             }
  614.  
  615.             $pos strpos($tpl$this->ld$ptr);
  616.  
  617.             if ($pos === false{
  618.                 $this->push(substr($tpl$ptr)0);
  619.                 break;
  620.             elseif (substr($tpl$pos-11=== '\\' && substr($tpl$pos-21!== '\\'{
  621.                 $this->push(substr($tpl$ptr$pos-$ptr-1$this->ld);
  622.                 $ptr $pos+strlen($this->ld);
  623.             elseif (preg_match('/^'.$this->ldr . ($this->allowLooseOpenings ? '\s*' '''literal' ($this->allowLooseOpenings ? '\s*' ''$this->rdr.'/s'substr($tpl$pos)$litOpen)) {
  624.                 if (!preg_match('/'.$this->ldr . ($this->allowLooseOpenings ? '\s*' '''\/literal' ($this->allowLooseOpenings ? '\s*' ''$this->rdr.'/s'$tpl$litClosePREG_OFFSET_CAPTURE$pos)) {
  625.                     throw new Dwoo_Compilation_Exception($this'The {literal} blocks must be closed explicitly with {/literal}');
  626.                 }
  627.                 $endpos $litClose[0][1];
  628.                 $this->push(substr($tpl$ptr$pos-$ptrsubstr($tpl$pos strlen($litOpen[0])$endpos-$pos-strlen($litOpen[0])));
  629.                 $ptr $endpos+strlen($litClose[0][0]);
  630.             else {
  631.                 if (substr($tpl$pos-21=== '\\' && substr($tpl$pos-11=== '\\'{
  632.                     $this->push(substr($tpl$ptr$pos-$ptr-1));
  633.                     $ptr $pos;
  634.                 }
  635.  
  636.                 $this->push(substr($tpl$ptr$pos-$ptr));
  637.  
  638.                 $pos += strlen($this->ld);
  639.                 if ($this->allowLooseOpenings{
  640.                     while (substr($tpl$pos1=== ' '{
  641.                         $pos+=1;
  642.                     }
  643.                 else {
  644.                     if (substr($tpl$pos1=== ' ' || substr($tpl$pos1=== "\r" || substr($tpl$pos1=== "\n" || substr($tpl$pos1=== "\t"{
  645.                         $ptr $pos;
  646.                         $this->push($this->ld);
  647.                         continue;
  648.                     }
  649.                 }
  650.  
  651.                 $endpos strpos($tpl$this->rd$pos);
  652.  
  653.                 if ($endpos===false{
  654.                     throw new Dwoo_Compilation_Exception($this'A template tag was not closed, started with <em>'.substr($tpl$pos20).'</em>');
  655.                 }
  656.  
  657.                 while (substr($tpl$endpos-11=== '\\'{
  658.                     $tpl substr_replace($tpl$this->rd$endpos-11+strlen($this->rd));
  659.                     $endpos strpos($tpl$this->rd$endpos);
  660.                 }
  661.  
  662.                 $ptr $endpos+strlen($this->rd);
  663.  
  664.                 $lines substr_count(substr($tpl$pos$endpos-$pos)"\n");
  665.  
  666.                 if (substr($tpl$pos1)==='/'{
  667.                     if (substr($tpl$pos$endpos-$pos=== '/'{
  668.                         $this->push($this->removeTopBlock()$lines);
  669.                     else {
  670.                         $this->push($this->removeBlock(substr($tpl$pos+1$endpos-$pos-1))$lines);
  671.                     }
  672.                 else {
  673.                     $this->push($this->parse($tpl$pos$endposfalse'root')$lines);
  674.                 }
  675.  
  676.                 // adds additional line breaks between php closing and opening tags because the php parser removes those if there is just a single line break
  677.                 if (substr($this->curBlock['buffer']-2=== '?>' && preg_match('{^(([\r\n])([\r\n]?))}'substr($tpl$ptr3)$m)) {
  678.                     if ($m[3=== ''{
  679.                         $ptr+=1;
  680.                         $this->push($m[1].$m[1]1);
  681.                     else {
  682.                         $ptr+=2;
  683.                         $this->push($m[1]."\n"2);
  684.                     }
  685.                 }
  686.             }
  687.         }
  688.  
  689.         $compiled .= $this->removeBlock('topLevelBlock');
  690.  
  691.         if ($this->debugecho 'PROCESSING POSTPROCESSORS<br>';
  692.  
  693.         foreach ($this->processors['post'as $postProc{
  694.             if (is_array($postProc&& isset($postProc['autoload'])) {
  695.                 $postProc $this->loadProcessor($postProc['class']$postProc['name']);
  696.             }
  697.             if (is_array($postProc&& $postProc[0instanceof Dwoo_Processor{
  698.                 $compiled call_user_func($postProc$compiled);
  699.             else {
  700.                 $compiled call_user_func($postProc$this$compiled);
  701.             }
  702.         }
  703.         unset($postProc);
  704.  
  705.         if ($this->debugecho 'COMPILATION COMPLETE : MEM USAGE : '.memory_get_usage().'<br>';
  706.  
  707.         $output "<?php\n";
  708.  
  709.         // build plugin preloader
  710.         foreach ($this->usedPlugins as $plugin=>$type{
  711.             if ($type Dwoo::CUSTOM_PLUGINcontinue;
  712.             switch($type{
  713.  
  714.             case Dwoo::BLOCK_PLUGIN:
  715.             case Dwoo::CLASS_PLUGIN:
  716.                 $output .= "if (class_exists('Dwoo_Plugin_$plugin', false)===false)\n\t\$this->loader->loadPlugin('$plugin');\n";
  717.                 break;
  718.             case Dwoo::FUNC_PLUGIN:
  719.                 $output .= "if (function_exists('Dwoo_Plugin_$plugin')===false)\n\t\$this->loader->loadPlugin('$plugin');\n";
  720.                 break;
  721.             case Dwoo::SMARTY_MODIFIER:
  722.                 $output .= "if (function_exists('smarty_modifier_$plugin')===false)\n\t\$this->loader->loadPlugin('$plugin');\n";
  723.                 break;
  724.             case Dwoo::SMARTY_FUNCTION:
  725.                 $output .= "if (function_exists('smarty_function_$plugin')===false)\n\t\$this->loader->loadPlugin('$plugin');\n";
  726.                 break;
  727.             case Dwoo::SMARTY_BLOCK:
  728.                 $output .= "if (function_exists('smarty_block_$plugin')===false)\n\t\$this->loader->loadPlugin('$plugin');\n";
  729.                 break;
  730.             default:
  731.                 throw new Dwoo_Compilation_Exception($this'Type error for '.$plugin.' with type'.$type);
  732.  
  733.             }
  734.         }
  735.  
  736.         $output .= $compiled."\n?>";
  737.  
  738.         $output preg_replace('/(?<!;|\})(\s*'.preg_quote(self::PHP_CLOSE'/'preg_quote(self::PHP_OPEN'/').')/'";\n"$output);
  739.         $output str_replace(self::PHP_CLOSE self::PHP_OPEN"\n"$output);
  740.  
  741.         if ($this->debug{
  742.             echo '<hr><pre>';
  743.             $lines preg_split('{\r\n|\n|<br />}'highlight_string(($output)true));
  744.             array_shift($lines);
  745.             foreach ($lines as $i=>$line{
  746.                 echo ($i+1).'. '.$line."\r\n";
  747.             }
  748.         }
  749.         if ($this->debugecho '<hr></pre></pre>';
  750.  
  751.         if (!empty($this->errors)) {
  752.             print_r($this->errors);
  753.         }
  754.  
  755.         $this->template = $this->dwoo null;
  756.         $tpl null;
  757.  
  758.         return $output;
  759.     }
  760.  
  761.     /**
  762.      * adds compiled content to the current block
  763.      *
  764.      * @param string $content the content to push
  765.      * @param int $lineCount newlines count in content, optional
  766.      */
  767.     public function push($content$lineCount null)
  768.     {
  769.         if ($lineCount === null{
  770.             $lineCount substr_count($content"\n");
  771.         }
  772.  
  773.         if ($this->curBlock['buffer'=== null && count($this->stack1{
  774.             // buffer is not initialized yet (the block has just been created)
  775.             $this->stack[count($this->stack)-2]['buffer'.= (string) $content;
  776.             $this->curBlock['buffer''';
  777.         else {
  778.             // append current content to current block's buffer
  779.             $this->curBlock['buffer'.= (string) $content;
  780.         }
  781.         $this->line += $lineCount;
  782.     }
  783.  
  784.     /**
  785.      * sets the scope
  786.      *
  787.      * set to null if the scope becomes "unstable" (i.e. too variable or unknown) so that
  788.      * variables are compiled in a more evaluative way than just $this->scope['key']
  789.      *
  790.      * @param mixed $scope a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
  791.      * @param bool $absolute if true, the scope is set from the top level scope and not from the current scope
  792.      * @return array the current scope tree
  793.      */
  794.     public function setScope($scope$absolute false)
  795.     {
  796.         $old $this->scopeTree;
  797.  
  798.         if ($scope===null{
  799.             unset($this->scope);
  800.             $this->scope = null;
  801.         }
  802.  
  803.         if (is_array($scope)===false{
  804.             $scope explode('.'$scope);
  805.         }
  806.  
  807.         if ($absolute===true{
  808.             $this->scope =$this->data;
  809.             $this->scopeTree = array();
  810.         }
  811.  
  812.         while (($bit array_shift($scope)) !== null{
  813.             if ($bit === '_parent' || $bit === '_'{
  814.                 array_pop($this->scopeTree);
  815.                 reset($this->scopeTree);
  816.                 $this->scope =$this->data;
  817.                 $cnt count($this->scopeTree);
  818.                 for ($i=0;$i<$cnt;$i++)
  819.                     $this->scope =$this->scope[$this->scopeTree[$i]];
  820.             elseif ($bit === '_root' || $bit === '__'{
  821.                 $this->scope =$this->data;
  822.                 $this->scopeTree = array();
  823.             elseif (isset($this->scope[$bit])) {
  824.                 $this->scope =$this->scope[$bit];
  825.                 $this->scopeTree[$bit;
  826.             else {
  827.                 $this->scope[$bitarray();
  828.                 $this->scope =$this->scope[$bit];
  829.                 $this->scopeTree[$bit;
  830.             }
  831.         }
  832.  
  833.         return $old;
  834.     }
  835.  
  836.     /**
  837.      * forces an absolute scope
  838.      *
  839.      * @deprecated
  840.      * @param mixed $scope a scope as a string or array
  841.      * @return array the current scope tree
  842.      */
  843.     public function forceScope($scope)
  844.     {
  845.         return $this->setScope($scopetrue);
  846.     }
  847.  
  848.     /**
  849.      * adds a block to the top of the block stack
  850.      *
  851.      * @param string $type block type (name)
  852.      * @param array $params the parameters array
  853.      * @param int $paramtype the parameters type (see mapParams), 0, 1 or 2
  854.      * @return string the preProcessing() method's output
  855.      */
  856.     public function addBlock($typearray $params$paramtype)
  857.     {
  858.         $class 'Dwoo_Plugin_'.$type;
  859.         if (class_exists($classfalse=== false{
  860.             $this->dwoo->getLoader()->loadPlugin($type);
  861.         }
  862.  
  863.         $params $this->mapParams($paramsarray($class'init')$paramtype);
  864.  
  865.         $this->stack[array('type' => $type'params' => $params'custom' => false'buffer' => null);
  866.         $this->curBlock =$this->stack[count($this->stack)-1];
  867.         return call_user_func(array($class,'preProcessing')$this$params''''$type);
  868.     }
  869.  
  870.     /**
  871.      * adds a custom block to the top of the block stack
  872.      *
  873.      * @param string $type block type (name)
  874.      * @param array $params the parameters array
  875.      * @param int $paramtype the parameters type (see mapParams), 0, 1 or 2
  876.      * @return string the preProcessing() method's output
  877.      */
  878.     public function addCustomBlock($typearray $params$paramtype)
  879.     {
  880.         $callback $this->customPlugins[$type]['callback'];
  881.         if (is_array($callback)) {
  882.             $class is_object($callback[0]get_class($callback[0]$callback[0];
  883.         else {
  884.             $class $callback;
  885.         }
  886.  
  887.         $params $this->mapParams($paramsarray($class'init')$paramtype);
  888.  
  889.         $this->stack[array('type' => $type'params' => $params'custom' => true'class'=>$class'buffer' => null);
  890.         $this->curBlock =$this->stack[count($this->stack)-1];
  891.         return call_user_func(array($class,'preProcessing')$this$params''''$type);
  892.     }
  893.  
  894.     /**
  895.      * injects a block at the top of the plugin stack without calling its preProcessing method
  896.      *
  897.      * used by {else} blocks to re-add themselves after having closed everything up to their parent
  898.      *
  899.      * @param string $type block type (name)
  900.      * @param array $params parameters array
  901.      */
  902.     public function injectBlock($typearray $params)
  903.     {
  904.         $class 'Dwoo_Plugin_'.$type;
  905.         if (class_exists($classfalse=== false{
  906.             $this->dwoo->getLoader()->loadPlugin($type);
  907.         }
  908.         $this->stack[array('type' => $type'params' => $params'custom' => false'buffer' => null);
  909.         $this->curBlock =$this->stack[count($this->stack)-1];
  910.     }
  911.  
  912.     /**
  913.      * removes the closest-to-top block of the given type and all other
  914.      * blocks encountered while going down the block stack
  915.      *
  916.      * @param string $type block type (name)
  917.      * @return string the output of all postProcessing() method's return values of the closed blocks
  918.      */
  919.     public function removeBlock($type)
  920.     {
  921.         $output '';
  922.  
  923.         $pluginType $this->getPluginType($type);
  924.         if ($pluginType Dwoo::SMARTY_BLOCK{
  925.             $type 'smartyinterface';
  926.         }
  927.         while (true{
  928.             while ($top array_pop($this->stack)) {
  929.                 if ($top['custom']{
  930.                     $class $top['class'];
  931.                 else {
  932.                     $class 'Dwoo_Plugin_'.$top['type'];
  933.                 }
  934.                 if (count($this->stack)) {
  935.                     $this->curBlock =$this->stack[count($this->stack)-1];
  936.                     $this->push(call_user_func(array($class'postProcessing')$this$top['params']''''$top['buffer'])0);
  937.                 else {
  938.                     $null null;
  939.                     $this->curBlock =$null;
  940.                     $output call_user_func(array($class'postProcessing')$this$top['params']''''$top['buffer']);
  941.                 }
  942.  
  943.                 if ($top['type'=== $type{
  944.                     break 2;
  945.                 }
  946.             }
  947.  
  948.             throw new Dwoo_Compilation_Exception($this'Syntax malformation, a block of type "'.$type.'" was closed but was not opened');
  949.             break;
  950.         }
  951.  
  952.         return $output;
  953.     }
  954.  
  955.     /**
  956.      * returns a reference to the first block of the given type encountered and
  957.      * optionally closes all blocks until it finds it
  958.      *
  959.      * this is mainly used by {else} plugins to close everything that was opened
  960.      * between their parent and themselves
  961.      *
  962.      * @param string $type the block type (name)
  963.      * @param bool $closeAlong whether to close all blocks encountered while going down the block stack or not
  964.      * @return &array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
  965.      *                    'custom'=>bool defining whether it's a custom plugin or not, for internal use)
  966.      */
  967.     public function &findBlock($type$closeAlong false)
  968.     {
  969.         if ($closeAlong===true{
  970.             while ($b end($this->stack)) {
  971.                 if ($b['type']===$type{
  972.                     return $this->stack[key($this->stack)];
  973.                 }
  974.                 $this->removeTopBlock();
  975.             }
  976.         else {
  977.             end($this->stack);
  978.             while ($b current($this->stack)) {
  979.                 if ($b['type']===$type{
  980.                     return $this->stack[key($this->stack)];
  981.                 }
  982.                 prev($this->stack);
  983.             }
  984.         }
  985.  
  986.         throw new Dwoo_Compilation_Exception($this'A parent block of type "'.$type.'" is required and can not be found');
  987.     }
  988.  
  989.     /**
  990.      * returns a reference to the current block array
  991.      *
  992.      * @return &array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
  993.      *                    'custom'=>bool defining whether it's a custom plugin or not, for internal use)
  994.      */
  995.     public function &getCurrentBlock()
  996.     {
  997.         return $this->curBlock;
  998.     }
  999.  
  1000.     /**
  1001.      * removes the block at the top of the stack and calls its postProcessing() method
  1002.      *
  1003.      * @return string the postProcessing() method's output
  1004.      */
  1005.     public function removeTopBlock()
  1006.     {
  1007.         $o array_pop($this->stack);
  1008.         if ($o === null{
  1009.             throw new Dwoo_Compilation_Exception($this'Syntax malformation, a block of unknown type was closed but was not opened.');
  1010.         }
  1011.         if ($o['custom']{
  1012.             $class $o['class'];
  1013.         else {
  1014.             $class 'Dwoo_Plugin_'.$o['type'];
  1015.         }
  1016.  
  1017.         $this->curBlock =$this->stack[count($this->stack)-1];
  1018.  
  1019.         return call_user_func(array($class'postProcessing')$this$o['params']''''$o['buffer']);
  1020.     }
  1021.  
  1022.     /**
  1023.      * returns the compiled parameters (for example a variable's compiled parameter will be "$this->scope['key']") out of the given parameter array
  1024.      *
  1025.      * @param array $params parameter array
  1026.      * @return array filtered parameters
  1027.      */
  1028.     public function getCompiledParams(array $params)
  1029.     {
  1030.         foreach ($params as &$p)
  1031.             $p $p[0];
  1032.         return $params;
  1033.     
  1034.  
  1035.     /**
  1036.      * returns the real parameters (for example a variable's real parameter will be its key, etc) out of the given parameter array
  1037.      *
  1038.      * @param array $params parameter array
  1039.      * @return array filtered parameters
  1040.      */
  1041.     public function getRealParams(array $params)
  1042.     {
  1043.         foreach ($params as &$p)
  1044.             $p $p[1];
  1045.         return $params;
  1046.     
  1047.  
  1048.     /**
  1049.      * entry point of the parser, it redirects calls to other parse* functions
  1050.      *
  1051.      * @param string $in the string within which we must parse something
  1052.      * @param int $from the starting offset of the parsed area
  1053.      * @param int $to the ending offset of the parsed area
  1054.      * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default
  1055.      * @param string $curBlock the current parser-block being processed
  1056.      * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default
  1057.      * @return string parsed values
  1058.      */
  1059.     protected function parse($in$from$to$parsingParams false$curBlock=''&$pointer null)
  1060.     {
  1061.         if ($to === null{
  1062.             $to strlen($in);
  1063.         }
  1064.         $first $in[$from];
  1065.         $substr substr($in$from$to-$from);
  1066.  
  1067.         if ($this->debugecho '<br />PARSE CALL : PARSING "<b>'.htmlentities(substr($in$from$to-$from)).'</b>" @ '.$from.':'.$to.' in '.$curBlock.' : pointer='.$pointer.'<br/>';
  1068.  
  1069.         if ($first==='$'{
  1070.             // var
  1071.             $out $this->parseVar($in$from$to$parsingParams$curBlock$pointer);
  1072.         elseif ($first==='%' && preg_match('#^%[a-z]#i'$substr)) {
  1073.             // const
  1074.             $out $this->parseConst($in$from$to$parsingParams$curBlock$pointer);
  1075.         elseif ($first==='"' || $first==="'"{
  1076.             // string
  1077.             $out $this->parseString($in$from$to$parsingParams$curBlock$pointer);
  1078.         elseif (preg_match('#^[a-z][a-z0-9_]*('.(is_array($parsingParams)||$curBlock!='root'?'':'\s+[^(]|').'\s*\(|$)#i'$substr)) {
  1079.             // func
  1080.             $out $this->parseFunction($in$from$to$parsingParams$curBlock$pointer);
  1081.         elseif (is_array($parsingParams&& preg_match('#^([a-z0-9_]+\s*=)(?:\s+|[^=]).*#i'$substr$match)) {
  1082.             // named parameter
  1083.             if ($this->debugecho 'NAMED PARAM FOUND<br />';
  1084.             $len strlen($match[1]);
  1085.             while (substr($in$from+$len1)===' '{
  1086.                 $len++;
  1087.             }
  1088.             if ($pointer !== null{
  1089.                 $pointer += $len;
  1090.             }
  1091.  
  1092.             $output array(trim(substr(trim($match[1])0-1))$this->parse($in$from+$len$tofalse'namedparam'$pointer));
  1093.  
  1094.             $parsingParams[$output;
  1095.             return $parsingParams;
  1096.         elseif ($substr!=='' && (is_array($parsingParams|| $curBlock === 'namedparam' || $curBlock === 'condition')) {
  1097.             // unquoted string, bool or number
  1098.             $out $this->parseOthers($in$from$to$parsingParams$curBlock$pointer);
  1099.         else {
  1100.             // parse error
  1101.             throw new Dwoo_Compilation_Exception($this'Parse error in "'.substr($in$from$to-$from).'"');
  1102.         }
  1103.  
  1104.         if (empty($out)) {
  1105.             return '';
  1106.         }
  1107.         if ($curBlock === 'root' && substr($out0strlen(self::PHP_OPEN)) !== self::PHP_OPEN{
  1108.             return self::PHP_OPEN .'echo '.$out.';'self::PHP_CLOSE;
  1109.         else {
  1110.             return $out;
  1111.         }
  1112.     }
  1113.  
  1114.     /**
  1115.      * parses a function call
  1116.      *
  1117.      * @param string $in the string within which we must parse something
  1118.      * @param int $from the starting offset of the parsed area
  1119.      * @param int $to the ending offset of the parsed area
  1120.      * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default
  1121.      * @param string $curBlock the current parser-block being processed
  1122.      * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default
  1123.      * @return string parsed values
  1124.      */
  1125.     protected function parseFunction($in$from$to$parsingParams false$curBlock=''&$pointer null)
  1126.     {
  1127.         $cmdstr substr($in$from$to-$from);
  1128.  
  1129.         if ($this->debugecho 'FUNC FOUND<br />';
  1130.  
  1131.         $paramsep '';
  1132.  
  1133.         if (is_array($parsingParams|| $curBlock != 'root'{
  1134.             $paramspos strpos($cmdstr'(');
  1135.             $paramsep ')';
  1136.         elseif(preg_match_all('#[a-z0-9_]+(\s*\(|\s+[^(])#'$cmdstr$matchPREG_OFFSET_CAPTURE)) {
  1137.             $paramspos $match[1][0][1];
  1138.             $paramsep substr($match[1][0][0]-1=== '(' ')':'';
  1139.             if($paramsep === ')'{
  1140.                 $paramspos += strlen($match[1][0][0]1;
  1141.                 if(substr($cmdstr02=== 'if' || substr($cmdstr06=== 'elseif'{
  1142.                     $paramsep '';
  1143.                     if(strlen($match[1][0][0]1{
  1144.                         $paramspos--;
  1145.                     }
  1146.                 }
  1147.             }
  1148.         else {
  1149.             $paramspos false;
  1150.         }
  1151.  
  1152.         $state 0;
  1153.  
  1154.         if ($paramspos === false{
  1155.             if (strpos($cmdstr' ')) {
  1156.                 $func substr($cmdstr0strpos($cmdstr' '));
  1157.             else {
  1158.                 $func $cmdstr;
  1159.             }
  1160.             $params array();
  1161.  
  1162.             if ($curBlock !== 'root'{
  1163.                 return $this->parseOthers($in$from$to$parsingParams$curBlock$pointer);
  1164.             }
  1165.         else {
  1166.             $func rtrim(substr($cmdstr0$paramspos));
  1167.             $whitespace strlen(substr($cmdstrstrlen($func)$paramspos-strlen($func)));
  1168.             $paramstr substr($cmdstr$paramspos+1);
  1169.             if (substr($paramstr-11=== $paramsep{
  1170.                 $paramstr substr($paramstr0-1);
  1171.             }
  1172.  
  1173.             if (strlen($paramstr)===0{
  1174.                 $params array();
  1175.                 $paramstr '';
  1176.             else {
  1177.                 $ptr 0;
  1178.                 $params array();
  1179.                 if ($func === 'empty'{
  1180.                     $params $this->parseVar($paramstr$ptrstrlen($paramstr)$params'root'$ptr);
  1181.                 else {
  1182.                     while ($ptr strlen($paramstr)) {
  1183.                         while (true{
  1184.                             if ($ptr >= strlen($paramstr)) {
  1185.                                 break 2;
  1186.                             }
  1187.  
  1188.                             if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr=== ')'{
  1189.                                 if ($this->debugecho 'PARAM PARSING ENDED, ")" FOUND, POINTER AT '.$ptr.'<br/>';
  1190.                                 break 2;
  1191.                             }
  1192.  
  1193.                             if ($paramstr[$ptr=== ' ' || $paramstr[$ptr=== ',' || $paramstr[$ptr=== "\r" || $paramstr[$ptr=== "\n" || $paramstr[$ptr=== "\t"{
  1194.                                 $ptr++;
  1195.                             else {
  1196.                                 break;
  1197.                             }
  1198.                         }
  1199.  
  1200.                         if ($this->debugecho 'FUNC START PARAM PARSING WITH POINTER AT '.$ptr.'<br/>';
  1201.  
  1202.                         if ($func === 'if' || $func === 'elseif' || $func === 'tif'{
  1203.                             $params $this->parse($paramstr$ptrstrlen($paramstr)$params'condition'$ptr);
  1204.                         else {
  1205.                             $params $this->parse($paramstr$ptrstrlen($paramstr)$params'function'$ptr);
  1206.                         }
  1207.  
  1208.                         if ($this->debugecho 'PARAM PARSED, POINTER AT '.$ptr.' ('.substr($paramstr$ptr-13).')<br/>';
  1209.                     }
  1210.                 }
  1211.                 $paramstr substr($paramstr0$ptr);
  1212.                 $state 0;
  1213.                 foreach ($params as $k=>$p{
  1214.                     if (is_array($p&& is_array($p[1])) {
  1215.                         $state |= 2;
  1216.                     else {
  1217.                         if (($state 2&& preg_match('#^(["\'])(.+?)\1$#'$p[0]$m)) {
  1218.                             $params[$karray($m[2]array('true''true'));
  1219.                         else {
  1220.                             if ($state 2{
  1221.                                 throw new Dwoo_Compilation_Exception($this'You can not use an unnamed parameter after a named one');
  1222.                             }
  1223.                             $state |= 1;
  1224.                         }
  1225.                     }
  1226.                 }
  1227.             }
  1228.         }
  1229.  
  1230.         if ($pointer !== null{
  1231.             $pointer += (isset($paramstrstrlen($paramstr0(')' === $paramsep 0strlen($func(isset($whitespace$whitespace 0);
  1232.             if ($this->debugecho 'FUNC ADDS '.((isset($paramstrstrlen($paramstr0(')' === $paramsep 0strlen($func)).' TO POINTER<br/>';
  1233.         }
  1234.  
  1235.         if ($curBlock === 'method' || $func === 'do'{
  1236.             $pluginType Dwoo::NATIVE_PLUGIN;
  1237.         else {
  1238.             $pluginType $this->getPluginType($func);
  1239.         }
  1240.  
  1241.         // blocks
  1242.         if ($pluginType Dwoo::BLOCK_PLUGIN{
  1243.             if ($curBlock !== 'root' || is_array($parsingParams)) {
  1244.                 throw new Dwoo_Compilation_Exception($this'Block plugins can not be used as other plugin\'s arguments');
  1245.             }
  1246.             if ($pluginType Dwoo::CUSTOM_PLUGIN{
  1247.                 return $this->addCustomBlock($func$params$state);
  1248.             else {
  1249.                 return $this->addBlock($func$params$state);
  1250.             }
  1251.         elseif ($pluginType Dwoo::SMARTY_BLOCK{
  1252.             if ($curBlock !== 'root' || is_array($parsingParams)) {
  1253.                 throw new Dwoo_Compilation_Exception($this'Block plugins can not be used as other plugin\'s arguments');
  1254.             }
  1255.  
  1256.             if ($state 2{
  1257.                 array_unshift($paramsarray('__functype'array($pluginType$pluginType)));
  1258.                 array_unshift($paramsarray('__funcname'array($func$func)));
  1259.             else {
  1260.                 array_unshift($paramsarray($pluginType$pluginType));
  1261.                 array_unshift($paramsarray($func$func));
  1262.             }
  1263.  
  1264.             return $this->addBlock('smartyinterface'$params$state);
  1265.         }
  1266.  
  1267.         // funcs
  1268.         if ($pluginType Dwoo::NATIVE_PLUGIN || $pluginType Dwoo::SMARTY_FUNCTION || $pluginType Dwoo::SMARTY_BLOCK{
  1269.             $params $this->mapParams($paramsnull$state);
  1270.         elseif ($pluginType Dwoo::CLASS_PLUGIN{
  1271.             if ($pluginType Dwoo::CUSTOM_PLUGIN{
  1272.                 $params $this->mapParams($paramsarray($this->customPlugins[$func]['class']$this->customPlugins[$func]['function'])$state);
  1273.             else {
  1274.                 $params $this->mapParams($paramsarray('Dwoo_Plugin_'.$func($pluginType Dwoo::COMPILABLE_PLUGIN'compile' 'process')$state);
  1275.             }
  1276.         elseif ($pluginType Dwoo::FUNC_PLUGIN{
  1277.             if ($pluginType Dwoo::CUSTOM_PLUGIN{
  1278.                 $params $this->mapParams($params$this->customPlugins[$func]['callback']$state);
  1279.             else {
  1280.                 $params $this->mapParams($params'Dwoo_Plugin_'.$func.(($pluginType Dwoo::COMPILABLE_PLUGIN'_compile' '')$state);
  1281.             }
  1282.         elseif ($pluginType Dwoo::SMARTY_MODIFIER{
  1283.             $output 'smarty_modifier_'.$func.'('.implode(', '$params).')';
  1284.         }
  1285.  
  1286.         // only keep php-syntax-safe values for non-block plugins
  1287.         foreach ($params as &$p)
  1288.             $p $p[0];
  1289.         if ($pluginType Dwoo::NATIVE_PLUGIN{
  1290.             if ($func === 'do'{
  1291.                 if (isset($params['*'])) {
  1292.                     $output implode(';'$params['*']).';';
  1293.                 else {
  1294.                     $output '';
  1295.                 }
  1296.  
  1297.                 if (is_array($parsingParams|| $curBlock !== 'root'{
  1298.                     throw new Dwoo_Compilation_Exception($this'Do can not be used inside another function or block');
  1299.                 else {
  1300.                     return self::PHP_OPEN.$output.self::PHP_CLOSE;
  1301.                 }
  1302.             else {
  1303.                 if (isset($params['*'])) {
  1304.                     $output $func.'('.implode(', '$params['*']).')';
  1305.                 else {
  1306.                     $output $func.'()';
  1307.                 }
  1308.             }
  1309.         elseif ($pluginType Dwoo::FUNC_PLUGIN{
  1310.             if ($pluginType Dwoo::COMPILABLE_PLUGIN{
  1311.                 $funcCompiler 'Dwoo_Plugin_'.$func.'_compile';
  1312.                 array_unshift($params$this);
  1313.                 $output call_user_func_array($funcCompiler$params);
  1314.             else {
  1315.                 array_unshift($params'$this');
  1316.                 $params $this->implode_r($params);
  1317.  
  1318.                 if ($pluginType Dwoo::CUSTOM_PLUGIN{
  1319.                     $callback $this->customPlugins[$func]['callback'];
  1320.                     $output 'call_user_func(\''.$callback.'\', '.$params.')';
  1321.                 else {
  1322.                     $output 'Dwoo_Plugin_'.$func.'('.$params.')';
  1323.                 }
  1324.             }
  1325.         elseif ($pluginType Dwoo::CLASS_PLUGIN{
  1326.             if ($pluginType Dwoo::COMPILABLE_PLUGIN{
  1327.                 $funcCompiler array('Dwoo_Plugin_'.$func'compile');
  1328.                 array_unshift($params$this);
  1329.                 $output call_user_func_array($funcCompiler$params);
  1330.             else {
  1331.                 $params $this->implode_r($params);
  1332.                 if ($pluginType Dwoo::CUSTOM_PLUGIN{
  1333.                     $callback $this->customPlugins[$func]['callback'];
  1334.                     if (!is_array($callback)) {
  1335.                         if (($ref new ReflectionMethod($callback'process')) && $ref->isStatic()) {
  1336.                             $output 'call_user_func(array(\''.$callback.'\', \'process\'), '.$params.')';
  1337.                         else {
  1338.                             $output 'call_user_func(array($this->getObjectPlugin(\''.$callback.'\'), \'process\'), '.$params.')';
  1339.                         }
  1340.                     elseif (is_object($callback[0])) {
  1341.                         $output 'call_user_func(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), '.$params.')';
  1342.                     elseif (($ref new ReflectionMethod($callback[0]$callback[1])) && $ref->isStatic()) {
  1343.                         $output 'call_user_func(array(\''.$callback[0].'\', \''.$callback[1].'\'), '.$params.')';
  1344.                     else {
  1345.                         $output 'call_user_func(array($this->getObjectPlugin(\''.$callback[0].'\'), \''.$callback[1].'\'), '.$params.')';
  1346.                     }
  1347.                 else {
  1348.                     $output '$this->classCall(\''.$func.'\', array('.$params.'))';
  1349.                 }
  1350.             }
  1351.         elseif ($pluginType Dwoo::SMARTY_FUNCTION{
  1352.             $params $this->implode_r($params['*']true);
  1353.  
  1354.             if ($pluginType Dwoo::CUSTOM_PLUGIN{
  1355.                 $callback $this->customPlugins[$func]['callback'];
  1356.                 if (is_array($callback)) {
  1357.                     if (is_object($callback[0])) {
  1358.                         $output 'call_user_func_array(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array(array('.$params.'), $this))';
  1359.                     else {
  1360.                         $output 'call_user_func_array(array(\''.$callback[0].'\', \''.$callback[1].'\'), array(array('.$params.'), $this))';
  1361.                     }
  1362.                 else {
  1363.                     $output $callback.'(array('.$params.'), $this)';
  1364.                 }
  1365.             else {
  1366.                 $output 'smarty_function_'.$func.'(array('.$params.'), $this)';
  1367.             }
  1368.         }
  1369.  
  1370.         if (is_array($parsingParams)) {
  1371.             $parsingParams[array($output$output);
  1372.             return $parsingParams;
  1373.         elseif ($curBlock === 'namedparam'{
  1374.             return array($output$output);
  1375.         else {
  1376.             return $output;
  1377.         }
  1378.     }
  1379.  
  1380.     /**
  1381.      * parses a string
  1382.      *
  1383.      * @param string $in the string within which we must parse something
  1384.      * @param int $from the starting offset of the parsed area
  1385.      * @param int $to the ending offset of the parsed area
  1386.      * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default
  1387.      * @param string $curBlock the current parser-block being processed
  1388.      * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default
  1389.      * @return string parsed values
  1390.      */
  1391.     protected function parseString($in$from$to$parsingParams false$curBlock=''&$pointer null)
  1392.     {
  1393.         $substr substr($in$from$to-$from);
  1394.         $first $substr[0];
  1395.  
  1396.         if ($this->debugecho 'STRING FOUND (in '.$substr.')<br />';
  1397.         $strend false;
  1398.         $o $from+1;
  1399.         while ($strend === false{
  1400.             $strend strpos($in$first$o);
  1401.             if ($strend === false{
  1402.                 throw new Dwoo_Compilation_Exception($this'Unfinished string, started with '.substr($in$from$to-$from));
  1403.             }
  1404.             if (substr($in$strend-11=== '\\'{
  1405.                 $o $strend+1;
  1406.                 $strend false;
  1407.             }
  1408.         }
  1409.         if ($this->debugecho 'STRING DELIMITED: '.substr($substr0$strend+1-$from).'<br/>';
  1410.  
  1411.         $srcOutput substr($in$from$strend+1-$from);
  1412.  
  1413.         if ($pointer !== null{
  1414.             $pointer += strlen($srcOutput);
  1415.         }
  1416.  
  1417.         $output $this->replaceStringVars($srcOutput$first);
  1418.  
  1419.         // handle modifiers
  1420.         if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i'substr($substr$strend+1-$from)$match)) {
  1421.             $modstr $match[1];
  1422.  
  1423.             if ($curBlock === 'root' && substr($modstr-1=== '}'{
  1424.                 $modstr substr($modstr0-1);
  1425.             }
  1426.             $modstr str_replace('\\'.$first$first$modstr);
  1427.             $ptr 0;
  1428.             $output $this->replaceModifiers(array(nullnull$output$modstr)'string'$ptr);
  1429.  
  1430.             $strend += $ptr;
  1431.             if ($pointer !== null{
  1432.                 $pointer += $ptr;
  1433.             }
  1434.             $srcOutput .= substr($substr$strend+1-$from$ptr);
  1435.         }
  1436.  
  1437.         // TODO obsolete?
  1438.         if ($curBlock !== 'namedparam' && $curBlock !== 'modifier' && $curBlock !== 'function' && $curBlock !== 'condition' && strlen(substr($in0$to)) $strend+1{
  1439.             $output .= $this->parse($in$strend+1$to$parsingParams);
  1440.         }
  1441.  
  1442.         if (is_array($parsingParams)) {
  1443.             $parsingParams[array($outputsubstr($srcOutput1-1));
  1444.             return $parsingParams;
  1445.         elseif ($curBlock === 'namedparam'{
  1446.             return array($outputsubstr($srcOutput1-1));
  1447.         else {
  1448.             return $output;
  1449.         }
  1450.     }
  1451.  
  1452.     /**
  1453.      * parses a constant
  1454.      *
  1455.      * @param string $in the string within which we must parse something
  1456.      * @param int $from the starting offset of the parsed area
  1457.      * @param int $to the ending offset of the parsed area
  1458.      * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default
  1459.      * @param string $curBlock the current parser-block being processed
  1460.      * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default
  1461.      * @return string parsed values
  1462.      */
  1463.     protected function parseConst($in$from$to$parsingParams false$curBlock=''&$pointer null)
  1464.     {
  1465.         $substr substr($in$from$to-$from);
  1466.  
  1467.         if ($this->debug{
  1468.             echo 'CONST FOUND : '.$substr.'<br />';
  1469.         }
  1470.  
  1471.         if (!preg_match('#^%([a-z0-9_:]+)#i'$substr$m)) {
  1472.             throw new Dwoo_Compilation_Exception($this'Invalid constant');
  1473.         }
  1474.  
  1475.         if ($pointer !== null{
  1476.             $pointer += strlen($m[0]);
  1477.         }
  1478.  
  1479.         $output $this->parseConstKey($m[1]$curBlock);
  1480.  
  1481.         if (is_array($parsingParams)) {
  1482.             $parsingParams[array($output$m[1]);
  1483.             return $parsingParams;
  1484.         elseif ($curBlock === 'namedparam'{
  1485.             return array($output$m[1]);
  1486.         else {
  1487.             return $output;
  1488.         }
  1489.     }
  1490.  
  1491.     /**
  1492.      * parses a constant
  1493.      *
  1494.      * @param string $key the constant to parse
  1495.      * @param string $curBlock the current parser-block being processed
  1496.      * @return string parsed constant
  1497.      */
  1498.     protected function parseConstKey($key$curBlock)
  1499.     {
  1500.         if ($this->securityPolicy !== null && $this->securityPolicy->getConstantHandling(=== Dwoo_Security_Policy::CONST_DISALLOW{
  1501.             return 'null';
  1502.         }
  1503.  
  1504.         if ($curBlock !== 'root'{
  1505.             $output '(defined("'.$key.'") ? '.$key.' : null)';
  1506.         else {
  1507.             $output $key;
  1508.         }
  1509.  
  1510.         return $output;
  1511.     }
  1512.  
  1513.     /**
  1514.      * parses a variable
  1515.      *
  1516.      * @param string $in the string within which we must parse something
  1517.      * @param int $from the starting offset of the parsed area
  1518.      * @param int $to the ending offset of the parsed area
  1519.      * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default
  1520.      * @param string $curBlock the current parser-block being processed
  1521.      * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default
  1522.      * @return string parsed values
  1523.      */
  1524.     protected function parseVar($in$from$to$parsingParams false$curBlock=''&$pointer null)
  1525.     {
  1526.         $substr substr($in$from$to-$from);
  1527.  
  1528.         if (preg_match('#(\$?\.?[a-z0-9_:]*(?:(?:(?:\.|->)(?:[a-z0-9_:]+|(?R))|\[(?:[a-z0-9_:]+|(?R))\]))*)' // var key
  1529.             ($curBlock==='root' || $curBlock==='function' || $curBlock==='namedparam' || $curBlock==='condition' || $curBlock==='variable' || $curBlock==='expression' '(\([^)]*?\)(?:->[a-z0-9_]+(?:\([^)]*?\))?)*)?' '()'// method call
  1530.             ($curBlock==='root' || $curBlock==='function' || $curBlock==='namedparam' || $curBlock==='condition' || $curBlock==='variable' || $curBlock==='string' '((?:(?:[+/*%=-])(?:(?<!=)=?-?[$%][a-z0-9.[\]>_:-]+(?:\([^)]*\))?|(?<!=)=?-?[0-9.,]*|[+-]))*)':'()'// simple math expressions
  1531.             ($curBlock!=='modifier' '((?:\|(?:@?[a-z0-9_]+(?:(?::("|\').*?\5|:[^`]*))*))+)?':'(())'// modifiers
  1532.             '#i'$substr$match)) {
  1533.             $key substr($match[1]1);
  1534.  
  1535.             $matchedLength strlen($match[0]);
  1536.             $hasModifiers = isset($match[4]&& !empty($match[4]);
  1537.             $hasExpression = isset($match[3]&& !empty($match[3]);
  1538.             $hasMethodCall = isset($match[2]&& !empty($match[2]);
  1539.  
  1540.             if ($hasMethodCall{
  1541.                 $key substr($match[1]1strrpos($match[1]'->')-1);
  1542.                 $methodCall substr($match[1]strrpos($match[1]'->')) $match[2];
  1543.             }
  1544.  
  1545.             if ($hasModifiers{
  1546.                 $matchedLength -= strlen($match[4]);
  1547.             }
  1548.  
  1549.             if ($pointer !== null{
  1550.                 $pointer += $matchedLength;
  1551.             }
  1552.  
  1553.             // replace useless brackets by dot accessed vars
  1554.             $key preg_replace('#\[([^$%\[.>-]+)\]#''.$1'$key);
  1555.  
  1556.             // prevent $foo->$bar calls because it doesn't seem worth the trouble
  1557.             if (strpos($key'->$'!== false{
  1558.                 throw new Dwoo_Compilation_Exception($this'You can not access an object\'s property using a variable name.');
  1559.             }
  1560.  
  1561.             if ($this->debug{
  1562.                 if ($hasMethodCall{
  1563.                     echo 'METHOD CALL FOUND : $'.$key.$methodCall.'<br />';
  1564.                 else {
  1565.                     echo 'VAR FOUND : $'.$key.'<br />';
  1566.                 }
  1567.             }
  1568.  
  1569.             $key str_replace('"''\\"'$key);
  1570.  
  1571.             $cnt=substr_count($key'$');
  1572.             if ($cnt 0{
  1573.                 $uid 0;
  1574.                 $parsed array($uid => '');
  1575.                 $current =$parsed;
  1576.                 $curTxt =$parsed[$uid++];
  1577.                 $tree array();
  1578.                 $chars str_split($key1);
  1579.                 $inSplittedVar false;
  1580.                 $bracketCount 0;
  1581.  
  1582.                 while (($char array_shift($chars)) !== null{
  1583.                     if ($char === '['{
  1584.                         if (count($tree0{
  1585.                             $bracketCount++;
  1586.                         else {
  1587.                             $tree[=$current;
  1588.                             $current[$uidarray($uid+=> '');
  1589.                             $current =$current[$uid++];
  1590.                             $curTxt =$current[$uid++];
  1591.                             continue;
  1592.                         }
  1593.                     elseif ($char === ']'{
  1594.                         if ($bracketCount 0{
  1595.                             $bracketCount--;
  1596.                         else {
  1597.                             $current =$tree[count($tree)-1];
  1598.                             array_pop($tree);
  1599.                             if (current($chars!== '[' && current($chars!== false && current($chars!== ']'{
  1600.                                 $current[$uid'';
  1601.                                 $curTxt =$current[$uid++];
  1602.                             }
  1603.                             continue;
  1604.                         }
  1605.                     elseif ($char === '$'{
  1606.                         if (count($tree== 0{
  1607.                             $curTxt =$current[$uid++];
  1608.                             $inSplittedVar true;
  1609.                         }
  1610.                     elseif (($char === '.' || $char === '-'&& count($tree== && $inSplittedVar{
  1611.                         $curTxt =$current[$uid++];
  1612.                         $inSplittedVar false;
  1613.                     }
  1614.  
  1615.                     $curTxt .= $char;
  1616.                 }
  1617.                 unset($uid$current$curTxt$tree$chars);
  1618.  
  1619.                 if ($this->debugecho 'RECURSIVE VAR REPLACEMENT : '.$key.'<br>';
  1620.  
  1621.                 $key $this->flattenVarTree($parsed);
  1622.  
  1623.                 if ($this->debugecho 'RECURSIVE VAR REPLACEMENT DONE : '.$key.'<br>';
  1624.  
  1625.                 $output preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#''$2$3''$this->readVar("'.$key.'")');
  1626.             else {
  1627.                 $output $this->parseVarKey($key$hasModifiers 'modifier' $curBlock);
  1628.             }
  1629.  
  1630.             // methods
  1631.             if ($hasMethodCall{
  1632.                 preg_match_all('{->([a-z0-9_]+)(\([^)]*\))?}i'$methodCall$calls);
  1633.                 foreach ($calls[1as $i=>$method{
  1634.                     $args $calls[2][$i];
  1635.                     if ($args === ''{
  1636.                         // property
  1637.                         $output '('.$output.'->'.$method.' : null)';
  1638.                     else {
  1639.                         // method
  1640.                         if ($args === '()'{
  1641.                             $parsedCall '->'.$method.$args;
  1642.                         else {
  1643.                             $parsedCall '->'.$this->parseFunction($method.$args0strlen($method.$args)false'method');
  1644.                         }
  1645.                         $output '(is_object($tmp = '.$output.') ? $tmp'.$parsedCall.' : $this->triggerError(\'Method <em>'.$method.'()</em> was called on a non-object ($'.$key.': \'.var_export($tmp, true).\')\'))';
  1646.                     }
  1647.                 }
  1648.             }
  1649.  
  1650.             if ($hasExpression{
  1651.                 // expressions
  1652.                 preg_match_all('#(?:([+/*%=-])(=?-?[%$][a-z0-9.[\]>_:-]+(?:\([^)]*\))?|=?-?[0-9.,]+|\1))#i'$match[3]$expMatch);
  1653.  
  1654.                 foreach ($expMatch[1as $k=>$operator{
  1655.                     if (substr($expMatch[2][$k]01)==='='{
  1656.                         $assign true;
  1657.                         if ($operator === '='{
  1658.                             throw new Dwoo_Compilation_Exception($this'Invalid expression <em>'.$substr.'</em>, can not use "==" in expressions');
  1659.                         }
  1660.                         if ($curBlock !== 'root'{
  1661.                             throw new Dwoo_Compilation_Exception($this'Invalid expression <em>'.$substr.'</em>, "=" can only be used in pure expressions like {$foo+=3}, {$foo="bar"}');
  1662.                         }
  1663.                         $operator .= '=';
  1664.                         $expMatch[2][$ksubstr($expMatch[2][$k]1);
  1665.                     }
  1666.  
  1667.                     if (substr($expMatch[2][$k]01)==='-' && strlen($expMatch[2][$k]1{
  1668.                         $operator .= '-';
  1669.                         $expMatch[2][$ksubstr($expMatch[2][$k]1);
  1670.                     }
  1671.                     if (($operator==='+'||$operator==='-'&& $expMatch[2][$k]===$operator{
  1672.                         $output '('.$output.$operator.$operator.')';
  1673.                         break;
  1674.                     elseif (substr($expMatch[2][$k]01=== '$'{
  1675.                         $output '('.$output.' '.$operator.' '.$this->parseVar($expMatch[2][$k]0strlen($expMatch[2][$k])false'expression').')';
  1676.                     elseif (substr($expMatch[2][$k]01=== '%'{
  1677.                         $output '('.$output.' '.$operator.' '.$this->parseConst($expMatch[2][$k]0strlen($expMatch[2][$k])false'expression').')';
  1678.                     elseif (!empty($expMatch[2][$k])) {
  1679.                         $output '('.$output.' '.$operator.' '.str_replace(',''.'$expMatch[2][$k]).')';
  1680.                     else {
  1681.                         throw new Dwoo_Compilation_Exception($this'Unfinished expression <em>'.$substr.'</em>, missing var or number after math operator');
  1682.                     }
  1683.                 }
  1684.             elseif ($curBlock === 'root' && substr(trim(substr($substr$matchedLength))01=== '='{
  1685.                 // var assignment
  1686.                 $value trim(substr(trim(substr($substr$matchedLength))1));
  1687.  
  1688.                 $parts array();
  1689.                 $parts $this->parse($value0strlen($value)$parts'condition');
  1690.  
  1691.                 // load if plugin
  1692.                 try {
  1693.                     $this->getPluginType('if');
  1694.                 catch (Dwoo_Exception $e{
  1695.                     throw new Dwoo_Compilation_Exception($this'Assignments require the "if" plugin to be accessible');
  1696.                 }
  1697.  
  1698.                 $parts $this->mapParams($partsarray('Dwoo_Plugin_if''init')1);
  1699.                 $parts $this->getCompiledParams($parts);
  1700.  
  1701.                 $value Dwoo_Plugin_if::replaceKeywords($parts['*']$this);
  1702.  
  1703.                 $output .= '='.implode(' '$value);
  1704.                 $assign true;
  1705.             }
  1706.  
  1707.             if ($this->autoEscape === true{
  1708.                 $output '(is_string($tmp='.$output.') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
  1709.             }
  1710.  
  1711.             // handle modifiers
  1712.             if ($curBlock !== 'modifier' && $hasModifiers{
  1713.                 $ptr 0;
  1714.                 $output $this->replaceModifiers(array(nullnull$output$match[4])'var'$ptr);
  1715.                 if ($pointer !== null{
  1716.                     $pointer += $ptr;
  1717.                 }
  1718.                 $matchedLength += $ptr;
  1719.             }
  1720.  
  1721.             if (is_array($parsingParams)) {
  1722.                 $parsingParams[array($output$key);
  1723.                 return $parsingParams;
  1724.             elseif ($curBlock === 'namedparam'{
  1725.                 return array($output$key);
  1726.             elseif ($curBlock === 'string'{
  1727.                 return array($matchedLength$output);
  1728.             elseif ($curBlock === 'expression' || $curBlock === 'variable'{
  1729.                 return $output;
  1730.             elseif (isset($assign)) {
  1731.                 return self::PHP_OPEN.$output.';'.self::PHP_CLOSE;
  1732.             else {
  1733.                 return $output;
  1734.             }
  1735.         else {
  1736.             if ($curBlock === 'string'{
  1737.                 return array(0'');
  1738.             else {
  1739.                 throw new Dwoo_Compilation_Exception($this'Invalid variable name <em>'.$substr.'</em>');
  1740.             }
  1741.         }
  1742.     }
  1743.  
  1744.     /**
  1745.      * parses a constant variable (a variable that doesn't contain another variable) and preprocesses it to save runtime processing time
  1746.      *
  1747.      * @param string $key the variable to parse
  1748.      * @param string $curBlock the current parser-block being processed
  1749.      * @return string parsed variable
  1750.      */
  1751.     protected function parseVarKey($key$curBlock)
  1752.     {
  1753.         if ($key === ''{
  1754.             return '$this->scope';
  1755.         }
  1756.         if (substr($key01=== '.'{
  1757.             $key 'dwoo'.$key;
  1758.         }
  1759.         if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i'$key$m)) {
  1760.             $global strtoupper($m[1]);
  1761.             if ($global === 'COOKIES'{
  1762.                 $global 'COOKIE';
  1763.             }
  1764.             $key '$_'.$global;
  1765.             foreach (explode('.'ltrim($m[2]'.')) as $part)
  1766.                 $key .= '['.var_export($parttrue).']';
  1767.             if ($curBlock === 'root'{
  1768.                 $output $key;
  1769.             else {
  1770.                 $output '(isset('.$key.')?'.$key.':null)';
  1771.             }
  1772.         elseif (preg_match('#dwoo\.const\.([a-z0-9_:]+)#i'$key$m)) {
  1773.             return $this->parseConstKey($m[1]$curBlock);
  1774.         elseif ($this->scope !== null{
  1775.             if (strstr($key'.'=== false && strstr($key'['=== false && strstr($key'->'=== false{
  1776.                 if ($key === 'dwoo'{
  1777.                     $output '$this->globals';
  1778.                 elseif ($key === '_root' || $key === '__'{
  1779.                     $output '$this->data';
  1780.                 elseif ($key === '_parent' || $key === '_'{
  1781.                     $output '$this->readParentVar(1)';
  1782.                 elseif ($key === '_key'{
  1783.                     $output '$tmp_key';
  1784.                 else {
  1785.                     if ($curBlock === 'root'{
  1786.                         $output '$this->scope["'.$key.'"]';
  1787.                     else {
  1788.                         $output '(isset($this->scope["'.$key.'"]) ? $this->scope["'.$key.'"] : null)';
  1789.                     }
  1790.                 }
  1791.             else {
  1792.                 preg_match_all('#(\[|->|\.)?([a-z0-9_]+)\]?#i'$key$m);
  1793.  
  1794.                 $i $m[2][0];
  1795.                 if ($i === '_parent' || $i === '_'{
  1796.                     $parentCnt 0;
  1797.  
  1798.                     while (true{
  1799.                         $parentCnt++;
  1800.                         array_shift($m[2]);
  1801.                         array_shift($m[1]);
  1802.                         if (current($m[2]=== '_parent'{
  1803.                             continue;
  1804.                         }
  1805.                         break;
  1806.                     }
  1807.  
  1808.                     $output '$this->readParentVar('.$parentCnt.')';
  1809.                 else {
  1810.                     if ($i === 'dwoo'{
  1811.                         $output '$this->globals';
  1812.                         array_shift($m[2]);
  1813.                         array_shift($m[1]);
  1814.                     elseif ($i === '_root' || $i === '__'{
  1815.                         $output '$this->data';
  1816.                         array_shift($m[2]);
  1817.                         array_shift($m[1]);
  1818.                     elseif ($i === '_key'{
  1819.                         $output '$tmp_key';
  1820.                     else {
  1821.                         $output '$this->scope';
  1822.                     }
  1823.  
  1824.                     while (count($m[1]&& $m[1][0!== '->'{
  1825.                         $output .= '["'.$m[2][0].'"]';
  1826.                         array_shift($m[2]);
  1827.                         array_shift($m[1]);
  1828.                     }
  1829.  
  1830.                     if ($curBlock !== 'root'{
  1831.                         $output '(isset('.$output.') ? '.$output.':null)';
  1832.                     }
  1833.                 }
  1834.  
  1835.                 if (count($m[2])) {
  1836.                     unset($m[0]);
  1837.                     $output '$this->readVarInto('.str_replace("\n"''var_export($mtrue)).', '.$output.')';
  1838.                 }
  1839.             }
  1840.         else {
  1841.             preg_match_all('#(\[|->|\.)?([a-z0-9_]+)\]?#i'$key$m);
  1842.             unset($m[0]);
  1843.             $output '$this->readVar('.str_replace("\n"''var_export($mtrue)).')';
  1844.         }
  1845.  
  1846.         return $output;
  1847.     }
  1848.  
  1849.     /**
  1850.      * flattens a variable tree, this helps in parsing very complex variables such as $var.foo[$foo.bar->baz].baz,
  1851.      * it computes the contents of the brackets first and works out from there
  1852.      *
  1853.      * @param array $tree the variable tree parsed by he parseVar() method that must be flattened
  1854.      * @param bool $recursed leave that to false by default, it is only for internal use
  1855.      * @return string flattened tree
  1856.      */
  1857.     protected function flattenVarTree(array $tree$recursed=false)
  1858.     {
  1859.         $out $recursed ?  '".$this->readVarInto(' '';
  1860.         foreach ($tree as $bit{
  1861.             if (is_array($bit)) {
  1862.                 $out.='.'.$this->flattenVarTree($bitfalse);
  1863.             else {
  1864.                 $key str_replace('"''\\"'$bit);
  1865.  
  1866.                 if (substr($key01)==='$'{
  1867.                     $out .= '".'.$this->parseVar($key0strlen($key)false'variable').'."';
  1868.                 else {
  1869.                     $cnt substr_count($key'$');
  1870.  
  1871.                     if ($this->debugecho 'PARSING SUBVARS IN : '.$key.'<br>';
  1872.                     if ($cnt 0{
  1873.                         while (--$cnt >= 0{
  1874.                             if (isset($last)) {
  1875.                                 $last strrpos($key'$'(strlen($key$last 1));
  1876.                             else {
  1877.                                 $last strrpos($key'$');
  1878.                             }
  1879.                             preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*'.
  1880.                                       '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i'substr($key$last)$submatch);
  1881.  
  1882.                             $len strlen($submatch[0]);
  1883.                             $key substr_replace(
  1884.                                 $key,
  1885.                                 preg_replace_callback(
  1886.                                     '#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)'.
  1887.                                     '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i',
  1888.                                     array($this'replaceVarKeyHelper')substr($key$last$len)
  1889.                                 ),
  1890.                                 $last,
  1891.                                 $len
  1892.                             );
  1893.                             if ($this->debugecho 'RECURSIVE VAR REPLACEMENT DONE : '.$key.'<br>';
  1894.                         }
  1895.                         unset($last);
  1896.  
  1897.                         $out .= $key;
  1898.                     else {
  1899.                         $out .= $key;
  1900.                     }
  1901.                 }
  1902.             }
  1903.         }
  1904.         $out .= $recursed ')."' '';
  1905.         return $out;
  1906.     }
  1907.  
  1908.     /**
  1909.      * helper function that parses a variable
  1910.      *
  1911.      * @param array $match the matched variable, array(1=>"string match")
  1912.      * @return string parsed variable
  1913.      */
  1914.     protected function replaceVarKeyHelper($match)
  1915.     {
  1916.         return '".'.$this->parseVar($match[0]0strlen($match[0])false'variable').'."';
  1917.     }
  1918.  
  1919.     /**
  1920.      * parses various constants, operators or non-quoted strings
  1921.      *
  1922.      * @param string $in the string within which we must parse something
  1923.      * @param int $from the starting offset of the parsed area
  1924.      * @param int $to the ending offset of the parsed area
  1925.      * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default
  1926.      * @param string $curBlock the current parser-block being processed
  1927.      * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default
  1928.      * @return string parsed values
  1929.      */
  1930.     protected function parseOthers($in$from$to$parsingParams false$curBlock=''&$pointer null)
  1931.     {
  1932.         $first $in[$from];
  1933.         $substr substr($in$from$to-$from);
  1934.  
  1935.         $end strlen($substr);
  1936.  
  1937.         if ($curBlock === 'condition'{
  1938.             $breakChars array('('')'' ''||''&&''|''&''>=''<=''===''==''=''!==''!=''<<''<''>>''>''^''~'',''+''-''*''/''%''!''?'':');
  1939.         elseif ($curBlock === 'modifier'{
  1940.             $breakChars array(' '','')'':''|'"\r""\n""\t");
  1941.         else {
  1942.             $breakChars array(' '','')'"\r""\n""\t");
  1943.         }
  1944.  
  1945.         $breaker false;
  1946.         while (list($k,$chareach($breakChars)) {
  1947.             $test strpos($substr$char);
  1948.             if ($test !== false && $test $end{
  1949.                 $end $test;
  1950.                 $breaker $k;
  1951.             }
  1952.         }
  1953.  
  1954.         if ($curBlock === 'condition'{
  1955.             if ($end === && $breaker !== false{
  1956.                 $end strlen($breakChars[$breaker]);
  1957.             }
  1958.         }
  1959.  
  1960.         if ($end !== false{
  1961.             $substr substr($substr0$end);
  1962.         }
  1963.  
  1964.         if ($pointer !== null{
  1965.             $pointer += strlen($substr);
  1966.         }
  1967.  
  1968.         $src $substr;
  1969.  
  1970.         if (strtolower($substr=== 'false' || strtolower($substr=== 'no' || strtolower($substr=== 'off'{
  1971.             if ($this->debugecho 'BOOLEAN(FALSE) PARSED<br />';
  1972.             $substr 'false';
  1973.         elseif (strtolower($substr=== 'true' || strtolower($substr=== 'yes' || strtolower($substr=== 'on'{
  1974.             if ($this->debugecho 'BOOLEAN(TRUE) PARSED<br />';
  1975.             $substr 'true';
  1976.         elseif ($substr === 'null' || $substr === 'NULL'{
  1977.             if ($this->debugecho 'NULL PARSED<br />';
  1978.             $substr 'null';
  1979.         elseif (is_numeric($substr)) {
  1980.             if ($this->debugecho 'NUMBER PARSED<br />';
  1981.             $substr = (float) $substr;
  1982.             if ((int) $substr == $substr{
  1983.                 $substr = (int) $substr;
  1984.             }
  1985.         elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}'$substr)) {
  1986.             if ($this->debugecho 'SIMPLE MATH PARSED<br />';
  1987.             $substr '('.$substr.')';
  1988.         elseif ($curBlock === 'condition' && array_search($substr$breakCharstrue!== false{
  1989.             if ($this->debugecho 'BREAKCHAR PARSED<br />';
  1990.             //$substr = '"'.$substr.'"';
  1991.         else {
  1992.             if ($this->debugecho 'BLABBER CASTED AS STRING<br />';
  1993.  
  1994.             $substr $this->replaceStringVars('"'.str_replace('"''\\"'$substr).'"''"'$curBlock);
  1995.         }
  1996.  
  1997.         if (is_array($parsingParams)) {
  1998.             $parsingParams[array($substr$src);
  1999.             return $parsingParams;
  2000.         elseif ($curBlock === 'namedparam'{
  2001.             return array($substr$src);
  2002.         else {
  2003.             throw new Exception('Something went wrong');
  2004.         }
  2005.     }
  2006.  
  2007.     /**
  2008.      * replaces variables within a parsed string
  2009.      *
  2010.      * @param string $string the parsed string
  2011.      * @param string $first the first character parsed in the string, which is the string delimiter (' or ")
  2012.      * @param string $curBlock the current parser-block being processed
  2013.      * @return string the original string with variables replaced
  2014.      */
  2015.     protected function replaceStringVars($string$first$curBlock='')
  2016.     {
  2017.         // replace vars
  2018.         $cnt=substr_count($string'$');
  2019.         if ($this->debugecho 'STRING VAR REPLACEMENT : '.$string.'<br>';
  2020.         while (--$cnt >= 0{
  2021.             if (isset($last)) {
  2022.                 $last strrpos($string'$'(strlen($string$last 1));
  2023.             else {
  2024.                 $last strrpos($string'$');
  2025.             }
  2026.  
  2027.             if (array_search($string[$last-1]array('\\''/''*''+''-''%')) !== false{
  2028.                 continue;
  2029.             }
  2030.  
  2031.             // get var length first
  2032.             $var $this->parse($string$lastnullfalse$curBlock === 'modifier' 'modifier' 'string');
  2033.             $len $var[0];
  2034.             // reparse after removing every \" in the parsed string
  2035.             $var $this->parse(str_replace('\\'.$first$first$string)$lastnullfalse$curBlock === 'modifier' 'modifier' 'string');
  2036.  
  2037.             $string substr_replace($string$first.'.'.$var[1].'.'.$first$last$len);
  2038.             if ($this->debugecho 'STRING VAR REPLACEMENT DONE : '.$string.'<br>';
  2039.         }
  2040.  
  2041.         // handle modifiers
  2042.         // TODO Obsolete?
  2043.         $string preg_replace_callback('#("|\')\.(.+?)\.\1((?:\|(?:@?[a-z0-9_]+(?:(?::("|\').+?\4|:[^`]*))*))+)#i'array($this'replaceModifiers')$string);
  2044.  
  2045.         // replace escaped dollar operators by unescaped ones if required
  2046.         if ($first==="'"{
  2047.             $string str_replace('\\$''$'$string);
  2048.         }
  2049.  
  2050.         // remove backticks around strings if needed
  2051.         $string preg_replace('#`(("|\').+?\2)`#''$1'$string);
  2052.  
  2053.         return $string;
  2054.     }
  2055.  
  2056.     /**
  2057.      * replaces the modifiers applied to a string or a variable
  2058.      *
  2059.      * @param array $m the regex matches that must be array(1=>"double or single quotes enclosing a string, when applicable", 2=>"the string or var", 3=>"the modifiers matched")
  2060.      * @param string $curBlock the current parser-block being processed
  2061.      * @return string the input enclosed with various function calls according to the modifiers found
  2062.      */
  2063.     protected function replaceModifiers(array $m$curBlock null&$pointer null)
  2064.     {
  2065.         if ($this->debugecho 'PARSING MODIFIERS : '.$m[3].'<br />';
  2066.  
  2067.         if ($pointer !== null{
  2068.             $pointer += strlen($m[3]);
  2069.         }
  2070.         // remove first pipe
  2071.         $cmdstrsrc substr($m[3]1);
  2072.         // remove last quote if present
  2073.         if (substr($cmdstrsrc-11=== $m[1]{
  2074.             $cmdstrsrc substr($cmdstrsrc0-1);
  2075.             $add $m[1];
  2076.         }
  2077.  
  2078.         $output $m[2];
  2079.  
  2080.         $continue true;
  2081.         while (strlen($cmdstrsrc&& $continue{
  2082.             $cmdstr $cmdstrsrc;
  2083.             $paramsep ':';
  2084.             $paramspos strpos($cmdstr$paramsep);
  2085.             $funcsep strpos($cmdstr'|');
  2086.             if ($funcsep !== false && ($paramspos === false || $paramspos $funcsep)) {
  2087.                 $paramspos false;
  2088.                 $cmdstr substr($cmdstr0$funcsep);
  2089.             }
  2090.  
  2091.             $state 0;
  2092.             if ($paramspos === false{
  2093.                 $func $cmdstr;
  2094.                 $cmdstrsrc substr($cmdstrsrcstrlen($func)+1);
  2095.                 $params array();
  2096.             else {
  2097.                 $func substr($cmdstr0$paramspos);
  2098.                 $paramstr substr($cmdstr$paramspos+1);
  2099.                 if (substr($paramstr-11=== $paramsep{
  2100.                     $paramstr substr($paramstr0-1);
  2101.                 }
  2102.  
  2103.                 $ptr 0;
  2104.                 $params array();
  2105.                 while ($ptr strlen($paramstr)) {
  2106.                     if ($this->debugecho 'MODIFIER START PARAM PARSING WITH POINTER AT '.$ptr.'<br/>';
  2107.                     if ($this->debugecho $paramstr.'--'.$ptr.'--'.strlen($paramstr).'--modifier<br/>';
  2108.                     $params $this->parse($paramstr$ptrstrlen($paramstr)$params'modifier'$ptr);
  2109.                     if ($this->debugecho 'PARAM PARSED, POINTER AT '.$ptr.'<br/>';
  2110.  
  2111.                     if ($ptr >= strlen($paramstr)) {
  2112.                         if ($this->debugecho 'PARAM PARSING ENDED, PARAM STRING CONSUMED<br/>';
  2113.                         break;
  2114.                     }
  2115.  
  2116.                     if ($paramstr[$ptr=== ' ' || $paramstr[$ptr=== '|'{
  2117.                         if ($this->debugecho 'PARAM PARSING ENDED, " " or "|" FOUND, POINTER AT '.$ptr.'<br/>';
  2118.                         if ($paramstr[$ptr=== ' '{
  2119.                             $continue false;
  2120.                             if ($pointer !== null{
  2121.                                 $pointer -= strlen($paramstr$ptr;
  2122.                             }
  2123.                         }
  2124.                         $ptr++;
  2125.                         break;
  2126.                     }
  2127.                     if ($ptr strlen($paramstr&& $paramstr[$ptr=== ':'{
  2128.                         $ptr++;
  2129.                     }
  2130.                 }
  2131.                 $cmdstrsrc substr($cmdstrsrcstrlen($func)+1+$ptr);
  2132.                 $paramstr substr($paramstr0$ptr);
  2133.                 foreach ($params as $k=>$p{
  2134.                     if (is_array($p&& is_array($p[1])) {
  2135.                         $state |= 2;
  2136.                     else {
  2137.                         if (($state 2&& preg_match('#^(["\'])(.+?)\1$#'$p[0]$m)) {
  2138.                             $params[$karray($m[2]array('true''true'));
  2139.                         else {
  2140.                             if ($state 2{
  2141.                                 throw new Dwoo_Compilation_Exception($this'You can not use an unnamed parameter after a named one');
  2142.                             }
  2143.                             $state |= 1;
  2144.                         }
  2145.                     }
  2146.                 }
  2147.             }
  2148.  
  2149.             // check if we must use array_map with this plugin or not
  2150.             $mapped false;
  2151.             if (substr($func01=== '@'{
  2152.                 $func substr($func1);
  2153.                 $mapped true;
  2154.             }
  2155.  
  2156.             $pluginType $this->getPluginType($func);
  2157.  
  2158.             if ($state 2{
  2159.                 array_unshift($paramsarray('value'array($output$output)));
  2160.             else {
  2161.                 array_unshift($paramsarray($output$output));
  2162.             }
  2163.  
  2164.             if ($pluginType Dwoo::NATIVE_PLUGIN{
  2165.                 $params $this->mapParams($paramsnull$state);
  2166.  
  2167.                 $params $params['*'][0];
  2168.  
  2169.                 $params $this->implode_r($params);
  2170.  
  2171.                 if ($mapped{
  2172.                     $output '$this->arrayMap(\''.$func.'\', array('.$params.'))';
  2173.                 else {
  2174.                     $output $func.'('.$params.')';
  2175.                 }
  2176.             elseif ($pluginType Dwoo::SMARTY_MODIFIER{
  2177.                 $params $this->mapParams($paramsnull$state);
  2178.                 $params $params['*'][0];
  2179.  
  2180.                 $params $this->implode_r($params);
  2181.  
  2182.                 if ($pluginType Dwoo::CUSTOM_PLUGIN{
  2183.                     $callback $this->customPlugins[$func]['callback'];
  2184.                     if (is_array($callback)) {
  2185.                         if (is_object($callback[0])) {
  2186.                             $output ($mapped '$this->arrayMap' 'call_user_func_array').'(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array('.$params.'))';
  2187.                         else {
  2188.                             $output ($mapped '$this->arrayMap' 'call_user_func_array').'(array(\''.$callback[0].'\', \''.$callback[1].'\'), array('.$params.'))';
  2189.                         }
  2190.                     elseif ($mapped{
  2191.                         $output '$this->arrayMap(\''.$callback.'\', array('.$params.'))';
  2192.                     else {
  2193.                         $output $callback.'('.$params.')';
  2194.                     }
  2195.                 elseif ($mapped{
  2196.                     $output '$this->arrayMap(\'smarty_modifier_'.$func.'\', array('.$params.'))';
  2197.                 else {
  2198.                     $output 'smarty_modifier_'.$func.'('.$params.')';
  2199.                 }
  2200.             else {
  2201.                 if ($pluginType Dwoo::CUSTOM_PLUGIN{
  2202.                     $callback $this->customPlugins[$func]['callback'];
  2203.                     $pluginName $callback;
  2204.                 else {
  2205.                     $pluginName 'Dwoo_Plugin_'.$func;
  2206.  
  2207.                     if ($pluginType Dwoo::CLASS_PLUGIN{
  2208.                         $callback array($pluginName($pluginType Dwoo::COMPILABLE_PLUGIN'compile' 'process');
  2209.                     else {
  2210.                         $callback $pluginName (($pluginType Dwoo::COMPILABLE_PLUGIN'_compile' '');
  2211.                     }
  2212.                 }
  2213.  
  2214.                 $params $this->mapParams($params$callback$state);
  2215.  
  2216.                 foreach ($params as &$p)
  2217.                     $p $p[0];
  2218.  
  2219.                 if ($pluginType Dwoo::FUNC_PLUGIN{
  2220.                     if ($pluginType Dwoo::COMPILABLE_PLUGIN{
  2221.                         if ($mapped{
  2222.                             throw new Dwoo_Compilation_Exception($this'The @ operator can not be used on compiled plugins.');
  2223.                         }
  2224.                         $funcCompiler 'Dwoo_Plugin_'.$func.'_compile';
  2225.                         array_unshift($params$this);
  2226.                         $output call_user_func_array($funcCompiler$params);
  2227.                     else {
  2228.                         array_unshift($params'$this');
  2229.  
  2230.                         $params $this->implode_r($params);
  2231.                         if ($mapped{
  2232.                             $output '$this->arrayMap(\''.$pluginName.'\', array('.$params.'))';
  2233.                         else {
  2234.                             $output $pluginName.'('.$params.')';
  2235.                         }
  2236.                     }
  2237.                 else {
  2238.                     if ($pluginType Dwoo::COMPILABLE_PLUGIN{
  2239.                         if ($mapped{
  2240.                             throw new Dwoo_Compilation_Exception($this'The @ operator can not be used on compiled plugins.');
  2241.                         }
  2242.                         $funcCompiler array('Dwoo_Plugin_'.$func'compile');
  2243.                         array_unshift($params$this);
  2244.                         $output call_user_func_array($funcCompiler$params);
  2245.                     else {
  2246.                         $params $this->implode_r($params);
  2247.  
  2248.                         if ($pluginType Dwoo::CUSTOM_PLUGIN{
  2249.                             if (is_object($callback[0])) {
  2250.                                 $output ($mapped '$this->arrayMap' 'call_user_func_array').'(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array('.$params.'))';
  2251.                             else {
  2252.                                 $output ($mapped '$this->arrayMap' 'call_user_func_array').'(array(\''.$callback[0].'\', \''.$callback[1].'\'), array('.$params.'))';
  2253.                             }
  2254.                         elseif ($mapped{
  2255.                             $output '$this->arrayMap(array($this->getObjectPlugin(\'Dwoo_Plugin_'.$func.'\'), \'process\'), array('.$params.'))';
  2256.                         else {
  2257.                             $output '$this->classCall(\''.$func.'\', array('.$params.'))';
  2258.                         }
  2259.                     }
  2260.                 }
  2261.             }
  2262.         }
  2263.  
  2264.         if ($curBlock === 'var' || $m[1=== null{
  2265.             return $output;
  2266.         elseif ($curBlock === 'string' || $curBlock === 'root'{
  2267.             return $m[1].'.'.$output.'.'.$m[1].(isset($add)?$add:null);
  2268.         }
  2269.     }
  2270.  
  2271.     /**
  2272.      * recursively implodes an array in a similar manner as var_export() does but with some tweaks
  2273.      * to handle pre-compiled values and the fact that we do not need to enclose everything with
  2274.      * "array" and do not require top-level keys to be displayed
  2275.      *
  2276.      * @param array $params the array to implode
  2277.      * @param bool $recursiveCall if set to true, the function outputs key names for the top level
  2278.      * @return string the imploded array
  2279.      */
  2280.     protected function implode_r(array $params$recursiveCall false)
  2281.     {
  2282.         $out '';
  2283.         foreach ($params as $k=>$p{
  2284.             if (is_array($p)) {
  2285.                 $out2 'array(';
  2286.                 foreach ($p as $k2=>$v)
  2287.                     $out2 .= var_export($k2true).' => '.(is_array($v'array('.$this->implode_r($vtrue).')' $v).', ';
  2288.                 $p rtrim($out2', ').')';
  2289.             }
  2290.             if ($recursiveCall{
  2291.                 $out .= var_export($ktrue).' => '.$p.', ';
  2292.             else {
  2293.                 $out .= $p.', ';
  2294.             }
  2295.         }
  2296.         return rtrim($out', ');
  2297.     }
  2298.  
  2299.     /**
  2300.      * returns the plugin type of a plugin and adds it to the used plugins array if required
  2301.      *
  2302.      * @param string $name plugin name, as found in the template
  2303.      * @return int type as a multi bit flag composed of the Dwoo plugin types constants
  2304.      */
  2305.     protected function getPluginType($name)
  2306.     {
  2307.         $pluginType = -1;
  2308.  
  2309.         if (($this->securityPolicy === null && (function_exists($name|| strtolower($name=== 'isset' || strtolower($name=== 'empty')) ||
  2310.             ($this->securityPolicy !== null && in_array(strtolower($name)$this->securityPolicy->getAllowedPhpFunctions()) !== false)) {
  2311.             $phpFunc true;
  2312.         }
  2313.  
  2314.         while ($pluginType <= 0{
  2315.             if (isset($this->customPlugins[$name])) {
  2316.                 $pluginType $this->customPlugins[$name]['type'Dwoo::CUSTOM_PLUGIN;
  2317.             elseif (class_exists('Dwoo_Plugin_'.$namefalse!== false{
  2318.                 if (is_subclass_of('Dwoo_Plugin_'.$name'Dwoo_Block_Plugin')) {
  2319.                     $pluginType Dwoo::BLOCK_PLUGIN;
  2320.                 else {
  2321.                     $pluginType Dwoo::CLASS_PLUGIN;
  2322.                 }
  2323.                 $interfaces class_implements('Dwoo_Plugin_'.$namefalse);
  2324.                 if (in_array('Dwoo_ICompilable'$interfaces!== false || in_array('Dwoo_ICompilable_Block'$interfaces!== false{
  2325.                     $pluginType |= Dwoo::COMPILABLE_PLUGIN;
  2326.                 }
  2327.             elseif (function_exists('Dwoo_Plugin_'.$name!== false{
  2328.                 $pluginType Dwoo::FUNC_PLUGIN;
  2329.             elseif (function_exists('Dwoo_Plugin_'.$name.'_compile')) {
  2330.                 $pluginType Dwoo::FUNC_PLUGIN Dwoo::COMPILABLE_PLUGIN;
  2331.             elseif (function_exists('smarty_modifier_'.$name!== false{
  2332.                 $pluginType Dwoo::SMARTY_MODIFIER;
  2333.             elseif (function_exists('smarty_function_'.$name!== false{
  2334.                 $pluginType Dwoo::SMARTY_FUNCTION;
  2335.             elseif (function_exists('smarty_block_'.$name!== false{
  2336.                 $pluginType Dwoo::SMARTY_BLOCK;
  2337.             else {
  2338.                 if ($pluginType===-1{
  2339.                     try {
  2340.                         $this->dwoo->getLoader()->loadPlugin($nameisset($phpFunc)===false);
  2341.                     catch (Exception $e{
  2342.                         if (isset($phpFunc)) {
  2343.                             $pluginType Dwoo::NATIVE_PLUGIN;
  2344.                         else {
  2345.                             throw $e;
  2346.                         }
  2347.                     }
  2348.                 else {
  2349.                     throw new Dwoo_Exception('Plugin "'.$name.'" could not be found');
  2350.                 }
  2351.                 $pluginType++;
  2352.             }
  2353.         }
  2354.  
  2355.         if (($pluginType Dwoo::COMPILABLE_PLUGIN=== && ($pluginType Dwoo::NATIVE_PLUGIN=== 0{
  2356.             $this->usedPlugins[$name$pluginType;
  2357.         }
  2358.  
  2359.         return $pluginType;
  2360.     }
  2361.  
  2362.     /**
  2363.      * runs htmlentities over the matched <?php ?> blocks when the security policy enforces that
  2364.      *
  2365.      * @param array $match matched php block
  2366.      * @return string the htmlentities-converted string
  2367.      */
  2368.     protected function phpTagEncodingHelper($match)
  2369.     {
  2370.         return htmlspecialchars($match[0]);
  2371.     }
  2372.  
  2373.     /**
  2374.      * maps the parameters received from the template onto the parameters required by the given callback
  2375.      *
  2376.      * @param array $params the array of parameters
  2377.      * @param callback $callback the function or method to reflect on to find out the required parameters
  2378.      * @param int $callType the type of call in the template, 0 = no params, 1 = php-style call, 2 = named parameters call
  2379.      * @return array parameters sorted in the correct order with missing optional parameters filled
  2380.      */
  2381.     protected function mapParams(array $params$callback$callType=2)
  2382.     {
  2383.         $map $this->getParamMap($callback);
  2384.  
  2385.         $paramlist array();
  2386.  
  2387.         // transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
  2388.         $ps array();
  2389.         foreach ($params as $p{
  2390.             if (is_array($p[1])) {
  2391.                 $ps[$p[0]] $p[1];
  2392.             else {
  2393.                 $ps[$p;
  2394.             }
  2395.         }
  2396.  
  2397.         // loops over the param map and assigns values from the template or default value for unset optional params
  2398.         while (list($k,$veach($map)) {
  2399.             if ($v[0=== '*'{
  2400.                 // "rest" array parameter, fill every remaining params in it and then break
  2401.                 if (count($ps=== 0{
  2402.                     if ($v[1]===false{
  2403.                         throw new Dwoo_Compilation_Exception($this'Rest argument missing for '.str_replace(array('Dwoo_Plugin_''_compile')''(is_array($callback$callback[0$callback)));
  2404.                     else {
  2405.                         break;
  2406.                     }
  2407.                 }
  2408.                 $tmp array();
  2409.                 $tmp2 array();
  2410.                 foreach ($ps as $i=>$p{
  2411.                     $tmp[$i$p[0];
  2412.                     $tmp2[$i$p[1];
  2413.                 }
  2414.                 $paramlist[$v[0]] array($tmp$tmp2);
  2415.                 unset($tmp$tmp2$i$p);
  2416.                 break;
  2417.             elseif (isset($ps[$v[0]])) {
  2418.                 // parameter is defined as named param
  2419.                 $paramlist[$v[0]] $ps[$v[0]];
  2420.                 unset($ps[$v[0]]);
  2421.             elseif (isset($ps[$k])) {
  2422.                 // parameter is defined as ordered param
  2423.                 $paramlist[$v[0]] $ps[$k];
  2424.                 unset($ps[$k]);
  2425.             elseif ($v[1]===false{
  2426.                 // parameter is not defined and not optional, throw error
  2427.                 throw new Dwoo_Compilation_Exception($this'Argument '.$k.'/'.$v[0].' missing for '.str_replace(array('Dwoo_Plugin_''_compile')''(is_array($callback$callback[0$callback)));
  2428.             elseif ($v[2]===null{
  2429.                 // enforce lowercased null if default value is null (php outputs NULL with var export)
  2430.                 $paramlist[$v[0]] array('null'null);
  2431.             else {
  2432.                 // outputs default value with var_export
  2433.                 $paramlist[$v[0]] array(var_export($v[2]true)$v[2]);
  2434.             }
  2435.         }
  2436.  
  2437.         return $paramlist;
  2438.     }
  2439.  
  2440.     /**
  2441.      * returns the parameter map of the given callback, it filters out entries typed as Dwoo and Dwoo_Compiler and turns the rest parameter into a "*"
  2442.      *
  2443.      * @param callback $callback the function/method to reflect on
  2444.      * @return array processed parameter map
  2445.      */
  2446.     protected function getParamMap($callback)
  2447.     {
  2448.         if (is_null($callback)) {
  2449.             return array(array('*'true));
  2450.         }
  2451.         if (is_array($callback)) {
  2452.             $ref new ReflectionMethod($callback[0]$callback[1]);
  2453.         else {
  2454.             $ref new ReflectionFunction($callback);
  2455.         }
  2456.  
  2457.         $out array();
  2458.         foreach ($ref->getParameters(as $param{
  2459.             if (($class $param->getClass()) !== null && $class->name === 'Dwoo'{
  2460.                 continue;
  2461.             }
  2462.             if (($class $param->getClass()) !== null && $class->name === 'Dwoo_Compiler'{
  2463.                 continue;
  2464.             }
  2465.             if ($param->getName(=== 'rest' && $param->isArray(=== true{
  2466.                 $out[array('*'$param->isOptional()null);
  2467.             }
  2468.             $out[array($param->getName()$param->isOptional()$param->isOptional($param->getDefaultValue(null);
  2469.         }
  2470.  
  2471.         return $out;
  2472.     }
  2473.  
  2474.     /**
  2475.      * returns a default instance of this compiler, used by default by all Dwoo templates that do not have a
  2476.      * specific compiler assigned and when you do not override the default compiler factory function
  2477.      *
  2478.      * @see Dwoo::setDefaultCompilerFactory()
  2479.      * @return Dwoo_Compiler 
  2480.      */
  2481.     public static function compilerFactory()
  2482.     {
  2483.         if (self::$instance === null{
  2484.             self::$instance new self;
  2485.         }
  2486.         return self::$instance;
  2487.     }
  2488. }

Documentation generated on Sat, 28 Jun 2008 01:38:13 +0200 by phpDocumentor 1.4.0