This commit is contained in:
bzick 2013-08-05 13:07:16 +04:00
parent 09f952686b
commit c7a90789de
5 changed files with 62 additions and 40 deletions

View File

@ -3,8 +3,16 @@ CHANGELOG
## 1.2.0
- Feature #28: macros may be called recursively
- Feature #29: add {unset} tag
- Add hook for loading modifiers and tags
- Add hook for loading modifiers and tags
- Feature #3: Add string operator '~'
- Improve parsers: parserExp, parserVar, parserVariable, parserMacro
- Fix ternary bug
- Bugs--
- Tests++
- Docs++
## 1.1.0

View File

@ -873,7 +873,7 @@ class Compiler
public static function macroOpen(Tokenizer $tokens, Scope $scope)
{
$scope["name"] = $tokens->get(Tokenizer::MACRO_STRING);
$scope["recursive"] = array();
$scope["recursive"] = false;
$args = array();
$defaults = array();
if (!$tokens->valid()) {
@ -897,10 +897,11 @@ class Compiler
}
$tokens->skipIf(')');
$scope["macro"] = array(
"id" => $scope->tpl->i++,
"name" => $scope["name"],
"args" => $args,
"defaults" => $defaults,
"body" => ""
"body" => "",
"recursive" => false
);
return;
}
@ -912,21 +913,9 @@ class Compiler
public static function macroClose(Tokenizer $tokens, Scope $scope)
{
if ($scope["recursive"]) {
$switch = "switch(\$call['mark']) {\n";
foreach ($scope["recursive"] as $mark) {
$switch .= "case $mark: goto macro_$mark;\n";
}
$switch .= "}";
$stack = '$stack_' . $scope["macro"]['id'];
$scope["macro"]["body"] = '<?php ' . $stack . ' = array(); macro_' . $scope["macro"]['id'] . ': ?>' . $scope->cutContent() . '<?php if(' . $stack . ') {' . PHP_EOL .
'$call = array_pop(' . $stack . ');' . PHP_EOL .
'$tpl = $call["tpl"];' . PHP_EOL .
$switch . PHP_EOL .
'unset($call, ' . $stack . ');' . PHP_EOL .
'} ?>';
} else {
$scope["macro"]["body"] = $scope->cutContent();
$scope["macro"]["recursive"] = true;
}
$scope["macro"]["body"] = $scope->cutContent();
$scope->tpl->macros[$scope["name"]] = $scope["macro"];
}

View File

@ -21,7 +21,8 @@ class Render extends \ArrayObject
"base_name" => "",
"scm" => false,
"time" => 0,
"depends" => array()
"depends" => array(),
"macros" => array()
);
/**
* @var \Closure
@ -81,6 +82,7 @@ class Render extends \ArrayObject
$this->_scm = $props["scm"];
$this->_time = $props["time"];
$this->_depends = $props["depends"];
$this->_macros = $props["macros"];
$this->_code = $code;
}
@ -183,6 +185,15 @@ class Render extends \ArrayObject
return true;
}
/**
* Get internal macro
* @param $name
* @return mixed
*/
public function getMacro($name) {
return $this->_macros[$name];
}
/**
* Execute template and write into output
* @param array $values for template

View File

@ -397,18 +397,31 @@ class Template extends Render
*/
public function getTemplateCode()
{
if($this->macros) {
$macros = array();
foreach($this->macros as $m) {
if($m["recursive"]) {
$macros[] = "\t\t'".$m["name"]."' => function (\$tpl) {\n?>".$m["body"]."<?php\n}";
}
}
$macros = "\n".implode(",\n", $macros);
} else {
$macros = "";
}
$before = $this->_before ? $this->_before . "\n" : "";
return "<?php \n" .
"/** Fenom template '" . $this->_name . "' compiled at " . date('Y-m-d H:i:s') . " */\n" .
$before . // some code 'before' template
"return new Fenom\\Render(\$fenom, " . $this->_getClosureSource() . ", " . var_export(array(
"options" => $this->_options,
"provider" => $this->_scm,
"name" => $this->_name,
"base_name" => $this->_base_name,
"time" => $this->_time,
"depends" => $this->_depends
), true) . ");\n";
"return new Fenom\\Render(\$fenom, " . $this->_getClosureSource() . ", array(\n".
"\t'options' => {$this->_options},\n".
"\t'provider' => ".var_export($this->_scm, true).",\n".
"\t'name' => ".var_export($this->_name, true).",\n".
"\t'base_name' => ".var_export($this->_base_name, true).",\n".
"\t'time' => {$this->_time},\n".
"\t'depends' => ".var_export($this->_base_name, true).",\n".
"\t'macros' => array({$macros}),
));\n";
}
/**
@ -1323,14 +1336,14 @@ class Template extends Render
throw new InvalidUsageException("Macro '$name' require '$arg' argument");
}
}
$args = $args ? '$tpl = ' . Compiler::toArray($args) . ';' : '';
$n = $this->i++;
if ($recursive) {
$n = $this->i++;
$recursive['recursive'][] = $n;
return '$stack_' . $macro['id'] . '[] = array("tpl" => $tpl, "mark" => ' . $n . '); ' . $args . ' goto macro_' . $macro['id'] . '; macro_' . $n . ':';
$recursive['recursive'] = true;
$body = '$tpl->getMacro("'.$name.'")->__invoke($tpl);';
} else {
return '$_tpl = $tpl; ' . $args . ' ?>' . $macro["body"] . '<?php $tpl = $_tpl; unset($_tpl);';
$body = '?>'.$macro["body"].'<?php';
}
return '$_tpl'.$n.' = $tpl->exchangeArray(' . Compiler::toArray($args) . ');' . PHP_EOL . $body . PHP_EOL . '$tpl->exchangeArray($_tpl'.$n.'); unset($_tpl'.$n.');';
}
/**

View File

@ -54,17 +54,18 @@ class MacrosTest extends TestCase
{macro.factorial num=10}');
}
// public function _testSandbox()
// {
// try {
// $this->fenom->compile("macro_recursive.tpl");
public function _testSandbox()
{
try {
$this->fenom->compile("macro_recursive.tpl");
// $this->fenom->flush();
// var_dump($this->fenom->fetch("macro_recursive.tpl", []));
// } catch (\Exception $e) {
// var_dump($e->getMessage() . ": " . $e->getTraceAsString());
// }
// exit;
// }
var_dump( $this->fenom->compile("macro_recursive.tpl")->getTemplateCode());
} catch (\Exception $e) {
var_dump($e->getMessage() . ": " . $e->getTraceAsString());
}
exit;
}
public function testMacros()
{