mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Done 1.4.0
This commit is contained in:
parent
3f77cdd099
commit
0a9facc493
22
CHANGELOG.md
22
CHANGELOG.md
@ -1,10 +1,21 @@
|
|||||||
CHANGELOG
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
## 1.3.1 (2013-08-29)
|
## 1.4.0
|
||||||
|
|
||||||
- Bug: accessor don't work in modifier
|
- Redesign tag {switch}
|
||||||
- Removed too many EOL in template code
|
- Add tag {insert}
|
||||||
|
- Add variable verification before using (option `Fenom::FORCE_VERIFY`)
|
||||||
|
- Improve internal parsers
|
||||||
|
- Fix #45: intersection of names of tmp vars
|
||||||
|
- Fix #44: invalid `_depend` format in template
|
||||||
|
- Docs++
|
||||||
|
- Tests++
|
||||||
|
|
||||||
|
### 1.3.1 (2013-08-29)
|
||||||
|
|
||||||
|
- Fix: accessor don't work in modifier
|
||||||
|
- Removed too many EOLs in template code
|
||||||
- Tests++
|
- Tests++
|
||||||
|
|
||||||
## 1.3.0 (2013-08-23)
|
## 1.3.0 (2013-08-23)
|
||||||
@ -15,7 +26,7 @@ CHANGELOG
|
|||||||
- Recognize macros parser
|
- Recognize macros parser
|
||||||
- Fix `auto_reload` option
|
- Fix `auto_reload` option
|
||||||
- Tests++
|
- Tests++
|
||||||
- Docs--
|
- Docs++
|
||||||
|
|
||||||
### 1.2.2 (2013-08-07)
|
### 1.2.2 (2013-08-07)
|
||||||
|
|
||||||
@ -30,7 +41,6 @@ CHANGELOG
|
|||||||
- Feature #28: macros may be called recursively
|
- Feature #28: macros may be called recursively
|
||||||
- Feature #29: add {unset} tag
|
- Feature #29: add {unset} tag
|
||||||
- Add hook for loading modifiers and tags
|
- Add hook for loading modifiers and tags
|
||||||
- Add hook for loading modifiers and tags
|
|
||||||
- Feature #3: Add string operator '~'
|
- Feature #3: Add string operator '~'
|
||||||
- Improve parsers: parserExp, parserVar, parserVariable, parserMacro
|
- Improve parsers: parserExp, parserVar, parserVariable, parserMacro
|
||||||
- Fix ternary bug
|
- Fix ternary bug
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
require_once __DIR__.'/../../vendor/autoload.php';
|
require_once __DIR__.'/../../vendor/autoload.php';
|
||||||
|
|
||||||
$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled', Fenom::FORCE_COMPILE);
|
$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled', 0);
|
||||||
|
|
||||||
$fenom->display("greeting.tpl", array(
|
$fenom->display("greeting.tpl", array(
|
||||||
"user" => array(
|
"user" => array(
|
||||||
"name" => "Ivka"
|
"name" => "Ivka",
|
||||||
)
|
'type' => 'new'
|
||||||
|
),
|
||||||
|
'type' => 'new'
|
||||||
));
|
));
|
@ -1,8 +1,5 @@
|
|||||||
Greeting,
|
{import 'macros.tpl' as mc}
|
||||||
{if $user}
|
|
||||||
{$user.name}!
|
|
||||||
{else}
|
|
||||||
anonymous?
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
3
|
A1
|
||||||
|
{mc.factorial num=10}
|
||||||
|
A2
|
5
benchmark/sandbox/templates/macros.tpl
Normal file
5
benchmark/sandbox/templates/macros.tpl
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{macro factorial(num)}
|
||||||
|
{if $num}
|
||||||
|
{$num} {macro.factorial num=$num-1} {$num}
|
||||||
|
{/if}
|
||||||
|
{/macro}
|
@ -131,11 +131,11 @@ Tests can be negated by using the `not in` operator.
|
|||||||
|
|
||||||
* `$a in $b` - variable `$a` contains in `$b`, $b may be string, plain or assoc array.
|
* `$a in $b` - variable `$a` contains in `$b`, $b may be string, plain or assoc array.
|
||||||
* `$a in list $b` - variable `$a` contains in array `$b` as value
|
* `$a in list $b` - variable `$a` contains in array `$b` as value
|
||||||
* `$a in keys $b` - variable `$a` contains in array `$b` as key
|
* `$a in keys $b` - array `$b` contain key `$a`
|
||||||
* `$a in string $b` - variable `$a` contains in string `$b` as substring
|
* `$a in string $b` - variable `$a` contains in string `$b` as substring
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{'df' in 'abcdefg'}
|
{'df' in 'abcdefg'}
|
||||||
{5 in [1, 5, 25, 125]}
|
{5 in [1, 5, 25, 125]}
|
||||||
{2 in keys [1, 5, 25, 125]}
|
{99 in keys [1, 5, 25, 99 => 125]}
|
||||||
```
|
```
|
@ -17,12 +17,12 @@ Tag {include} [RU]
|
|||||||
|
|
||||||
### {insert}
|
### {insert}
|
||||||
|
|
||||||
The tag insert template template code instead self.
|
The tag insert template code instead self.
|
||||||
|
|
||||||
* No dynamic name allowed
|
* No dynamic name allowed
|
||||||
* No variables as attribute allowed
|
* No variables as attribute allowed
|
||||||
|
|
||||||
For example,
|
For example, main.tpl:
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
a: {$a}
|
a: {$a}
|
||||||
|
@ -31,7 +31,7 @@ For example,
|
|||||||
{/switch}
|
{/switch}
|
||||||
```
|
```
|
||||||
|
|
||||||
If `$type = 'new'` template outputs
|
set `$type = 'new'`, then template output
|
||||||
|
|
||||||
```
|
```
|
||||||
It is new item
|
It is new item
|
||||||
|
@ -157,17 +157,16 @@ class Fenom
|
|||||||
'close' => 'Fenom\Compiler::stdClose',
|
'close' => 'Fenom\Compiler::stdClose',
|
||||||
'tags' => array(
|
'tags' => array(
|
||||||
'elseif' => 'Fenom\Compiler::tagElseIf',
|
'elseif' => 'Fenom\Compiler::tagElseIf',
|
||||||
'else' => 'Fenom\Compiler::tagElse',
|
'else' => 'Fenom\Compiler::tagElse'
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
'switch' => array( // {switch ...} {case ...} {break} {default} {/switch}
|
'switch' => array( // {switch ...} {case ..., ...} {default} {/switch}
|
||||||
'type' => self::BLOCK_COMPILER,
|
'type' => self::BLOCK_COMPILER,
|
||||||
'open' => 'Fenom\Compiler::switchOpen',
|
'open' => 'Fenom\Compiler::switchOpen',
|
||||||
'close' => 'Fenom\Compiler::stdClose',
|
'close' => 'Fenom\Compiler::switchClose',
|
||||||
'tags' => array(
|
'tags' => array(
|
||||||
'case' => 'Fenom\Compiler::tagCase',
|
'case' => 'Fenom\Compiler::tagCase',
|
||||||
'default' => 'Fenom\Compiler::tagDefault',
|
'default' => 'Fenom\Compiler::tagDefault'
|
||||||
'break' => 'Fenom\Compiler::tagBreak',
|
|
||||||
),
|
),
|
||||||
'float_tags' => array('break' => 1)
|
'float_tags' => array('break' => 1)
|
||||||
),
|
),
|
||||||
@ -196,6 +195,10 @@ class Fenom
|
|||||||
'type' => self::INLINE_COMPILER,
|
'type' => self::INLINE_COMPILER,
|
||||||
'parser' => 'Fenom\Compiler::tagInclude'
|
'parser' => 'Fenom\Compiler::tagInclude'
|
||||||
),
|
),
|
||||||
|
'insert' => array( // {include ...}
|
||||||
|
'type' => self::INLINE_COMPILER,
|
||||||
|
'parser' => 'Fenom\Compiler::tagInsert'
|
||||||
|
),
|
||||||
'var' => array( // {var ...}
|
'var' => array( // {var ...}
|
||||||
'type' => self::BLOCK_COMPILER,
|
'type' => self::BLOCK_COMPILER,
|
||||||
'open' => 'Fenom\Compiler::varOpen',
|
'open' => 'Fenom\Compiler::varOpen',
|
||||||
@ -205,8 +208,7 @@ class Fenom
|
|||||||
'type' => self::BLOCK_COMPILER,
|
'type' => self::BLOCK_COMPILER,
|
||||||
'open' => 'Fenom\Compiler::tagBlockOpen',
|
'open' => 'Fenom\Compiler::tagBlockOpen',
|
||||||
'close' => 'Fenom\Compiler::tagBlockClose',
|
'close' => 'Fenom\Compiler::tagBlockClose',
|
||||||
'tags' => array(
|
'tags' => array(// 'parent' => 'Fenom\Compiler::tagParent' // not implemented yet
|
||||||
'parent' => 'Fenom\Compiler::tagParent'
|
|
||||||
),
|
),
|
||||||
'float_tags' => array('parent' => 1)
|
'float_tags' => array('parent' => 1)
|
||||||
),
|
),
|
||||||
@ -608,15 +610,18 @@ class Fenom
|
|||||||
*
|
*
|
||||||
* @param string $scm scheme name
|
* @param string $scm scheme name
|
||||||
* @param Fenom\ProviderInterface $provider provider object
|
* @param Fenom\ProviderInterface $provider provider object
|
||||||
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function addProvider($scm, \Fenom\ProviderInterface $provider)
|
public function addProvider($scm, \Fenom\ProviderInterface $provider)
|
||||||
{
|
{
|
||||||
$this->_providers[$scm] = $provider;
|
$this->_providers[$scm] = $provider;
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set options
|
* Set options
|
||||||
* @param int|array $options
|
* @param int|array $options
|
||||||
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setOptions($options)
|
public function setOptions($options)
|
||||||
{
|
{
|
||||||
@ -625,6 +630,7 @@ class Fenom
|
|||||||
}
|
}
|
||||||
$this->_storage = array();
|
$this->_storage = array();
|
||||||
$this->_options = $options;
|
$this->_options = $options;
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -758,10 +764,11 @@ class Fenom
|
|||||||
{
|
{
|
||||||
$file_name = $this->_getCacheName($tpl, $opts);
|
$file_name = $this->_getCacheName($tpl, $opts);
|
||||||
if (is_file($this->_compile_dir . "/" . $file_name)) {
|
if (is_file($this->_compile_dir . "/" . $file_name)) {
|
||||||
$fenom = $this;
|
$fenom = $this; // used in template
|
||||||
$_tpl = include($this->_compile_dir . "/" . $file_name);
|
$_tpl = include($this->_compile_dir . "/" . $file_name);
|
||||||
/* @var Fenom\Render $tpl */
|
/* @var Fenom\Render $_tpl */
|
||||||
if($_tpl->isValid()) {
|
// var_dump($tpl, $_tpl->isValid()); exit;
|
||||||
|
if (!($this->_options & self::AUTO_RELOAD) || ($this->_options & self::AUTO_RELOAD) && $_tpl->isValid()) {
|
||||||
return $_tpl;
|
return $_tpl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ class Compiler
|
|||||||
$cname = $tpl->parsePlainArg($tokens, $name);
|
$cname = $tpl->parsePlainArg($tokens, $name);
|
||||||
$p = $tpl->parseParams($tokens);
|
$p = $tpl->parseParams($tokens);
|
||||||
if ($p) { // if we have additionally variables
|
if ($p) { // if we have additionally variables
|
||||||
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) { // if FORCE_INCLUDE enabled and template name known
|
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) {
|
||||||
$inc = $tpl->getStorage()->compile($name, false);
|
$inc = $tpl->getStorage()->compile($name, false);
|
||||||
$tpl->addDepend($inc);
|
$tpl->addDepend($inc);
|
||||||
return '$_tpl = (array)$tpl; $tpl->exchangeArray(' . self::toArray($p) . '+$_tpl); ?>' . $inc->getBody() . '<?php $tpl->exchangeArray($_tpl); unset($_tpl);';
|
return '$_tpl = (array)$tpl; $tpl->exchangeArray(' . self::toArray($p) . '+$_tpl); ?>' . $inc->getBody() . '<?php $tpl->exchangeArray($_tpl); unset($_tpl);';
|
||||||
@ -44,7 +44,7 @@ class Compiler
|
|||||||
return '$tpl->getStorage()->getTemplate(' . $cname . ')->display(' . self::toArray($p) . '+(array)$tpl);';
|
return '$tpl->getStorage()->getTemplate(' . $cname . ')->display(' . self::toArray($p) . '+(array)$tpl);';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) { // if FORCE_INCLUDE enabled and template name known
|
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) {
|
||||||
$inc = $tpl->getStorage()->compile($name, false);
|
$inc = $tpl->getStorage()->compile($name, false);
|
||||||
$tpl->addDepend($inc);
|
$tpl->addDepend($inc);
|
||||||
return '$_tpl = (array)$tpl; ?>' . $inc->getBody() . '<?php $tpl->exchangeArray($_tpl); unset($_tpl);';
|
return '$_tpl = (array)$tpl; ?>' . $inc->getBody() . '<?php $tpl->exchangeArray($_tpl); unset($_tpl);';
|
||||||
@ -54,6 +54,24 @@ class Compiler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag {insert ...}
|
||||||
|
* @param Tokenizer $tokens
|
||||||
|
* @param Template $tpl
|
||||||
|
* @return string
|
||||||
|
* @throws Error\InvalidUsageException
|
||||||
|
*/
|
||||||
|
public static function tagInsert(Tokenizer $tokens, Template $tpl)
|
||||||
|
{
|
||||||
|
$tpl->parsePlainArg($tokens, $name);
|
||||||
|
if (!$name) {
|
||||||
|
throw new InvalidUsageException("Tag {insert} accept only static template name");
|
||||||
|
}
|
||||||
|
$inc = $tpl->getStorage()->compile($name, false);
|
||||||
|
$tpl->addDepend($inc);
|
||||||
|
return '?>' . $tpl->getBody() . '<?php';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open tag {if ...}
|
* Open tag {if ...}
|
||||||
@ -117,7 +135,7 @@ class Compiler
|
|||||||
$key = null;
|
$key = null;
|
||||||
$before = $body = array();
|
$before = $body = array();
|
||||||
if ($tokens->is(T_VARIABLE)) {
|
if ($tokens->is(T_VARIABLE)) {
|
||||||
$from = $scope->tpl->parseVariable($tokens, Template::DENY_MODS);
|
$from = $scope->tpl->parseTerm($tokens);
|
||||||
$prepend = "";
|
$prepend = "";
|
||||||
} elseif ($tokens->is('[')) {
|
} elseif ($tokens->is('[')) {
|
||||||
$from = $scope->tpl->parseArray($tokens);
|
$from = $scope->tpl->parseArray($tokens);
|
||||||
@ -129,11 +147,11 @@ class Compiler
|
|||||||
}
|
}
|
||||||
$tokens->get(T_AS);
|
$tokens->get(T_AS);
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$value = $scope->tpl->parseVar($tokens);
|
$value = $scope->tpl->parseVariable($tokens);
|
||||||
if ($tokens->is(T_DOUBLE_ARROW)) {
|
if ($tokens->is(T_DOUBLE_ARROW)) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$key = $value;
|
$key = $value;
|
||||||
$value = $scope->tpl->parseVar($tokens);
|
$value = $scope->tpl->parseVariable($tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope["after"] = array();
|
$scope["after"] = array();
|
||||||
@ -146,7 +164,7 @@ class Compiler
|
|||||||
}
|
}
|
||||||
$tokens->getNext("=");
|
$tokens->getNext("=");
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$p[$param] = $scope->tpl->parseVar($tokens);
|
$p[$param] = $scope->tpl->parseVariable($tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($p["index"]) {
|
if ($p["index"]) {
|
||||||
@ -208,8 +226,9 @@ class Compiler
|
|||||||
* @static
|
* @static
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param Scope $scope
|
* @param Scope $scope
|
||||||
|
* @throws Error\UnexpectedTokenException
|
||||||
|
* @throws Error\InvalidUsageException
|
||||||
* @return string
|
* @return string
|
||||||
* @throws InvalidUsageException
|
|
||||||
*/
|
*/
|
||||||
public static function forOpen(Tokenizer $tokens, Scope $scope)
|
public static function forOpen(Tokenizer $tokens, Scope $scope)
|
||||||
{
|
{
|
||||||
@ -217,7 +236,10 @@ class Compiler
|
|||||||
$scope["after"] = $before = $body = array();
|
$scope["after"] = $before = $body = array();
|
||||||
$i = array('', '');
|
$i = array('', '');
|
||||||
$c = "";
|
$c = "";
|
||||||
$var = $scope->tpl->parseVariable($tokens, Template::DENY_MODS);
|
$var = $scope->tpl->parseTerm($tokens, $is_var);
|
||||||
|
if (!$is_var) {
|
||||||
|
throw new UnexpectedTokenException($tokens);
|
||||||
|
}
|
||||||
$tokens->get("=");
|
$tokens->get("=");
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$val = $scope->tpl->parseExpr($tokens);
|
$val = $scope->tpl->parseExpr($tokens);
|
||||||
@ -310,12 +332,34 @@ class Compiler
|
|||||||
*/
|
*/
|
||||||
public static function switchOpen(Tokenizer $tokens, Scope $scope)
|
public static function switchOpen(Tokenizer $tokens, Scope $scope)
|
||||||
{
|
{
|
||||||
$scope["no-break"] = $scope["no-continue"] = true;
|
$scope["expr"] = $scope->tpl->parseExpr($tokens);
|
||||||
$scope["switch"] = 'switch(' . $scope->tpl->parseExpr($tokens) . ') {';
|
$scope["case"] = array();
|
||||||
|
$scope["last"] = array();
|
||||||
|
$scope["default"] = '';
|
||||||
// lazy init
|
// lazy init
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resort cases for {switch}
|
||||||
|
* @param Scope $scope
|
||||||
|
*/
|
||||||
|
private static function _caseResort(Scope $scope)
|
||||||
|
{
|
||||||
|
$content = $scope->cutContent();
|
||||||
|
if ($scope["last"] === false) {
|
||||||
|
$scope["default"] .= $content;
|
||||||
|
} else {
|
||||||
|
foreach ($scope["last"] as $case) {
|
||||||
|
if (!isset($scope["case"][$case])) {
|
||||||
|
$scope["case"][$case] = "";
|
||||||
|
}
|
||||||
|
$scope["case"][$case] .= $content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$scope["last"] = array();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag {case ...}
|
* Tag {case ...}
|
||||||
*
|
*
|
||||||
@ -326,12 +370,52 @@ class Compiler
|
|||||||
*/
|
*/
|
||||||
public static function tagCase(Tokenizer $tokens, Scope $scope)
|
public static function tagCase(Tokenizer $tokens, Scope $scope)
|
||||||
{
|
{
|
||||||
$code = 'case ' . $scope->tpl->parseExpr($tokens) . ': ';
|
self::_caseResort($scope);
|
||||||
if ($scope["switch"]) {
|
do {
|
||||||
unset($scope["no-break"], $scope["no-continue"]);
|
$scope["last"][] = $scope->tpl->parseScalar($tokens, false);
|
||||||
$code = $scope["switch"] . "\n" . $code;
|
if ($tokens->is(',')) {
|
||||||
$scope["switch"] = "";
|
$tokens->next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag {default}
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @param Tokenizer $tokens
|
||||||
|
* @param Scope $scope
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function tagDefault($tokens, Scope $scope)
|
||||||
|
{
|
||||||
|
self::_caseResort($scope);
|
||||||
|
$scope["last"] = false;
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close tag {switch}
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @param Tokenizer $tokens
|
||||||
|
* @param Scope $scope
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function switchClose(Tokenizer $tokens, Scope $scope)
|
||||||
|
{
|
||||||
|
self::_caseResort($scope);
|
||||||
|
$expr = $scope["expr"];
|
||||||
|
$code = "";
|
||||||
|
$default = $scope["default"];
|
||||||
|
foreach ($scope["case"] as $case => $content) {
|
||||||
|
$code .= "if($expr == $case) {\n?>$content<?php\n} else";
|
||||||
}
|
}
|
||||||
|
$code .= " {\n?>$default<?php\n}";
|
||||||
return $code;
|
return $code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,25 +437,6 @@ class Compiler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tag {default}
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @param Tokenizer $tokens
|
|
||||||
* @param Scope $scope
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function tagDefault($tokens, Scope $scope)
|
|
||||||
{
|
|
||||||
$code = 'default: ';
|
|
||||||
if ($scope["switch"]) {
|
|
||||||
unset($scope["no-break"], $scope["no-continue"]);
|
|
||||||
$code = $scope["switch"] . "\n" . $code;
|
|
||||||
$scope["switch"] = "";
|
|
||||||
}
|
|
||||||
return $code;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag {break}
|
* Tag {break}
|
||||||
*
|
*
|
||||||
@ -698,7 +763,7 @@ class Compiler
|
|||||||
*/
|
*/
|
||||||
public static function varOpen(Tokenizer $tokens, Scope $scope)
|
public static function varOpen(Tokenizer $tokens, Scope $scope)
|
||||||
{
|
{
|
||||||
$var = $scope->tpl->parseVar($tokens);
|
$var = $scope->tpl->parseVariable($tokens);
|
||||||
if ($tokens->is('=')) { // inline tag {var ...}
|
if ($tokens->is('=')) { // inline tag {var ...}
|
||||||
$scope->is_closed = true;
|
$scope->is_closed = true;
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
@ -975,7 +1040,7 @@ class Compiler
|
|||||||
{
|
{
|
||||||
$vars = array();
|
$vars = array();
|
||||||
while ($tokens->valid()) {
|
while ($tokens->valid()) {
|
||||||
$vars[] = $tpl->parseVar($tokens);
|
$vars[] = $tpl->parseVariable($tokens);
|
||||||
}
|
}
|
||||||
if (!$vars) {
|
if (!$vars) {
|
||||||
throw new InvalidUsageException("Unset must accept variable(s)");
|
throw new InvalidUsageException("Unset must accept variable(s)");
|
||||||
|
@ -175,7 +175,7 @@ class Render extends \ArrayObject
|
|||||||
*/
|
*/
|
||||||
public function isValid()
|
public function isValid()
|
||||||
{
|
{
|
||||||
if (count($this->_depends) === 1) { // if no external dependencies, only self
|
if (count($this->_depends[0]) === 1) { // if no external dependencies, only self
|
||||||
$provider = $this->_fenom->getProvider($this->_scm);
|
$provider = $this->_fenom->getProvider($this->_scm);
|
||||||
if ($provider->getLastModified($this->_name) !== $this->_time) {
|
if ($provider->getLastModified($this->_name) !== $this->_time) {
|
||||||
return false;
|
return false;
|
||||||
@ -198,7 +198,7 @@ class Render extends \ArrayObject
|
|||||||
*/
|
*/
|
||||||
public function getMacro($name)
|
public function getMacro($name)
|
||||||
{
|
{
|
||||||
if(empty($this->_macros[$name])) {
|
if (empty($this->_macros[$name])) {
|
||||||
throw new RuntimeException('macro not found');
|
throw new RuntimeException('macro not found');
|
||||||
}
|
}
|
||||||
return $this->_macros[$name];
|
return $this->_macros[$name];
|
||||||
@ -247,7 +247,7 @@ class Render extends \ArrayObject
|
|||||||
|
|
||||||
public function __get($name)
|
public function __get($name)
|
||||||
{
|
{
|
||||||
if($name == 'info') {
|
if ($name == 'info') {
|
||||||
return array(
|
return array(
|
||||||
'name' => $this->_name,
|
'name' => $this->_name,
|
||||||
'schema' => $this->_scm,
|
'schema' => $this->_scm,
|
||||||
|
@ -223,10 +223,6 @@ class Template extends Render
|
|||||||
unset($comment); // cleanup
|
unset($comment); // cleanup
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// var_dump($this->_src[$pos]);
|
|
||||||
// if($this->_src[$pos] === "\n") {
|
|
||||||
// $pos++;
|
|
||||||
// }
|
|
||||||
$this->_appendText(substr($this->_src, $pos, $start - $pos));
|
$this->_appendText(substr($this->_src, $pos, $start - $pos));
|
||||||
$end = $start + 1;
|
$end = $start + 1;
|
||||||
do {
|
do {
|
||||||
@ -388,7 +384,7 @@ class Template extends Render
|
|||||||
"\t'name' => " . var_export($this->_name, true) . ",\n" .
|
"\t'name' => " . var_export($this->_name, true) . ",\n" .
|
||||||
"\t'base_name' => " . var_export($this->_base_name, true) . ",\n" .
|
"\t'base_name' => " . var_export($this->_base_name, true) . ",\n" .
|
||||||
"\t'time' => {$this->_time},\n" .
|
"\t'time' => {$this->_time},\n" .
|
||||||
"\t'depends' => " . var_export($this->_base_name, true) . ",\n" .
|
"\t'depends' => " . var_export($this->_depends, true) . ",\n" .
|
||||||
"\t'macros' => " . $this->_getMacrosArray() . ",\n
|
"\t'macros' => " . $this->_getMacrosArray() . ",\n
|
||||||
));\n";
|
));\n";
|
||||||
}
|
}
|
||||||
@ -406,7 +402,7 @@ class Template extends Render
|
|||||||
$macros[] = "\t\t'" . $m["name"] . "' => function (\$tpl) {\n?>" . $m["body"] . "<?php\n}";
|
$macros[] = "\t\t'" . $m["name"] . "' => function (\$tpl) {\n?>" . $m["body"] . "<?php\n}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "array(\n" . implode(",\n", $macros).")";
|
return "array(\n" . implode(",\n", $macros) . ")";
|
||||||
} else {
|
} else {
|
||||||
return 'array()';
|
return 'array()';
|
||||||
}
|
}
|
||||||
@ -432,7 +428,7 @@ class Template extends Render
|
|||||||
{
|
{
|
||||||
if (!$this->_code) {
|
if (!$this->_code) {
|
||||||
// evaluate template's code
|
// evaluate template's code
|
||||||
eval("\$this->_code = " . $this->_getClosureSource() . ";\n\$this->_macros = ".$this->_getMacrosArray() .';');
|
eval("\$this->_code = " . $this->_getClosureSource() . ";\n\$this->_macros = " . $this->_getMacrosArray() . ';');
|
||||||
if (!$this->_code) {
|
if (!$this->_code) {
|
||||||
throw new CompileException("Fatal error while creating the template");
|
throw new CompileException("Fatal error while creating the template");
|
||||||
}
|
}
|
||||||
@ -447,7 +443,6 @@ class Template extends Render
|
|||||||
*/
|
*/
|
||||||
public function addDepend(Render $tpl)
|
public function addDepend(Render $tpl)
|
||||||
{
|
{
|
||||||
// var_dump($tpl->getScm(),"$tpl", (new \Exception())->getTraceAsString() );
|
|
||||||
$this->_depends[$tpl->getScm()][$tpl->getName()] = $tpl->getTime();
|
$this->_depends[$tpl->getScm()][$tpl->getName()] = $tpl->getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,7 +601,6 @@ class Template extends Render
|
|||||||
* Parse expressions. The mix of operators and terms.
|
* Parse expressions. The mix of operators and terms.
|
||||||
*
|
*
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @return string
|
|
||||||
* @throws Error\UnexpectedTokenException
|
* @throws Error\UnexpectedTokenException
|
||||||
*/
|
*/
|
||||||
public function parseExpr(Tokenizer $tokens)
|
public function parseExpr(Tokenizer $tokens)
|
||||||
@ -619,6 +613,18 @@ class Template extends Render
|
|||||||
// parse term
|
// parse term
|
||||||
$term = $this->parseTerm($tokens, $var); // term of the expression
|
$term = $this->parseTerm($tokens, $var); // term of the expression
|
||||||
if ($term !== false) {
|
if ($term !== false) {
|
||||||
|
if($this->_options & Fenom::FORCE_VERIFY) {
|
||||||
|
$term = '(isset('.$term.') ? '.$term.' : null)';
|
||||||
|
$var = false;
|
||||||
|
}
|
||||||
|
if ($tokens->is('|')) {
|
||||||
|
$term = $this->parseModifier($tokens, $term);
|
||||||
|
$var = false;
|
||||||
|
}
|
||||||
|
if ($tokens->is('?', '!')) {
|
||||||
|
$term = $this->parseTernary($tokens, $term, $tokens->current());
|
||||||
|
$var = false;
|
||||||
|
}
|
||||||
$exp[] = $term;
|
$exp[] = $term;
|
||||||
$op = false;
|
$op = false;
|
||||||
} else {
|
} else {
|
||||||
@ -683,14 +689,14 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse any term of expression: -2, ++$var, 'adf'|mod:4
|
* Parse any term of expression: -2, ++$var, 'adf'
|
||||||
*
|
*
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param bool $is_var
|
* @param bool $is_var is parsed term - plain variable
|
||||||
* @return bool|string
|
|
||||||
* @throws Error\UnexpectedTokenException
|
* @throws Error\UnexpectedTokenException
|
||||||
* @throws Error\TokenizeException
|
* @throws Error\TokenizeException
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
|
* @return bool|string
|
||||||
*/
|
*/
|
||||||
public function parseTerm(Tokenizer $tokens, &$is_var = false)
|
public function parseTerm(Tokenizer $tokens, &$is_var = false)
|
||||||
{
|
{
|
||||||
@ -701,63 +707,50 @@ class Template extends Render
|
|||||||
$unary = "";
|
$unary = "";
|
||||||
}
|
}
|
||||||
if ($tokens->is(T_LNUMBER, T_DNUMBER)) {
|
if ($tokens->is(T_LNUMBER, T_DNUMBER)) {
|
||||||
return $unary . $this->parseScalar($tokens, true);
|
$code = $unary . $this->parseScalar($tokens, true);
|
||||||
} elseif ($tokens->is(T_CONSTANT_ENCAPSED_STRING, '"', T_ENCAPSED_AND_WHITESPACE)) {
|
} elseif ($tokens->is(T_CONSTANT_ENCAPSED_STRING, '"', T_ENCAPSED_AND_WHITESPACE)) {
|
||||||
if ($unary) {
|
if ($unary) {
|
||||||
throw new UnexpectedTokenException($tokens->back());
|
throw new UnexpectedTokenException($tokens->back());
|
||||||
}
|
}
|
||||||
return $this->parseScalar($tokens, true);
|
$code = $this->parseScalar($tokens, true);
|
||||||
} elseif ($tokens->is(T_VARIABLE)) {
|
} elseif ($tokens->is(T_VARIABLE)) {
|
||||||
$var = $this->parseVar($tokens);
|
$code = $unary . $this->parseVariable($tokens);
|
||||||
if ($tokens->is(Tokenizer::MACRO_INCDEC, "|", "!", "?")) {
|
if ($tokens->is("(") && $tokens->hasBackList(T_STRING, T_OBJECT_OPERATOR)) {
|
||||||
return $unary . $this->parseVariable($tokens, 0, $var);
|
if ($this->_options & Fenom::DENY_METHODS) {
|
||||||
} elseif ($tokens->is("(") && $tokens->hasBackList(T_STRING)) { // method call
|
throw new \LogicException("Forbidden to call methods");
|
||||||
return $unary . $this->parseVariable($tokens, 0, $var);
|
}
|
||||||
} elseif ($unary) {
|
$code .= $this->parseArgs($tokens);
|
||||||
return $unary . $var;
|
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
||||||
|
$code .= $tokens->getAndNext();
|
||||||
} else {
|
} else {
|
||||||
$is_var = true;
|
$is_var = true;
|
||||||
return $var;
|
|
||||||
}
|
}
|
||||||
} elseif ($tokens->is('$')) {
|
} elseif ($tokens->is('$')) {
|
||||||
$var = $this->parseAccessor($tokens, $is_var);
|
$var = $this->parseAccessor($tokens, $is_var);
|
||||||
if ($tokens->is(Tokenizer::MACRO_INCDEC, "|", "!", "?")) {
|
$code = $unary . $var;
|
||||||
return $unary . $this->parseVariable($tokens, 0, $var);
|
|
||||||
} else {
|
|
||||||
return $unary . $var;
|
|
||||||
}
|
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
||||||
return $unary . $this->parseVariable($tokens);
|
$code = $unary . $tokens->getAndNext() . $this->parseVariable($tokens);
|
||||||
} elseif ($tokens->is("(")) {
|
} elseif ($tokens->is("(")) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$exp = $unary . "(" . $this->parseExpr($tokens) . ")";
|
$code = $unary . "(" . $this->parseExpr($tokens) . ")";
|
||||||
$tokens->need(")")->next();
|
$tokens->need(")")->next();
|
||||||
return $exp;
|
|
||||||
} elseif ($tokens->is(T_STRING)) {
|
} elseif ($tokens->is(T_STRING)) {
|
||||||
if ($tokens->isSpecialVal()) {
|
if ($tokens->isSpecialVal()) {
|
||||||
return $unary . $tokens->getAndNext();
|
$code = $unary . $tokens->getAndNext();
|
||||||
} elseif ($tokens->isNext("(") && !$tokens->getWhitespace()) {
|
} elseif ($tokens->isNext("(") && !$tokens->getWhitespace()) {
|
||||||
$func = $this->_fenom->getModifier($tokens->current(), $this);
|
$func = $this->_fenom->getModifier($tokens->current(), $this);
|
||||||
if (!$func) {
|
if (!$func) {
|
||||||
throw new \Exception("Function " . $tokens->getAndNext() . " not found");
|
throw new \Exception("Function " . $tokens->getAndNext() . " not found");
|
||||||
}
|
}
|
||||||
$tokens->next();
|
$code = $unary . $func . $this->parseArgs($tokens->next());
|
||||||
$func = $func . $this->parseArgs($tokens);
|
|
||||||
if ($tokens->is('|')) {
|
|
||||||
return $unary . $this->parseModifier($tokens, $func);
|
|
||||||
} else {
|
|
||||||
return $unary . $func;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} elseif ($tokens->is(T_ISSET, T_EMPTY)) {
|
} elseif ($tokens->is(T_ISSET, T_EMPTY)) {
|
||||||
$func = $tokens->getAndNext();
|
$func = $tokens->getAndNext();
|
||||||
if ($tokens->is("(") && $tokens->isNext(T_VARIABLE)) {
|
if ($tokens->is("(") && $tokens->isNext(T_VARIABLE)) {
|
||||||
$tokens->next();
|
$code = $unary . $func . "(" . $this->parseVariable($tokens->next()) . ")";
|
||||||
$exp = $func . "(" . $this->parseVar($tokens) . ")";
|
|
||||||
$tokens->need(')')->next();
|
$tokens->need(')')->next();
|
||||||
return $unary . $exp;
|
|
||||||
} else {
|
} else {
|
||||||
throw new TokenizeException("Unexpected token " . $tokens->getNext() . ", isset() and empty() accept only variables");
|
throw new TokenizeException("Unexpected token " . $tokens->getNext() . ", isset() and empty() accept only variables");
|
||||||
}
|
}
|
||||||
@ -765,43 +758,29 @@ class Template extends Render
|
|||||||
if ($unary) {
|
if ($unary) {
|
||||||
throw new UnexpectedTokenException($tokens->back());
|
throw new UnexpectedTokenException($tokens->back());
|
||||||
}
|
}
|
||||||
return $this->parseArray($tokens);
|
$code = $this->parseArray($tokens);
|
||||||
} elseif ($unary) {
|
} elseif ($unary) {
|
||||||
$tokens->back();
|
throw new UnexpectedTokenException($tokens->back());
|
||||||
throw new UnexpectedTokenException($tokens);
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $code;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse simple variable (without modifier etc)
|
* Parse variable name: $a, $a.b, $a.b[c]
|
||||||
*
|
|
||||||
* @param Tokenizer $tokens
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function parseVar(Tokenizer $tokens)
|
|
||||||
{
|
|
||||||
$var = $tokens->get(T_VARIABLE);
|
|
||||||
$_var = '$tpl["' . substr($var, 1) . '"]';
|
|
||||||
$tokens->next();
|
|
||||||
$_var = $this->_var($tokens, $_var);
|
|
||||||
if ($this->_options & Fenom::FORCE_VERIFY) {
|
|
||||||
return 'isset(' . $_var . ') ? ' . $_var . ' : null';
|
|
||||||
} else {
|
|
||||||
return $_var;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param $var
|
* @param $var
|
||||||
* @return string
|
* @return string
|
||||||
* @throws Error\UnexpectedTokenException
|
* @throws Error\UnexpectedTokenException
|
||||||
*/
|
*/
|
||||||
protected function _var(Tokenizer $tokens, $var)
|
public function parseVariable(Tokenizer $tokens, $var = null)
|
||||||
{
|
{
|
||||||
|
if(!$var) {
|
||||||
|
$var = '$tpl["' . substr( $tokens->get(T_VARIABLE), 1) . '"]';
|
||||||
|
$tokens->next();
|
||||||
|
}
|
||||||
while ($t = $tokens->key()) {
|
while ($t = $tokens->key()) {
|
||||||
if ($t === ".") {
|
if ($t === ".") {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
@ -844,62 +823,6 @@ class Template extends Render
|
|||||||
return $var;
|
return $var;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse complex variable
|
|
||||||
* $var.foo[bar]["a"][1+3/$var]|mod:3:"w":$var3|mod3
|
|
||||||
* ++$var|mod
|
|
||||||
* $var--|mod
|
|
||||||
*
|
|
||||||
* @see parseModifier
|
|
||||||
* @static
|
|
||||||
* @param Tokenizer $tokens
|
|
||||||
* @param int $options set parser options
|
|
||||||
* @param string $var already parsed plain variable
|
|
||||||
* @throws \LogicException
|
|
||||||
* @throws InvalidUsageException
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function parseVariable(Tokenizer $tokens, $options = 0, $var = null)
|
|
||||||
{
|
|
||||||
$stained = false;
|
|
||||||
if (!$var) {
|
|
||||||
if ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
|
||||||
$stained = true;
|
|
||||||
$var = $tokens->getAndNext() . $this->parseVar($tokens, $options);
|
|
||||||
} else {
|
|
||||||
$var = $this->parseVar($tokens, $options);
|
|
||||||
}
|
|
||||||
if ($tokens->is(T_OBJECT_OPERATOR)) { // parse
|
|
||||||
$var .= '->' . $tokens->getNext(T_STRING);
|
|
||||||
$tokens->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($tokens->is("(") && $tokens->hasBackList(T_STRING, T_OBJECT_OPERATOR)) {
|
|
||||||
if ($stained) {
|
|
||||||
throw new InvalidUsageException("Can not increment or decrement of the method result");
|
|
||||||
}
|
|
||||||
if ($this->_options & Fenom::DENY_METHODS) {
|
|
||||||
throw new \LogicException("Forbidden to call methods");
|
|
||||||
}
|
|
||||||
$var .= $this->parseArgs($tokens);
|
|
||||||
$stained = true;
|
|
||||||
}
|
|
||||||
if ($tokens->is('?', '!')) {
|
|
||||||
return $this->parseTernary($tokens, $var, $tokens->current());
|
|
||||||
}
|
|
||||||
if ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
|
||||||
if ($stained) {
|
|
||||||
throw new InvalidUsageException("Can not use two increments and/or decrements for one variable");
|
|
||||||
}
|
|
||||||
$var .= $tokens->getAndNext();
|
|
||||||
}
|
|
||||||
if ($tokens->is('|') && !($options & self::DENY_MODS)) {
|
|
||||||
return $this->parseModifier($tokens, $var);
|
|
||||||
}
|
|
||||||
return $var;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse accessor
|
* Parse accessor
|
||||||
*/
|
*/
|
||||||
@ -907,16 +830,16 @@ class Template extends Render
|
|||||||
{
|
{
|
||||||
$is_var = false;
|
$is_var = false;
|
||||||
$vars = array(
|
$vars = array(
|
||||||
'get' => '$_GET',
|
'get' => '$_GET',
|
||||||
'post' => '$_POST',
|
'post' => '$_POST',
|
||||||
'session' => '$_SESSION',
|
'session' => '$_SESSION',
|
||||||
'cookie' => '$_COOKIE',
|
'cookie' => '$_COOKIE',
|
||||||
'request' => '$_REQUEST',
|
'request' => '$_REQUEST',
|
||||||
'files' => '$_FILES',
|
'files' => '$_FILES',
|
||||||
'globals' => '$GLOBALS',
|
'globals' => '$GLOBALS',
|
||||||
'server' => '$_SERVER',
|
'server' => '$_SERVER',
|
||||||
'env' => '$_ENV',
|
'env' => '$_ENV',
|
||||||
'tpl' => '$tpl->info'
|
'tpl' => '$tpl->info'
|
||||||
);
|
);
|
||||||
if ($this->_options & Fenom::DENY_ACCESSOR) {
|
if ($this->_options & Fenom::DENY_ACCESSOR) {
|
||||||
throw new \LogicException("Accessor are disabled");
|
throw new \LogicException("Accessor are disabled");
|
||||||
@ -925,7 +848,7 @@ class Template extends Render
|
|||||||
$tokens->next();
|
$tokens->next();
|
||||||
if (isset($vars[$key])) {
|
if (isset($vars[$key])) {
|
||||||
$is_var = true;
|
$is_var = true;
|
||||||
return $this->_var($tokens, $vars[$key]);
|
return $this->parseVariable($tokens, $vars[$key]);
|
||||||
}
|
}
|
||||||
switch ($key) {
|
switch ($key) {
|
||||||
case 'const':
|
case 'const':
|
||||||
@ -942,11 +865,7 @@ class Template extends Render
|
|||||||
throw new UnexpectedTokenException($tokens);
|
throw new UnexpectedTokenException($tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($tokens->is('|')) {
|
return $var;
|
||||||
return $this->parseModifier($tokens, $var);
|
|
||||||
} else {
|
|
||||||
return $var;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1021,12 +940,8 @@ class Template extends Render
|
|||||||
return '(' . $value . ' ' . $equal . '= ' . $action . ')';
|
return '(' . $value . ' ' . $equal . '= ' . $action . ')';
|
||||||
}
|
}
|
||||||
return $invert . '(' . $value . ' instanceof \\' . $this->parseName($tokens) . ')';
|
return $invert . '(' . $value . ' instanceof \\' . $this->parseName($tokens) . ')';
|
||||||
} elseif ($tokens->is(T_VARIABLE)) {
|
} elseif ($tokens->is(T_VARIABLE, '[', Tokenizer::MACRO_SCALAR, '"')) {
|
||||||
return '(' . $value . ' ' . $equal . '= ' . $this->parseVariable($tokens) . ')';
|
return '(' . $value . ' ' . $equal . '= ' . $this->parseTerm($tokens) . ')';
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR)) {
|
|
||||||
return '(' . $value . ' ' . $equal . '= ' . $this->parseScalar($tokens) . ')';
|
|
||||||
} elseif ($tokens->is('[')) {
|
|
||||||
return '(' . $value . ' ' . $equal . '= ' . $this->parseArray($tokens) . ')';
|
|
||||||
} elseif ($tokens->is(T_NS_SEPARATOR)) { //
|
} elseif ($tokens->is(T_NS_SEPARATOR)) { //
|
||||||
return $invert . '(' . $value . ' instanceof \\' . $this->parseName($tokens) . ')';
|
return $invert . '(' . $value . ' instanceof \\' . $this->parseName($tokens) . ')';
|
||||||
} else {
|
} else {
|
||||||
@ -1085,7 +1000,7 @@ class Template extends Render
|
|||||||
if (!$checker) {
|
if (!$checker) {
|
||||||
$checker = "auto";
|
$checker = "auto";
|
||||||
}
|
}
|
||||||
return $invert . sprintf($checkers[$checker], $value, $this->parseVariable($tokens));
|
return $invert . sprintf($checkers[$checker], $value, $this->parseTerm($tokens));
|
||||||
} else {
|
} else {
|
||||||
throw new UnexpectedTokenException($tokens);
|
throw new UnexpectedTokenException($tokens);
|
||||||
}
|
}
|
||||||
@ -1115,30 +1030,25 @@ class Template extends Render
|
|||||||
* Parse scalar values
|
* Parse scalar values
|
||||||
*
|
*
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param bool $allow_mods
|
* @throws Error\UnexpectedTokenException
|
||||||
* @return string
|
* @return string
|
||||||
* @throws TokenizeException
|
|
||||||
*/
|
*/
|
||||||
public function parseScalar(Tokenizer $tokens, $allow_mods = true)
|
public function parseScalar(Tokenizer $tokens)
|
||||||
{
|
{
|
||||||
$_scalar = "";
|
$_scalar = "";
|
||||||
if ($token = $tokens->key()) {
|
$token = $tokens->key();
|
||||||
switch ($token) {
|
switch ($token) {
|
||||||
case T_CONSTANT_ENCAPSED_STRING:
|
case T_CONSTANT_ENCAPSED_STRING:
|
||||||
case T_LNUMBER:
|
case T_LNUMBER:
|
||||||
case T_DNUMBER:
|
case T_DNUMBER:
|
||||||
$_scalar .= $tokens->getAndNext();
|
$_scalar .= $tokens->getAndNext();
|
||||||
break;
|
break;
|
||||||
case T_ENCAPSED_AND_WHITESPACE:
|
case T_ENCAPSED_AND_WHITESPACE:
|
||||||
case '"':
|
case '"':
|
||||||
$_scalar .= $this->parseQuote($tokens);
|
$_scalar .= $this->parseQuote($tokens);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new TokenizeException("Unexpected scalar token '" . $tokens->current() . "'");
|
throw new UnexpectedTokenException($tokens);
|
||||||
}
|
|
||||||
if ($allow_mods && $tokens->is("|")) {
|
|
||||||
return $this->parseModifier($tokens, $_scalar);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $_scalar;
|
return $_scalar;
|
||||||
}
|
}
|
||||||
@ -1152,7 +1062,7 @@ class Template extends Render
|
|||||||
*/
|
*/
|
||||||
public function parseQuote(Tokenizer $tokens)
|
public function parseQuote(Tokenizer $tokens)
|
||||||
{
|
{
|
||||||
if ($tokens->is('"', "`")) {
|
if ($tokens->is('"')) {
|
||||||
$stop = $tokens->current();
|
$stop = $tokens->current();
|
||||||
$_str = '"';
|
$_str = '"';
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
@ -1208,17 +1118,6 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Tokenizer $tokens
|
|
||||||
* @param null $first_member
|
|
||||||
*/
|
|
||||||
public function parseConcat(Tokenizer $tokens, $first_member = null)
|
|
||||||
{
|
|
||||||
$concat = array();
|
|
||||||
if ($first_member) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse modifiers
|
* Parse modifiers
|
||||||
* |modifier:1:2.3:'string':false:$var:(4+5*$var3)|modifier2:"str {$var+3} ing":$arr.item
|
* |modifier:1:2.3:'string':false:$var:(4+5*$var3)|modifier2:"str {$var+3} ing":$arr.item
|
||||||
@ -1240,25 +1139,8 @@ class Template extends Render
|
|||||||
$args = array();
|
$args = array();
|
||||||
|
|
||||||
while ($tokens->is(":")) {
|
while ($tokens->is(":")) {
|
||||||
$token = $tokens->getNext(Tokenizer::MACRO_SCALAR, T_VARIABLE, '"', Tokenizer::MACRO_STRING, "(", "[", '$');
|
if (!$args[] = $this->parseTerm($tokens->next())) {
|
||||||
|
throw new UnexpectedTokenException($tokens);
|
||||||
if ($tokens->is(Tokenizer::MACRO_SCALAR) || $tokens->isSpecialVal()) {
|
|
||||||
$args[] = $token;
|
|
||||||
$tokens->next();
|
|
||||||
} elseif ($tokens->is(T_VARIABLE)) {
|
|
||||||
$args[] = $this->parseVariable($tokens, self::DENY_MODS);
|
|
||||||
} elseif ($tokens->is('$')) {
|
|
||||||
$args[] = $this->parseAccessor($tokens, $is_var);
|
|
||||||
} elseif ($tokens->is('"', '`', T_ENCAPSED_AND_WHITESPACE)) {
|
|
||||||
$args[] = $this->parseQuote($tokens);
|
|
||||||
} elseif ($tokens->is('(')) {
|
|
||||||
$args[] = $this->parseExpr($tokens);
|
|
||||||
} elseif ($tokens->is('[')) {
|
|
||||||
$args[] = $this->parseArray($tokens);
|
|
||||||
} elseif ($tokens->is(T_STRING) && $tokens->isNext('(')) {
|
|
||||||
$args[] = $tokens->getAndNext() . $this->parseArgs($tokens);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1358,14 +1240,14 @@ class Template extends Render
|
|||||||
throw new InvalidUsageException("Macro '$name' require '$arg' argument");
|
throw new InvalidUsageException("Macro '$name' require '$arg' argument");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$n = $this->i++;
|
$n = sprintf('%u_%d', crc32($this->_name), $this->i++);
|
||||||
if ($recursive) {
|
if ($recursive) {
|
||||||
$recursive['recursive'] = true;
|
$recursive['recursive'] = true;
|
||||||
$body = '$tpl->getMacro("' . $name . '")->__invoke($tpl);';
|
$body = '$tpl->getMacro("' . $name . '")->__invoke($tpl);';
|
||||||
} else {
|
} else {
|
||||||
$body = '?>' . $macro["body"] . '<?php';
|
$body = '?>' . $macro["body"] . '<?php';
|
||||||
}
|
}
|
||||||
return '$_tpl' . $n . ' = $tpl->exchangeArray(' . Compiler::toArray($args) . ');' . PHP_EOL . $body . PHP_EOL . '$tpl->exchangeArray($_tpl' . $n . '); unset($_tpl' . $n . ');';
|
return '$_tpl' . $n . ' = $tpl->exchangeArray(' . Compiler::toArray($args) . ');' . PHP_EOL . $body . PHP_EOL . '$tpl->exchangeArray($_tpl' . $n . '); /* X */ unset($_tpl' . $n . ');';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1457,7 +1339,7 @@ class Template extends Render
|
|||||||
} else {
|
} else {
|
||||||
$params[$key] = 'true';
|
$params[$key] = 'true';
|
||||||
}
|
}
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR, '"', '`', T_VARIABLE, "[", '(')) {
|
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR, '"', T_VARIABLE, "[", '(')) {
|
||||||
$params[] = $this->parseExpr($tokens);
|
$params[] = $this->parseExpr($tokens);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -104,8 +104,8 @@ class Tokenizer
|
|||||||
\T_LOGICAL_AND => 1, \T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_METHOD_C => 1, \T_NAMESPACE => 1, \T_NS_C => 1,
|
\T_LOGICAL_AND => 1, \T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_METHOD_C => 1, \T_NAMESPACE => 1, \T_NS_C => 1,
|
||||||
\T_NEW => 1, \T_PRINT => 1, \T_PRIVATE => 1, \T_PUBLIC => 1, \T_PROTECTED => 1, \T_REQUIRE => 1,
|
\T_NEW => 1, \T_PRINT => 1, \T_PRIVATE => 1, \T_PUBLIC => 1, \T_PROTECTED => 1, \T_REQUIRE => 1,
|
||||||
\T_REQUIRE_ONCE => 1, \T_RETURN => 1, \T_RETURN => 1, \T_STRING => 1, \T_SWITCH => 1, \T_THROW => 1,
|
\T_REQUIRE_ONCE => 1, \T_RETURN => 1, \T_RETURN => 1, \T_STRING => 1, \T_SWITCH => 1, \T_THROW => 1,
|
||||||
\T_TRAIT => 1, \T_TRAIT_C => 1, \T_TRY => 1, \T_UNSET => 1, \T_VAR => 1,
|
\T_TRAIT => 1, \T_TRAIT_C => 1, \T_TRY => 1, \T_UNSET => 1, \T_USE => 1, \T_VAR => 1,
|
||||||
\T_WHILE => 1, \T_YIELD => 1, \T_USE => 1
|
\T_WHILE => 1, \T_YIELD => 1
|
||||||
),
|
),
|
||||||
self::MACRO_INCDEC => array(
|
self::MACRO_INCDEC => array(
|
||||||
\T_INC => 1, \T_DEC => 1
|
\T_INC => 1, \T_DEC => 1
|
||||||
@ -130,9 +130,10 @@ class Tokenizer
|
|||||||
\T_IS_NOT_EQUAL => 1, \T_IS_NOT_IDENTICAL => 1, \T_IS_SMALLER_OR_EQUAL => 1,
|
\T_IS_NOT_EQUAL => 1, \T_IS_NOT_IDENTICAL => 1, \T_IS_SMALLER_OR_EQUAL => 1,
|
||||||
),
|
),
|
||||||
self::MACRO_EQUALS => array(
|
self::MACRO_EQUALS => array(
|
||||||
\T_AND_EQUAL => 1, \T_CONCAT_EQUAL => 1, \T_DIV_EQUAL => 1, \T_MINUS_EQUAL => 1, \T_MOD_EQUAL => 1,
|
\T_AND_EQUAL => 1, \T_DIV_EQUAL => 1, \T_MINUS_EQUAL => 1, \T_MOD_EQUAL => 1,
|
||||||
\T_MUL_EQUAL => 1, \T_OR_EQUAL => 1, \T_PLUS_EQUAL => 1, \T_SL_EQUAL => 1, \T_SR_EQUAL => 1,
|
\T_MUL_EQUAL => 1, \T_OR_EQUAL => 1, \T_PLUS_EQUAL => 1, \T_SL_EQUAL => 1, \T_SR_EQUAL => 1,
|
||||||
\T_XOR_EQUAL => 1, '=' => 1
|
\T_XOR_EQUAL => 1, '=' => 1,
|
||||||
|
// \T_CONCAT_EQUAL => 1,
|
||||||
),
|
),
|
||||||
self::MACRO_SCALAR => array(
|
self::MACRO_SCALAR => array(
|
||||||
\T_LNUMBER => 1, \T_DNUMBER => 1, \T_CONSTANT_ENCAPSED_STRING => 1
|
\T_LNUMBER => 1, \T_DNUMBER => 1, \T_CONSTANT_ENCAPSED_STRING => 1
|
||||||
|
@ -137,6 +137,7 @@ class TemplateTest extends TestCase
|
|||||||
array('Mod: {$date|date:"Y m d"}!', $b, 'Mod: 2012 07 26!'),
|
array('Mod: {$date|date:"Y m d"}!', $b, 'Mod: 2012 07 26!'),
|
||||||
array('Mod: {$tags|strip_tags}!', $b, 'Mod: my name is Legion!'),
|
array('Mod: {$tags|strip_tags}!', $b, 'Mod: my name is Legion!'),
|
||||||
array('Mod: {$b.c|json_encode}!', $b, 'Mod: "Username"!'),
|
array('Mod: {$b.c|json_encode}!', $b, 'Mod: "Username"!'),
|
||||||
|
array('Mod: {($time/1024/1024)|round:2}!', $b, 'Mod: 1281.09!'),
|
||||||
array('Mod: {time()|date:"Y m d"}!', $b, 'Mod: ' . date("Y m d") . '!'),
|
array('Mod: {time()|date:"Y m d"}!', $b, 'Mod: ' . date("Y m d") . '!'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -341,7 +342,7 @@ class TemplateTest extends TestCase
|
|||||||
array('Create: {var $v = 1++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
array('Create: {var $v = 1++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
||||||
array('Create: {var $v = c} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token 'c'"),
|
array('Create: {var $v = c} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token 'c'"),
|
||||||
array('Create: {var $v = ($a)++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
array('Create: {var $v = ($a)++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
||||||
array('Create: {var $v = --$a++} Result: {$v} end', 'Fenom\Error\CompileException', "Can not use two increments and/or decrements for one variable"),
|
array('Create: {var $v = --$a++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
||||||
array('Create: {var $v = $a|upper++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
array('Create: {var $v = $a|upper++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
||||||
array('Create: {var $v = max($a,2)++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
array('Create: {var $v = max($a,2)++} Result: {$v} end', 'Fenom\Error\CompileException', "Unexpected token '++'"),
|
||||||
array('Create: {var $v = max($a,2)} Result: {$v} end', 'Fenom\Error\CompileException', "Function max not found", Fenom::DENY_NATIVE_FUNCS),
|
array('Create: {var $v = max($a,2)} Result: {$v} end', 'Fenom\Error\CompileException', "Function max not found", Fenom::DENY_NATIVE_FUNCS),
|
||||||
@ -494,37 +495,40 @@ class TemplateTest extends TestCase
|
|||||||
public static function providerSwitch()
|
public static function providerSwitch()
|
||||||
{
|
{
|
||||||
$code1 = 'Switch: {switch $a}
|
$code1 = 'Switch: {switch $a}
|
||||||
{case 1} one {break}
|
{case 1, "one"} one
|
||||||
{case 2} two {break}
|
{case 2, "two"} two
|
||||||
{case "string"} str {break}
|
{case "string"} str
|
||||||
{default} def
|
{default} def
|
||||||
{/switch} end';
|
{/switch} end';
|
||||||
|
|
||||||
$code2 = 'Switch: {switch $a}
|
$code2 = 'Switch: {switch $a}
|
||||||
{case 1} one {break}
|
{case 1, "one"} one
|
||||||
{case 2} two {break}
|
{case 2, "two"} two
|
||||||
{case "string"} str {break}
|
{case "string"} str
|
||||||
{/switch} end';
|
{/switch} end';
|
||||||
|
|
||||||
$code3 = 'Switch: {switch $a} invalid
|
$code3 = 'Switch: {switch $a} invalid
|
||||||
{case 1} one {break}
|
{case 1, "one"} one
|
||||||
{/switch} end';
|
{/switch} end';
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
array($code1, array("a" => 1), 'Switch: one end'),
|
array($code1, array("a" => 1), 'Switch: one end'),
|
||||||
|
array($code1, array("a" => 'one'), 'Switch: one end'),
|
||||||
array($code1, array("a" => 2), 'Switch: two end'),
|
array($code1, array("a" => 2), 'Switch: two end'),
|
||||||
|
array($code1, array("a" => 'two'), 'Switch: two end'),
|
||||||
array($code1, array("a" => "string"), 'Switch: str end'),
|
array($code1, array("a" => "string"), 'Switch: str end'),
|
||||||
array($code2, array("a" => "unk"), 'Switch: end'),
|
array($code2, array("a" => "unk"), 'Switch: end'),
|
||||||
array($code3, array("a" => 1), 'Switch: invalid one end'),
|
array($code3, array("a" => 1), 'Switch: one end'),
|
||||||
|
array($code3, array("a" => 'one'), 'Switch: one end'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function providerSwitchInvalid()
|
public static function providerSwitchInvalid()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array('Switch: {switch}{case 1} one {break}{/switch} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
array('Switch: {switch}{case 1} one {/switch} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
||||||
array('Switch: {switch 1}{case} one {break}{/switch} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
array('Switch: {switch 1}{case} one{/switch} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
||||||
array('Switch: {switch 1}{break}{case} one {/switch} end', 'Fenom\Error\CompileException', "Improper usage of the tag {break}"),
|
array('Switch: {switch 1}{case $var} one {/switch} end', 'Fenom\Error\CompileException', "Unexpected token '\$var' in expression"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,7 +579,7 @@ class TemplateTest extends TestCase
|
|||||||
array('For: {for} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
array('For: {for} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
||||||
array('For: {for $a=} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
array('For: {for $a=} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected end of expression"),
|
||||||
array('For: {for $a+1=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token '+'"),
|
array('For: {for $a+1=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token '+'"),
|
||||||
array('For: {for max($a,$b)=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'max'"),
|
array('For: {for max($a,$b)=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token '='"),
|
||||||
array('For: {for to=6 $a=3} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'to'"),
|
array('For: {for to=6 $a=3} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'to'"),
|
||||||
array('For: {for index=$i $a=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'index'"),
|
array('For: {for index=$i $a=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'index'"),
|
||||||
array('For: {for first=$i $a=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'first'"),
|
array('For: {for first=$i $a=3 to=6} block1 {/for} end', 'Fenom\Error\CompileException', "Unexpected token 'first'"),
|
||||||
@ -719,7 +723,7 @@ class TemplateTest extends TestCase
|
|||||||
public function _testSandbox()
|
public function _testSandbox()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
var_dump($this->fenom->compileCode('{"string"|append:$.get.one}')->getBody());
|
var_dump($this->fenom->setOptions(Fenom::FORCE_VERIFY)->compileCode('{if $unexist} block1 {else} block2 {/if}')->getBody());
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
||||||
}
|
}
|
||||||
@ -875,6 +879,7 @@ class TemplateTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @group switch
|
||||||
* @dataProvider providerSwitch
|
* @dataProvider providerSwitch
|
||||||
*/
|
*/
|
||||||
public function testSwitch($code, $vars, $result)
|
public function testSwitch($code, $vars, $result)
|
||||||
@ -883,6 +888,7 @@ class TemplateTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @group switch-bad
|
||||||
* @dataProvider providerSwitchInvalid
|
* @dataProvider providerSwitchInvalid
|
||||||
*/
|
*/
|
||||||
public function testSwitchInvalid($code, $exception, $message, $options = 0)
|
public function testSwitchInvalid($code, $exception, $message, $options = 0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user