Selaa lähdekoodia

Move filter logic from the compiler to the parser.

Justin Hileman 11 vuotta sitten
vanhempi
sitoutus
58a7726515
3 muutettua tiedostoa jossa 120 lisäystä ja 83 poistoa
  1. 52 68
      src/Mustache/Compiler.php
  2. 57 5
      src/Mustache/Parser.php
  3. 11 10
      src/Mustache/Tokenizer.php

+ 52 - 68
src/Mustache/Compiler.php

@@ -60,7 +60,7 @@ class Mustache_Compiler
      *
      * @internal Users should set global pragmas in Mustache_Engine, not here :)
      *
-     * @param array $pragmas
+     * @param string[] $pragmas
      */
     public function setPragmas(array $pragmas)
     {
@@ -95,6 +95,7 @@ class Mustache_Compiler
                     $code .= $this->section(
                         $node[Mustache_Tokenizer::NODES],
                         $node[Mustache_Tokenizer::NAME],
+                        isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(),
                         $node[Mustache_Tokenizer::INDEX],
                         $node[Mustache_Tokenizer::END],
                         $node[Mustache_Tokenizer::OTAG],
@@ -107,6 +108,7 @@ class Mustache_Compiler
                     $code .= $this->invertedSection(
                         $node[Mustache_Tokenizer::NODES],
                         $node[Mustache_Tokenizer::NAME],
+                        isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(),
                         $level
                     );
                     break;
@@ -154,14 +156,24 @@ class Mustache_Compiler
 
                 case Mustache_Tokenizer::T_UNESCAPED:
                 case Mustache_Tokenizer::T_UNESCAPED_2:
-                    $code .= $this->variable($node[Mustache_Tokenizer::NAME], false, $level);
+                    $code .= $this->variable(
+                        $node[Mustache_Tokenizer::NAME],
+                        isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(),
+                        false,
+                        $level
+                    );
                     break;
 
                 case Mustache_Tokenizer::T_COMMENT:
                     break;
 
                 case Mustache_Tokenizer::T_ESCAPED:
-                    $code .= $this->variable($node[Mustache_Tokenizer::NAME], true, $level);
+                    $code .= $this->variable(
+                        $node[Mustache_Tokenizer::NAME],
+                        isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(),
+                        true,
+                        $level
+                    );
                     break;
 
                 case Mustache_Tokenizer::T_TEXT:
@@ -279,8 +291,8 @@ class Mustache_Compiler
      */
     private function blockArg($nodes, $id, $start, $end, $otag, $ctag, $level)
     {
-        $key = $this->section($nodes, $id, $start, $end, $otag, $ctag, $level, true);
-        $id       = var_export($id, true);
+        $key = $this->section($nodes, $id, array(), $start, $end, $otag, $ctag, $level, true);
+        $id  = var_export($id, true);
 
         return sprintf($this->prepare(self::BLOCK_ARG, $level), $id, $key, $id, $this->flushIndent());
     }
@@ -320,25 +332,20 @@ class Mustache_Compiler
     /**
      * Generate Mustache Template section PHP source.
      *
-     * @param array  $nodes Array of child tokens
-     * @param string $id    Section name
-     * @param int    $start Section start offset
-     * @param int    $end   Section end offset
-     * @param string $otag  Current Mustache opening tag
-     * @param string $ctag  Current Mustache closing tag
-     * @param int    $level
-     * @param bool   $arg   (default: false)
+     * @param array    $nodes   Array of child tokens
+     * @param string   $id      Section name
+     * @param string[] $filters Array of filters
+     * @param int      $start   Section start offset
+     * @param int      $end     Section end offset
+     * @param string   $otag    Current Mustache opening tag
+     * @param string   $ctag    Current Mustache closing tag
+     * @param int      $level
+     * @param bool     $arg     (default: false)
      *
      * @return string Generated section PHP source code
      */
-    private function section($nodes, $id, $start, $end, $otag, $ctag, $level, $arg = false)
+    private function section($nodes, $id, $filters, $start, $end, $otag, $ctag, $level, $arg = false)
     {
-        $filters = '';
-
-        if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) {
-            list($id, $filters) = $this->getFilters($id, $level);
-        }
-
         $source   = var_export(substr($this->source, $start, $end - $start), true);
         $callable = $this->getCallable();
 
@@ -357,8 +364,9 @@ class Mustache_Compiler
         if ($arg === true) {
             return $key;
         } else {
-            $method = $this->getFindMethod($id);
-            $id     = var_export($id, true);
+            $method  = $this->getFindMethod($id);
+            $id      = var_export($id, true);
+            $filters = $this->getFilters($filters, $level);
 
             return sprintf($this->prepare(self::SECTION_CALL, $level), $id, $method, $id, $filters, $key);
         }
@@ -374,22 +382,18 @@ class Mustache_Compiler
     /**
      * Generate Mustache Template inverted section PHP source.
      *
-     * @param array  $nodes Array of child tokens
-     * @param string $id    Section name
-     * @param int    $level
+     * @param array    $nodes   Array of child tokens
+     * @param string   $id      Section name
+     * @param string[] $filters Array of filters
+     * @param int      $level
      *
      * @return string Generated inverted section PHP source code
      */
-    private function invertedSection($nodes, $id, $level)
+    private function invertedSection($nodes, $id, $filters, $level)
     {
-        $filters = '';
-
-        if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) {
-            list($id, $filters) = $this->getFilters($id, $level);
-        }
-
-        $method = $this->getFindMethod($id);
-        $id     = var_export($id, true);
+        $method  = $this->getFindMethod($id);
+        $id      = var_export($id, true);
+        $filters = $this->getFilters($filters, $level);
 
         return sprintf($this->prepare(self::INVERTED_SECTION, $level), $id, $method, $id, $filters, $this->walk($nodes, $level));
     }
@@ -477,43 +481,23 @@ class Mustache_Compiler
     /**
      * Generate Mustache Template variable interpolation PHP source.
      *
-     * @param string  $id     Variable name
-     * @param boolean $escape Escape the variable value for output?
-     * @param int     $level
+     * @param string   $id      Variable name
+     * @param string[] $filters Array of filters
+     * @param boolean  $escape  Escape the variable value for output?
+     * @param int      $level
      *
      * @return string Generated variable interpolation PHP source
      */
-    private function variable($id, $escape, $level)
+    private function variable($id, $filters, $escape, $level)
     {
-        $filters = '';
-
-        if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) {
-            list($id, $filters) = $this->getFilters($id, $level);
-        }
-
-        $method = $this->getFindMethod($id);
-        $id     = ($method !== 'last') ? var_export($id, true) : '';
-        $value  = $escape ? $this->getEscape() : '$value';
+        $method  = $this->getFindMethod($id);
+        $id      = ($method !== 'last') ? var_export($id, true) : '';
+        $filters = $this->getFilters($filters, $level);
+        $value   = $escape ? $this->getEscape() : '$value';
 
         return sprintf($this->prepare(self::VARIABLE, $level), $method, $id, $filters, $this->flushIndent(), $value);
     }
 
-    /**
-     * Generate Mustache Template variable filtering PHP source.
-     *
-     * @param string $id    Variable name
-     * @param int    $level
-     *
-     * @return string Generated variable filtering PHP source
-     */
-    private function getFilters($id, $level)
-    {
-        $filters = array_map('trim', explode('|', $id));
-        $id      = array_shift($filters);
-
-        return array($id, $this->getFilter($filters, $level));
-    }
-
     const FILTER = '
         $filter = $context->%s(%s);
         if (!(%s)) {
@@ -523,14 +507,14 @@ class Mustache_Compiler
     ';
 
     /**
-     * Generate PHP source for a single filter.
+     * Generate Mustache Template variable filtering PHP source.
      *
-     * @param array $filters
-     * @param int   $level
+     * @param string[] $filters Array of filters
+     * @param int      $level
      *
      * @return string Generated filter PHP source
      */
-    private function getFilter(array $filters, $level)
+    private function getFilters(array $filters, $level)
     {
         if (empty($filters)) {
             return '';
@@ -542,7 +526,7 @@ class Mustache_Compiler
         $callable = $this->getCallable('$filter');
         $msg      = var_export($name, true);
 
-        return sprintf($this->prepare(self::FILTER, $level), $method, $filter, $callable, $msg, $this->getFilter($filters, $level));
+        return sprintf($this->prepare(self::FILTER, $level), $method, $filter, $callable, $msg, $this->getFilters($filters, $level));
     }
 
     const LINE = '$buffer .= "\n";';

+ 57 - 5
src/Mustache/Parser.php

@@ -21,6 +21,9 @@ class Mustache_Parser
     private $pragmas;
     private $defaultPragmas = array();
 
+    private $pragmaFilters;
+    private $pragmaBlocks;
+
     /**
      * Process an array of Mustache tokens and convert them into a parse tree.
      *
@@ -34,6 +37,9 @@ class Mustache_Parser
         $this->lineTokens = 0;
         $this->pragmas    = $this->defaultPragmas;
 
+        $this->pragmaFilters = isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS]);
+        $this->pragmaBlocks  = isset($this->pragmas[Mustache_Engine::PRAGMA_BLOCKS]);
+
         return $this->buildTree($tokens);
     }
 
@@ -43,13 +49,13 @@ class Mustache_Parser
      *
      * @internal Users should set global pragmas in Mustache_Engine, not here :)
      *
-     * @param array $pragmas
+     * @param string[] $pragmas
      */
     public function setPragmas(array $pragmas)
     {
         $this->pragmas = array();
         foreach ($pragmas as $pragma) {
-            $this->pragmas[$pragma] = true;
+            $this->enablePragma($pragma);
         }
         $this->defaultPragmas = $this->pragmas;
     }
@@ -78,6 +84,14 @@ class Mustache_Parser
                 $this->lineTokens = 0;
             }
 
+            if ($this->pragmaFilters && isset($token[Mustache_Tokenizer::NAME])) {
+                list($name, $filters) = $this->getNameAndFilters($token[Mustache_Tokenizer::NAME]);
+                if (!empty($filters)) {
+                    $token[Mustache_Tokenizer::NAME]    = $name;
+                    $token[Mustache_Tokenizer::FILTERS] = $filters;
+                }
+            }
+
             switch ($token[Mustache_Tokenizer::TYPE]) {
                 case Mustache_Tokenizer::T_DELIM_CHANGE:
                     $this->checkIfTokenIsAllowedInParent($parent, $token);
@@ -133,7 +147,7 @@ class Mustache_Parser
                     break;
 
                 case Mustache_Tokenizer::T_BLOCK_VAR:
-                    if (isset($this->pragmas[Mustache_Engine::PRAGMA_BLOCKS])) {
+                    if ($this->pragmaBlocks) {
                         // BLOCKS pragma is enabled, let's do this!
                         if ($parent[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_PARENT) {
                             $token[Mustache_Tokenizer::TYPE] = Mustache_Tokenizer::T_BLOCK_ARG;
@@ -150,7 +164,7 @@ class Mustache_Parser
                     break;
 
                 case Mustache_Tokenizer::T_PRAGMA:
-                    $this->pragmas[$token[Mustache_Tokenizer::NAME]] = true;
+                    $this->enablePragma($token[Mustache_Tokenizer::NAME]);
                     // no break
 
                 case Mustache_Tokenizer::T_COMMENT:
@@ -184,7 +198,7 @@ class Mustache_Parser
      * @param array $nodes  Parsed nodes.
      * @param array $tokens Tokens to be parsed.
      *
-     * @return array Resulting indent token, if any.
+     * @return array|null Resulting indent token, if any.
      */
     private function clearStandaloneLines(array &$nodes, array &$tokens)
     {
@@ -265,4 +279,42 @@ class Mustache_Parser
             throw new Mustache_Exception_SyntaxException('Illegal content in < parent tag', $token);
         }
     }
+
+    /**
+     * Split a tag name into name and filters.
+     *
+     * @param string $name
+     *
+     * @return array {
+     * @type string   Tag name
+     * @type string[] Array of filters
+     *               }
+     */
+    private function getNameAndFilters($name)
+    {
+        $filters = array_map('trim', explode('|', $name));
+        $name    = array_shift($filters);
+
+        return array($name, $filters);
+    }
+
+    /**
+     * Enable a pragma.
+     *
+     * @param string $name
+     */
+    private function enablePragma($name)
+    {
+        $this->pragmas[$name] = true;
+
+        switch ($name) {
+            case Mustache_Engine::PRAGMA_BLOCKS:
+                $this->pragmaBlocks = true;
+                break;
+
+            case Mustache_Engine::PRAGMA_FILTERS:
+                $this->pragmaFilters = true;
+                break;
+        }
+    }
 }

+ 11 - 10
src/Mustache/Tokenizer.php

@@ -61,16 +61,17 @@ class Mustache_Tokenizer
     );
 
     // Token properties
-    const TYPE   = 'type';
-    const NAME   = 'name';
-    const OTAG   = 'otag';
-    const CTAG   = 'ctag';
-    const LINE   = 'line';
-    const INDEX  = 'index';
-    const END    = 'end';
-    const INDENT = 'indent';
-    const NODES  = 'nodes';
-    const VALUE  = 'value';
+    const TYPE    = 'type';
+    const NAME    = 'name';
+    const OTAG    = 'otag';
+    const CTAG    = 'ctag';
+    const LINE    = 'line';
+    const INDEX   = 'index';
+    const END     = 'end';
+    const INDENT  = 'indent';
+    const NODES   = 'nodes';
+    const VALUE   = 'value';
+    const FILTERS = 'filters';
 
     private $state;
     private $tagType;