|
@@ -16,6 +16,9 @@
|
|
|
*/
|
|
*/
|
|
|
class Mustache_Compiler
|
|
class Mustache_Compiler
|
|
|
{
|
|
{
|
|
|
|
|
+
|
|
|
|
|
+ private $pragmas;
|
|
|
|
|
+ private $defaultPragmas = array();
|
|
|
private $sections;
|
|
private $sections;
|
|
|
private $source;
|
|
private $source;
|
|
|
private $indentNextLine;
|
|
private $indentNextLine;
|
|
@@ -23,7 +26,6 @@ class Mustache_Compiler
|
|
|
private $entityFlags;
|
|
private $entityFlags;
|
|
|
private $charset;
|
|
private $charset;
|
|
|
private $strictCallables;
|
|
private $strictCallables;
|
|
|
- private $pragmas;
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Compile a Mustache token parse tree into PHP source code.
|
|
* Compile a Mustache token parse tree into PHP source code.
|
|
@@ -40,7 +42,7 @@ class Mustache_Compiler
|
|
|
*/
|
|
*/
|
|
|
public function compile($source, array $tree, $name, $customEscape = false, $charset = 'UTF-8', $strictCallables = false, $entityFlags = ENT_COMPAT)
|
|
public function compile($source, array $tree, $name, $customEscape = false, $charset = 'UTF-8', $strictCallables = false, $entityFlags = ENT_COMPAT)
|
|
|
{
|
|
{
|
|
|
- $this->pragmas = array();
|
|
|
|
|
|
|
+ $this->pragmas = $this->defaultPragmas;
|
|
|
$this->sections = array();
|
|
$this->sections = array();
|
|
|
$this->source = $source;
|
|
$this->source = $source;
|
|
|
$this->indentNextLine = true;
|
|
$this->indentNextLine = true;
|
|
@@ -52,6 +54,23 @@ class Mustache_Compiler
|
|
|
return $this->writeCode($tree, $name);
|
|
return $this->writeCode($tree, $name);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Enable pragmas across all templates, regardless of the presence of pragma
|
|
|
|
|
+ * tags in the individual templates.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @internal Users should set global pragmas in Mustache_Engine, not here :)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param string[] $pragmas
|
|
|
|
|
+ */
|
|
|
|
|
+ public function setPragmas(array $pragmas)
|
|
|
|
|
+ {
|
|
|
|
|
+ $this->pragmas = array();
|
|
|
|
|
+ foreach ($pragmas as $pragma) {
|
|
|
|
|
+ $this->pragmas[$pragma] = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ $this->defaultPragmas = $this->pragmas;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Helper function for walking the Mustache token parse tree.
|
|
* Helper function for walking the Mustache token parse tree.
|
|
|
*
|
|
*
|
|
@@ -76,6 +95,7 @@ class Mustache_Compiler
|
|
|
$code .= $this->section(
|
|
$code .= $this->section(
|
|
|
$node[Mustache_Tokenizer::NODES],
|
|
$node[Mustache_Tokenizer::NODES],
|
|
|
$node[Mustache_Tokenizer::NAME],
|
|
$node[Mustache_Tokenizer::NAME],
|
|
|
|
|
+ isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(),
|
|
|
$node[Mustache_Tokenizer::INDEX],
|
|
$node[Mustache_Tokenizer::INDEX],
|
|
|
$node[Mustache_Tokenizer::END],
|
|
$node[Mustache_Tokenizer::END],
|
|
|
$node[Mustache_Tokenizer::OTAG],
|
|
$node[Mustache_Tokenizer::OTAG],
|
|
@@ -88,12 +108,12 @@ class Mustache_Compiler
|
|
|
$code .= $this->invertedSection(
|
|
$code .= $this->invertedSection(
|
|
|
$node[Mustache_Tokenizer::NODES],
|
|
$node[Mustache_Tokenizer::NODES],
|
|
|
$node[Mustache_Tokenizer::NAME],
|
|
$node[Mustache_Tokenizer::NAME],
|
|
|
|
|
+ isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(),
|
|
|
$level
|
|
$level
|
|
|
);
|
|
);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case Mustache_Tokenizer::T_PARTIAL:
|
|
case Mustache_Tokenizer::T_PARTIAL:
|
|
|
- case Mustache_Tokenizer::T_PARTIAL_2:
|
|
|
|
|
$code .= $this->partial(
|
|
$code .= $this->partial(
|
|
|
$node[Mustache_Tokenizer::NAME],
|
|
$node[Mustache_Tokenizer::NAME],
|
|
|
isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '',
|
|
isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '',
|
|
@@ -101,16 +121,51 @@ class Mustache_Compiler
|
|
|
);
|
|
);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
- case Mustache_Tokenizer::T_UNESCAPED:
|
|
|
|
|
- case Mustache_Tokenizer::T_UNESCAPED_2:
|
|
|
|
|
- $code .= $this->variable($node[Mustache_Tokenizer::NAME], false, $level);
|
|
|
|
|
|
|
+ case Mustache_Tokenizer::T_PARENT:
|
|
|
|
|
+ $code .= $this->parent(
|
|
|
|
|
+ $node[Mustache_Tokenizer::NAME],
|
|
|
|
|
+ isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '',
|
|
|
|
|
+ $node[Mustache_Tokenizer::NODES],
|
|
|
|
|
+ $level
|
|
|
|
|
+ );
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case Mustache_Tokenizer::T_BLOCK_ARG:
|
|
|
|
|
+ $code .= $this->blockArg(
|
|
|
|
|
+ $node[Mustache_Tokenizer::NODES],
|
|
|
|
|
+ $node[Mustache_Tokenizer::NAME],
|
|
|
|
|
+ $node[Mustache_Tokenizer::INDEX],
|
|
|
|
|
+ $node[Mustache_Tokenizer::END],
|
|
|
|
|
+ $node[Mustache_Tokenizer::OTAG],
|
|
|
|
|
+ $node[Mustache_Tokenizer::CTAG],
|
|
|
|
|
+ $level
|
|
|
|
|
+ );
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case Mustache_Tokenizer::T_BLOCK_VAR:
|
|
|
|
|
+ $code .= $this->blockVar(
|
|
|
|
|
+ $node[Mustache_Tokenizer::NODES],
|
|
|
|
|
+ $node[Mustache_Tokenizer::NAME],
|
|
|
|
|
+ $node[Mustache_Tokenizer::INDEX],
|
|
|
|
|
+ $node[Mustache_Tokenizer::END],
|
|
|
|
|
+ $node[Mustache_Tokenizer::OTAG],
|
|
|
|
|
+ $node[Mustache_Tokenizer::CTAG],
|
|
|
|
|
+ $level
|
|
|
|
|
+ );
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case Mustache_Tokenizer::T_COMMENT:
|
|
case Mustache_Tokenizer::T_COMMENT:
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case Mustache_Tokenizer::T_ESCAPED:
|
|
case Mustache_Tokenizer::T_ESCAPED:
|
|
|
- $code .= $this->variable($node[Mustache_Tokenizer::NAME], true, $level);
|
|
|
|
|
|
|
+ case Mustache_Tokenizer::T_UNESCAPED:
|
|
|
|
|
+ case Mustache_Tokenizer::T_UNESCAPED_2:
|
|
|
|
|
+ $code .= $this->variable(
|
|
|
|
|
+ $node[Mustache_Tokenizer::NAME],
|
|
|
|
|
+ isset($node[Mustache_Tokenizer::FILTERS]) ? $node[Mustache_Tokenizer::FILTERS] : array(),
|
|
|
|
|
+ $node[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_ESCAPED,
|
|
|
|
|
+ $level
|
|
|
|
|
+ );
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case Mustache_Tokenizer::T_TEXT:
|
|
case Mustache_Tokenizer::T_TEXT:
|
|
@@ -135,6 +190,7 @@ class Mustache_Compiler
|
|
|
{
|
|
{
|
|
|
$this->lambdaHelper = new Mustache_LambdaHelper($this->mustache, $context);
|
|
$this->lambdaHelper = new Mustache_LambdaHelper($this->mustache, $context);
|
|
|
$buffer = \'\';
|
|
$buffer = \'\';
|
|
|
|
|
+ $newContext = array();
|
|
|
%s
|
|
%s
|
|
|
|
|
|
|
|
return $buffer;
|
|
return $buffer;
|
|
@@ -149,6 +205,7 @@ class Mustache_Compiler
|
|
|
public function renderInternal(Mustache_Context $context, $indent = \'\')
|
|
public function renderInternal(Mustache_Context $context, $indent = \'\')
|
|
|
{
|
|
{
|
|
|
$buffer = \'\';
|
|
$buffer = \'\';
|
|
|
|
|
+ $newContext = array();
|
|
|
%s
|
|
%s
|
|
|
|
|
|
|
|
return $buffer;
|
|
return $buffer;
|
|
@@ -170,11 +227,68 @@ class Mustache_Compiler
|
|
|
$code = $this->walk($tree);
|
|
$code = $this->walk($tree);
|
|
|
$sections = implode("\n", $this->sections);
|
|
$sections = implode("\n", $this->sections);
|
|
|
$klass = empty($this->sections) ? self::KLASS_NO_LAMBDAS : self::KLASS;
|
|
$klass = empty($this->sections) ? self::KLASS_NO_LAMBDAS : self::KLASS;
|
|
|
|
|
+
|
|
|
$callable = $this->strictCallables ? $this->prepare(self::STRICT_CALLABLE) : '';
|
|
$callable = $this->strictCallables ? $this->prepare(self::STRICT_CALLABLE) : '';
|
|
|
|
|
|
|
|
return sprintf($this->prepare($klass, 0, false, true), $name, $callable, $code, $sections);
|
|
return sprintf($this->prepare($klass, 0, false, true), $name, $callable, $code, $sections);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ const BLOCK_VAR = '
|
|
|
|
|
+ $value = $this->resolveValue($context->findInBlock(%s), $context, $indent);
|
|
|
|
|
+ if ($value && !is_array($value) && !is_object($value)) {
|
|
|
|
|
+ $buffer .= $value;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ %s
|
|
|
|
|
+ }
|
|
|
|
|
+ ';
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Generate Mustache Template inheritance block variable 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
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return string Generated PHP source code
|
|
|
|
|
+ */
|
|
|
|
|
+ private function blockVar($nodes, $id, $start, $end, $otag, $ctag, $level)
|
|
|
|
|
+ {
|
|
|
|
|
+ $id = var_export($id, true);
|
|
|
|
|
+
|
|
|
|
|
+ return sprintf($this->prepare(self::BLOCK_VAR, $level), $id, $this->walk($nodes, 2));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const BLOCK_ARG = '
|
|
|
|
|
+ // %s block_arg
|
|
|
|
|
+ $value = $this->section%s($context, $indent, true);
|
|
|
|
|
+ $newContext[%s] = %s$value;
|
|
|
|
|
+ ';
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Generate Mustache Template inheritance block argument 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
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return string Generated PHP source code
|
|
|
|
|
+ */
|
|
|
|
|
+ private function blockArg($nodes, $id, $start, $end, $otag, $ctag, $level)
|
|
|
|
|
+ {
|
|
|
|
|
+ $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());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const SECTION_CALL = '
|
|
const SECTION_CALL = '
|
|
|
// %s section
|
|
// %s section
|
|
|
$value = $context->%s(%s);%s
|
|
$value = $context->%s(%s);%s
|
|
@@ -198,7 +312,8 @@ class Mustache_Compiler
|
|
|
} elseif (!empty($value)) {
|
|
} elseif (!empty($value)) {
|
|
|
$values = $this->isIterable($value) ? $value : array($value);
|
|
$values = $this->isIterable($value) ? $value : array($value);
|
|
|
foreach ($values as $value) {
|
|
foreach ($values as $value) {
|
|
|
- $context->push($value);%s
|
|
|
|
|
|
|
+ $context->push($value);
|
|
|
|
|
+ %s
|
|
|
$context->pop();
|
|
$context->pop();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -209,26 +324,20 @@ class Mustache_Compiler
|
|
|
/**
|
|
/**
|
|
|
* Generate Mustache Template section PHP source.
|
|
* 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 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
|
|
* @return string Generated section PHP source code
|
|
|
*/
|
|
*/
|
|
|
- private function section($nodes, $id, $start, $end, $otag, $ctag, $level)
|
|
|
|
|
|
|
+ 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);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- $method = $this->getFindMethod($id);
|
|
|
|
|
- $id = var_export($id, true);
|
|
|
|
|
$source = var_export(substr($this->source, $start, $end - $start), true);
|
|
$source = var_export(substr($this->source, $start, $end - $start), true);
|
|
|
$callable = $this->getCallable();
|
|
$callable = $this->getCallable();
|
|
|
|
|
|
|
@@ -238,13 +347,21 @@ class Mustache_Compiler
|
|
|
$delims = '';
|
|
$delims = '';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- $key = ucfirst(md5($delims."\n".$source));
|
|
|
|
|
|
|
+ $key = ucfirst(md5($delims."\n".$source));
|
|
|
|
|
|
|
|
if (!isset($this->sections[$key])) {
|
|
if (!isset($this->sections[$key])) {
|
|
|
$this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $delims, $this->walk($nodes, 2));
|
|
$this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $delims, $this->walk($nodes, 2));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return sprintf($this->prepare(self::SECTION_CALL, $level), $id, $method, $id, $filters, $key);
|
|
|
|
|
|
|
+ if ($arg === true) {
|
|
|
|
|
+ return $key;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $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);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const INVERTED_SECTION = '
|
|
const INVERTED_SECTION = '
|
|
@@ -257,29 +374,26 @@ class Mustache_Compiler
|
|
|
/**
|
|
/**
|
|
|
* Generate Mustache Template inverted section PHP source.
|
|
* 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
|
|
* @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));
|
|
return sprintf($this->prepare(self::INVERTED_SECTION, $level), $id, $method, $id, $filters, $this->walk($nodes, $level));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ const PARTIAL_INDENT = ', $indent . %s';
|
|
|
const PARTIAL = '
|
|
const PARTIAL = '
|
|
|
if ($partial = $this->mustache->loadPartial(%s)) {
|
|
if ($partial = $this->mustache->loadPartial(%s)) {
|
|
|
- $buffer .= $partial->renderInternal($context, $indent . %s);
|
|
|
|
|
|
|
+ $buffer .= $partial->renderInternal($context%s);
|
|
|
}
|
|
}
|
|
|
';
|
|
';
|
|
|
|
|
|
|
@@ -294,56 +408,86 @@ class Mustache_Compiler
|
|
|
*/
|
|
*/
|
|
|
private function partial($id, $indent, $level)
|
|
private function partial($id, $indent, $level)
|
|
|
{
|
|
{
|
|
|
|
|
+ if ($indent !== '') {
|
|
|
|
|
+ $indentParam = sprintf(self::PARTIAL_INDENT, var_export($indent, true));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $indentParam = '';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return sprintf(
|
|
return sprintf(
|
|
|
$this->prepare(self::PARTIAL, $level),
|
|
$this->prepare(self::PARTIAL, $level),
|
|
|
var_export($id, true),
|
|
var_export($id, true),
|
|
|
- var_export($indent, true)
|
|
|
|
|
|
|
+ $indentParam
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const VARIABLE = '
|
|
|
|
|
- $value = $this->resolveValue($context->%s(%s), $context, $indent);%s
|
|
|
|
|
- $buffer .= %s%s;
|
|
|
|
|
|
|
+ const PARENT = '
|
|
|
|
|
+ %s
|
|
|
|
|
+
|
|
|
|
|
+ if ($parent = $this->mustache->LoadPartial(%s)) {
|
|
|
|
|
+ $context->pushBlockContext($newContext);
|
|
|
|
|
+ $buffer .= $parent->renderInternal($context, $indent);
|
|
|
|
|
+ $context->popBlockContext();
|
|
|
|
|
+ }
|
|
|
';
|
|
';
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * Generate Mustache Template variable interpolation PHP source.
|
|
|
|
|
|
|
+ * Generate Mustache Template inheritance parent call PHP source.
|
|
|
*
|
|
*
|
|
|
- * @param string $id Variable name
|
|
|
|
|
- * @param boolean $escape Escape the variable value for output?
|
|
|
|
|
- * @param int $level
|
|
|
|
|
|
|
+ * @param string $id Parent tag name
|
|
|
|
|
+ * @param string $indent Whitespace indent to apply to parent
|
|
|
|
|
+ * @param array $children Child nodes
|
|
|
|
|
+ * @param int $level
|
|
|
*
|
|
*
|
|
|
- * @return string Generated variable interpolation PHP source
|
|
|
|
|
|
|
+ * @return string Generated PHP source code
|
|
|
*/
|
|
*/
|
|
|
- private function variable($id, $escape, $level)
|
|
|
|
|
|
|
+ private function parent($id, $indent, array $children, $level)
|
|
|
{
|
|
{
|
|
|
- $filters = '';
|
|
|
|
|
-
|
|
|
|
|
- if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) {
|
|
|
|
|
- list($id, $filters) = $this->getFilters($id, $level);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ $realChildren = array_filter($children, array(__CLASS__, 'onlyBlockArgs'));
|
|
|
|
|
|
|
|
- $method = $this->getFindMethod($id);
|
|
|
|
|
- $id = ($method !== 'last') ? var_export($id, true) : '';
|
|
|
|
|
- $value = $escape ? $this->getEscape() : '$value';
|
|
|
|
|
|
|
+ return sprintf(
|
|
|
|
|
+ $this->prepare(self::PARENT, $level),
|
|
|
|
|
+ $this->walk($realChildren, $level),
|
|
|
|
|
+ var_export($id, true),
|
|
|
|
|
+ var_export($indent, true)
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return sprintf($this->prepare(self::VARIABLE, $level), $method, $id, $filters, $this->flushIndent(), $value);
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Helper method for filtering out non-block-arg tokens.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param array $node
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return boolean True if $node is a block arg token.
|
|
|
|
|
+ */
|
|
|
|
|
+ private static function onlyBlockArgs(array $node)
|
|
|
|
|
+ {
|
|
|
|
|
+ return $node[Mustache_Tokenizer::TYPE] === Mustache_Tokenizer::T_BLOCK_ARG;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ const VARIABLE = '
|
|
|
|
|
+ $value = $this->resolveValue($context->%s(%s), $context, $indent);%s
|
|
|
|
|
+ $buffer .= %s%s;
|
|
|
|
|
+ ';
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
- * Generate Mustache Template variable filtering PHP source.
|
|
|
|
|
|
|
+ * Generate Mustache Template variable interpolation PHP source.
|
|
|
*
|
|
*
|
|
|
- * @param string $id Variable name
|
|
|
|
|
- * @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 filtering PHP source
|
|
|
|
|
|
|
+ * @return string Generated variable interpolation PHP source
|
|
|
*/
|
|
*/
|
|
|
- private function getFilters($id, $level)
|
|
|
|
|
|
|
+ private function variable($id, $filters, $escape, $level)
|
|
|
{
|
|
{
|
|
|
- $filters = array_map('trim', explode('|', $id));
|
|
|
|
|
- $id = array_shift($filters);
|
|
|
|
|
|
|
+ $method = $this->getFindMethod($id);
|
|
|
|
|
+ $id = ($method !== 'last') ? var_export($id, true) : '';
|
|
|
|
|
+ $filters = $this->getFilters($filters, $level);
|
|
|
|
|
+ $value = $escape ? $this->getEscape() : '$value';
|
|
|
|
|
|
|
|
- return array($id, $this->getFilter($filters, $level));
|
|
|
|
|
|
|
+ return sprintf($this->prepare(self::VARIABLE, $level), $method, $id, $filters, $this->flushIndent(), $value);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const FILTER = '
|
|
const FILTER = '
|
|
@@ -355,14 +499,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
|
|
* @return string Generated filter PHP source
|
|
|
*/
|
|
*/
|
|
|
- private function getFilter(array $filters, $level)
|
|
|
|
|
|
|
+ private function getFilters(array $filters, $level)
|
|
|
{
|
|
{
|
|
|
if (empty($filters)) {
|
|
if (empty($filters)) {
|
|
|
return '';
|
|
return '';
|
|
@@ -374,7 +518,7 @@ class Mustache_Compiler
|
|
|
$callable = $this->getCallable('$filter');
|
|
$callable = $this->getCallable('$filter');
|
|
|
$msg = var_export($name, true);
|
|
$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";';
|
|
const LINE = '$buffer .= "\n";';
|
|
@@ -434,9 +578,9 @@ class Mustache_Compiler
|
|
|
{
|
|
{
|
|
|
if ($this->customEscape) {
|
|
if ($this->customEscape) {
|
|
|
return sprintf(self::CUSTOM_ESCAPE, $value);
|
|
return sprintf(self::CUSTOM_ESCAPE, $value);
|
|
|
- } else {
|
|
|
|
|
- return sprintf(self::DEFAULT_ESCAPE, $value, var_export($this->entityFlags, true), var_export($this->charset, true));
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ return sprintf(self::DEFAULT_ESCAPE, $value, var_export($this->entityFlags, true), var_export($this->charset, true));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -456,16 +600,25 @@ class Mustache_Compiler
|
|
|
{
|
|
{
|
|
|
if ($id === '.') {
|
|
if ($id === '.') {
|
|
|
return 'last';
|
|
return 'last';
|
|
|
- } elseif (strpos($id, '.') === false) {
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (strpos($id, '.') === false) {
|
|
|
return 'find';
|
|
return 'find';
|
|
|
- } else {
|
|
|
|
|
- return 'findDot';
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ return 'findDot';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const IS_CALLABLE = '!is_string(%s) && is_callable(%s)';
|
|
const IS_CALLABLE = '!is_string(%s) && is_callable(%s)';
|
|
|
const STRICT_IS_CALLABLE = 'is_object(%s) && is_callable(%s)';
|
|
const STRICT_IS_CALLABLE = 'is_object(%s) && is_callable(%s)';
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Helper function to compile strict vs lax "is callable" logic.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param string $variable (default: '$value')
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return string "is callable" logic
|
|
|
|
|
+ */
|
|
|
private function getCallable($variable = '$value')
|
|
private function getCallable($variable = '$value')
|
|
|
{
|
|
{
|
|
|
$tpl = $this->strictCallables ? self::STRICT_IS_CALLABLE : self::IS_CALLABLE;
|
|
$tpl = $this->strictCallables ? self::STRICT_IS_CALLABLE : self::IS_CALLABLE;
|