/**
  Handles filter chains. Wraps given code, and returns new one.
  
  @param[in] $node Filter chain source node
  @param[in] $filterExpr Filter chain expression (e.g. a|b|c:d)
  @param[in] $code Code to wrap in filters
  @return New code that uses filters
 */
 public function parseFilterChain(TemplateNodeEx $node, $filterExpr, $code)
 {
     $filterChain = TemplateUtils::splitEscaped('|', $filterExpr);
     $resultCode = $code;
     // Hook-point: parseFilterChain:entry
     $this->runHooks('parseFilterChain:entry', array(&$filterChain));
     //
     foreach ($filterChain as &$filter) {
         list($name, $args) = TemplateUtils::split(':', $filter);
         if ($args) {
             $args = TemplateUtils::splitEscaped(',', $args);
         } else {
             $args = array();
         }
         foreach ($args as &$arg) {
             if (mb_substr($arg, 0, 1) == '"') {
                 $arg = array('string', '\'' . TemplateUtils::escape(mb_substr($arg, 1, -1)) . '\'');
             } elseif (preg_match('~^\\-?[0-9]+(?:\\.[0-9]+)?$~', $arg)) {
                 $arg = array('number', $arg);
             } else {
                 list($code, ) = $this->parseVariableExpression($node, $arg);
                 $arg = array('variable', '@' . $code);
             }
         }
         $filterInfo = $this->commonVerifyElement($node, 'filter', $name, $args);
         $filterCode = call_user_func_array($filterInfo['handler'], array($this, $node, &$name, &$args));
         $resultCode = sprintf($filterCode, $resultCode);
     }
     return $resultCode;
 }
 /**
  Tests the behaviour of @ref TemplateUtils::splitEscaped.
  
  @dataProvider providerUtilsSplitEscaped
 */
 public function testUtilsSplitEscaped($delimiter, $string, $expected)
 {
     $this->assertEquals($expected, TemplateUtils::splitEscaped($delimiter, $string));
 }