mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
commit
3a1da1c154
54
CHANGELOG.md
54
CHANGELOG.md
@ -1,6 +1,60 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
## 2.6.0 (2015-02-22)
|
||||||
|
|
||||||
|
- Add range operator (`1..3`)
|
||||||
|
- Tag `for` now is deprecated, use tag `foreach` with range
|
||||||
|
- Internal improves
|
||||||
|
|
||||||
|
### 2.5.4 (2015-02-19)
|
||||||
|
|
||||||
|
- Fix bug #152
|
||||||
|
- Add composer.lock to git
|
||||||
|
|
||||||
|
### 2.5.3 (2015-02-19)
|
||||||
|
|
||||||
|
- Fix bug #147
|
||||||
|
|
||||||
|
### 2.5.2 (2015-02-10)
|
||||||
|
|
||||||
|
- Fix bug: unexpected array conversion when object given to {foreach} with force verify option (pull #148)
|
||||||
|
|
||||||
|
### 2.5.1 (2015-02-10)
|
||||||
|
|
||||||
|
- Fix bugs #144, #135
|
||||||
|
|
||||||
|
|
||||||
|
## 2.5.0 (2015-02-01)
|
||||||
|
|
||||||
|
- Internal improvement: functions accept array of template variables
|
||||||
|
- Improve `in` operator
|
||||||
|
- Fix bug #142
|
||||||
|
|
||||||
|
### 2.4.6 (2015-01-30)
|
||||||
|
|
||||||
|
- Fix bug #138
|
||||||
|
|
||||||
|
### 2.4.5 (2015-01-30)
|
||||||
|
|
||||||
|
Move project to organization `fenom-template`
|
||||||
|
|
||||||
|
### 2.4.4 (2015-01-22)
|
||||||
|
|
||||||
|
- Fix: parse error then modifier's argument converts to false
|
||||||
|
|
||||||
|
### 2.4.3 (2015-01-08)
|
||||||
|
|
||||||
|
- Fix #132
|
||||||
|
|
||||||
|
### 2.4.2 (2015-01-07)
|
||||||
|
|
||||||
|
- Internal improvements and code cleaning
|
||||||
|
|
||||||
|
### 2.4.2 (2015-01-07)
|
||||||
|
|
||||||
|
- Fix bug #128
|
||||||
|
|
||||||
## 2.4.0 (2015-01-02)
|
## 2.4.0 (2015-01-02)
|
||||||
|
|
||||||
- Fix bugs #120, #104, #119
|
- Fix bugs #120, #104, #119
|
||||||
|
@ -112,7 +112,7 @@
|
|||||||
|
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{var $b |= $flags}
|
{set $b |= $flags}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Операторы инкремента и декремента
|
### Операторы инкремента и декремента
|
||||||
@ -135,6 +135,39 @@ Fenom поддерживает префиксные и постфиксные о
|
|||||||
* `$a ~~ $b` - возвращает результат объединения сток `$a` и `$b` через пробел
|
* `$a ~~ $b` - возвращает результат объединения сток `$a` и `$b` через пробел
|
||||||
* `$a ~= $b` - присвоение с объединением
|
* `$a ~= $b` - присвоение с объединением
|
||||||
|
|
||||||
|
### Оператор интервала
|
||||||
|
|
||||||
|
Оператор `..` позволяет создать массив данных, не выходящие за указанные ограничения.
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $a = 1..4}
|
||||||
|
```
|
||||||
|
|
||||||
|
создаст массив `[1,2,3,4]`
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $a = 'a'..'f'}
|
||||||
|
```
|
||||||
|
|
||||||
|
создаст массив `['a','b','c','d','e','f']`
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $a = 'a'|up..'f'|up}
|
||||||
|
```
|
||||||
|
|
||||||
|
создаст массив `['A','B','C','D','E','F']`
|
||||||
|
|
||||||
|
```smarty
|
||||||
|
{set $a = $min..$max}
|
||||||
|
```
|
||||||
|
|
||||||
|
создаст массив из значений где первый и минимальный элемент будет значение `$min`,
|
||||||
|
а максимальный и последний элемент будет занчение `$max`
|
||||||
|
|
||||||
|
**Замечание:**
|
||||||
|
оганичения должны быть одного типа, интервал `1..'f'` преобразует `f` в `0` и будет сгенерировано `[1,0]`
|
||||||
|
|
||||||
|
|
||||||
### Тернарные операторы
|
### Тернарные операторы
|
||||||
|
|
||||||
Еще одним условным оператором являются тернарные операторы `?:` и `!:`.
|
Еще одним условным оператором являются тернарные операторы `?:` и `!:`.
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
Тег {foreach}
|
Тег {foreach}
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Тег `foreach` предоставляет простой способ перебора массивов.
|
Тег `foreach` предоставляет простой способ перебора массивов.
|
||||||
|
`Foreach` работает только с массивами, объектами и интервалами.
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{foreach $list as [$key =>] $value [index=$index] [first=$first] [last=$last]}
|
{foreach $list as [$key =>] $value [index=$index] [first=$first] [last=$last]}
|
||||||
@ -17,15 +18,19 @@
|
|||||||
|
|
||||||
### {foreach}
|
### {foreach}
|
||||||
|
|
||||||
Перебор значений массива $list
|
Перебор значений массива $list:
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{foreach $list as $value}
|
{foreach $list as $value}
|
||||||
<div>{$value}</div>
|
<div>{$value}</div>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
|
|
||||||
|
{foreach 1..7 as $value} {* так же хорошо работает и с интрвелами *}
|
||||||
|
<div>№{$value}</div>
|
||||||
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
Перебор ключей и значений массива $list
|
Перебор ключей и значений массива $list:
|
||||||
|
|
||||||
```smarty
|
```smarty
|
||||||
{foreach $list as $key => $value}
|
{foreach $list as $key => $value}
|
||||||
@ -60,13 +65,19 @@
|
|||||||
|
|
||||||
Переменная `$last` будет иметь значение **TRUE**, если текущая итерация является последней.
|
Переменная `$last` будет иметь значение **TRUE**, если текущая итерация является последней.
|
||||||
|
|
||||||
|
**Замечание:**
|
||||||
|
Использование `last` требует от `$list` быть **countable**.
|
||||||
|
|
||||||
### {break}
|
### {break}
|
||||||
|
|
||||||
Тег `{break}` используется для выхода из цикла до достижения последней итерации. Если в цикле встречается тег `{break}`, цикл завершает свою работу, и далее, выполняется код, следующий сразу за блоком цикла
|
Тег `{break}` используется для выхода из цикла до достижения последней итерации.
|
||||||
|
Если в цикле встречается тег `{break}`, цикл завершает свою работу, и далее, выполняется код, следующий сразу за блоком цикла
|
||||||
|
|
||||||
### {continue}
|
### {continue}
|
||||||
|
|
||||||
Тег `{continue}` используется для прерывания текущей итерации. Если в цикле встречается тег `{continue}`, часть цикла, следующая после тега, не выполняется, и начинается следующая итерация. Если текущая итерация была последней, цикл завершается.
|
Тег `{continue}` используется для прерывания текущей итерации.
|
||||||
|
Если в цикле встречается тег `{continue}`, часть цикла, следующая после тега, не выполняется, и начинается следующая итерация.
|
||||||
|
Если текущая итерация была последней, цикл завершается.
|
||||||
|
|
||||||
### {foreachelse}
|
### {foreachelse}
|
||||||
|
|
||||||
@ -81,7 +92,4 @@
|
|||||||
{/foreach}
|
{/foreach}
|
||||||
```
|
```
|
||||||
|
|
||||||
В блоке `{foreachelse}...{/foreach}` использование `{break}`, `{continue}` выбросит исключение `Fenom\CompileException` при компиляции
|
В блоке `{foreachelse}...{/foreach}` использование `{break}`, `{continue}` выбросит исключение `Fenom\CompileException` при компиляции
|
||||||
|
|
||||||
**Замечание:**
|
|
||||||
Использование last требует от `$list` быть **countable**.
|
|
@ -7,6 +7,6 @@ require_once __DIR__.'/../tests/tools.php';
|
|||||||
|
|
||||||
$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled');
|
$fenom = Fenom::factory(__DIR__.'/templates', __DIR__.'/compiled');
|
||||||
$fenom->setOptions(Fenom::AUTO_RELOAD);
|
$fenom->setOptions(Fenom::AUTO_RELOAD);
|
||||||
var_dump($fenom->compile("blocks/second.tpl", false)->getBody());
|
var_dump($fenom->compileCode('{$b == 5 ? "5" : "?"}')->getBody());
|
||||||
//$fenom->display("blocks/second.tpl", []);
|
//$fenom->display("blocks/second.tpl", []);
|
||||||
// $fenom->getTemplate("problem.tpl");
|
// $fenom->getTemplate("problem.tpl");
|
@ -136,21 +136,20 @@ class Compiler
|
|||||||
$key = null;
|
$key = null;
|
||||||
$before = $body = array();
|
$before = $body = array();
|
||||||
$prepend = "";
|
$prepend = "";
|
||||||
if ($tokens->is(T_VARIABLE)) {
|
if ($tokens->is('[')) {
|
||||||
$from = $scope->tpl->parseTerm($tokens, $is_var);
|
|
||||||
if($is_var) {
|
|
||||||
$check = '!empty('.$from.')';
|
|
||||||
} else {
|
|
||||||
$scope["var"] = $scope->tpl->tmpVar();
|
|
||||||
$prepend = $scope["var"].' = '.$from.';';
|
|
||||||
$from = $check = $scope["var"];
|
|
||||||
}
|
|
||||||
} elseif ($tokens->is('[')) {
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
$from = $scope->tpl->parseArray($tokens, $count);
|
$from = $scope->tpl->parseArray($tokens, $count);
|
||||||
$check = $count;
|
$check = $count;
|
||||||
} else {
|
} else {
|
||||||
throw new UnexpectedTokenException($tokens, null, "tag {foreach}");
|
$from = $scope->tpl->parseExpr($tokens, $is_var);
|
||||||
|
if($is_var) {
|
||||||
|
$check = '!empty('.$from.') && (is_array('.$from.') || '.$from.' instanceof \Traversable)';
|
||||||
|
} else {
|
||||||
|
$scope["var"] = $scope->tpl->tmpVar();
|
||||||
|
$prepend = $scope["var"].' = '.$from.';';
|
||||||
|
$from = $scope["var"];
|
||||||
|
$check = 'is_array('.$from.') && count('.$from.') || ('.$from.' instanceof \Traversable)';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$tokens->get(T_AS);
|
$tokens->get(T_AS);
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
@ -193,9 +192,9 @@ class Compiler
|
|||||||
$body = $body ? implode("; ", $body) . ";" : "";
|
$body = $body ? implode("; ", $body) . ";" : "";
|
||||||
$scope["after"] = $scope["after"] ? implode("; ", $scope["after"]) . ";" : "";
|
$scope["after"] = $scope["after"] ? implode("; ", $scope["after"]) . ";" : "";
|
||||||
if ($key) {
|
if ($key) {
|
||||||
return "$prepend if($check) { $before foreach($from as $key => $value) { $body";
|
return "$prepend if($check) {\n $before foreach($from as $key => $value) { $body";
|
||||||
} else {
|
} else {
|
||||||
return "$prepend if($check) { $before foreach($from as $value) { $body";
|
return "$prepend if($check) {\n $before foreach($from as $value) { $body";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,9 +235,11 @@ class Compiler
|
|||||||
* @throws Error\UnexpectedTokenException
|
* @throws Error\UnexpectedTokenException
|
||||||
* @throws Error\InvalidUsageException
|
* @throws Error\InvalidUsageException
|
||||||
* @return string
|
* @return string
|
||||||
|
* @codeCoverageIgnore
|
||||||
*/
|
*/
|
||||||
public static function forOpen(Tokenizer $tokens, Tag $scope)
|
public static function forOpen(Tokenizer $tokens, Tag $scope)
|
||||||
{
|
{
|
||||||
|
trigger_error("Fenom: tag {for} deprecated, use {foreach 1..4 as \$value} (in {$scope->tpl->getName()}:{$scope->line})", E_USER_DEPRECATED);
|
||||||
$p = array(
|
$p = array(
|
||||||
"index" => false,
|
"index" => false,
|
||||||
"first" => false,
|
"first" => false,
|
||||||
@ -309,6 +310,7 @@ class Compiler
|
|||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param Tag $scope
|
* @param Tag $scope
|
||||||
* @return string
|
* @return string
|
||||||
|
* @codeCoverageIgnore
|
||||||
*/
|
*/
|
||||||
public static function forElse($tokens, Tag $scope)
|
public static function forElse($tokens, Tag $scope)
|
||||||
{
|
{
|
||||||
@ -322,6 +324,7 @@ class Compiler
|
|||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param Tag $scope
|
* @param Tag $scope
|
||||||
* @return string
|
* @return string
|
||||||
|
* @codeCoverageIgnore
|
||||||
*/
|
*/
|
||||||
public static function forClose($tokens, Tag $scope)
|
public static function forClose($tokens, Tag $scope)
|
||||||
{
|
{
|
||||||
|
@ -279,4 +279,15 @@ class Modifier
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|int $from
|
||||||
|
* @param string|int $to
|
||||||
|
* @param int $step
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function range($from, $to, $step = 1) {
|
||||||
|
$v = range($from, $to, $step);
|
||||||
|
return $v ? $v : array();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,14 @@ class Template extends Render
|
|||||||
* Disable modifier parser.
|
* Disable modifier parser.
|
||||||
*/
|
*/
|
||||||
const DENY_MODS = 2;
|
const DENY_MODS = 2;
|
||||||
|
/**
|
||||||
|
* Allow parse modifiers with term
|
||||||
|
*/
|
||||||
|
const TERM_MODS = 1;
|
||||||
|
/**
|
||||||
|
* Allow parse range with term
|
||||||
|
*/
|
||||||
|
const TERM_RANGE = 1;
|
||||||
/**
|
/**
|
||||||
* @var int shared counter
|
* @var int shared counter
|
||||||
*/
|
*/
|
||||||
@ -649,10 +657,11 @@ 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
|
||||||
|
* @param bool $is_var
|
||||||
|
* @throws \Exception
|
||||||
* @return string
|
* @return string
|
||||||
* @throws Error\UnexpectedTokenException
|
|
||||||
*/
|
*/
|
||||||
public function parseExpr(Tokenizer $tokens)
|
public function parseExpr(Tokenizer $tokens, &$is_var = false)
|
||||||
{
|
{
|
||||||
$exp = array();
|
$exp = array();
|
||||||
$var = false; // last term was: true - variable, false - mixed
|
$var = false; // last term was: true - variable, false - mixed
|
||||||
@ -660,12 +669,8 @@ class Template extends Render
|
|||||||
$cond = false; // was comparison operator
|
$cond = false; // was comparison operator
|
||||||
while ($tokens->valid()) {
|
while ($tokens->valid()) {
|
||||||
// parse term
|
// parse term
|
||||||
$term = $this->parseTerm($tokens, $var); // term of the expression
|
$term = $this->parseTerm($tokens, $var, -1); // term of the expression
|
||||||
if ($term !== false) {
|
if ($term !== false) {
|
||||||
if ($tokens->is('|')) {
|
|
||||||
$term = $this->parseModifier($tokens, $term);
|
|
||||||
$var = false;
|
|
||||||
}
|
|
||||||
if ($tokens->is('?', '!')) {
|
if ($tokens->is('?', '!')) {
|
||||||
if($cond) {
|
if($cond) {
|
||||||
$term = array_pop($exp) . ' ' . $term;
|
$term = array_pop($exp) . ' ' . $term;
|
||||||
@ -718,7 +723,7 @@ class Template extends Render
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} elseif ($tokens->is('~')) { // string concatenation operator: 'asd' ~ $var
|
} elseif ($tokens->is('~')) { // string concatenation operator: 'asd' ~ $var
|
||||||
if($tokens->isNext('=')) { // ~=
|
if ($tokens->isNext('=')) { // ~=
|
||||||
$exp[] = ".=";
|
$exp[] = ".=";
|
||||||
$tokens->next()->next();
|
$tokens->next()->next();
|
||||||
} else {
|
} else {
|
||||||
@ -729,11 +734,11 @@ class Template extends Render
|
|||||||
if ($tokens->is(T_LNUMBER, T_DNUMBER)) {
|
if ($tokens->is(T_LNUMBER, T_DNUMBER)) {
|
||||||
$concat[] = "strval(" . $this->parseTerm($tokens) . ")";
|
$concat[] = "strval(" . $this->parseTerm($tokens) . ")";
|
||||||
} else {
|
} else {
|
||||||
if($tokens->is('~')) {
|
if ($tokens->is('~')) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$concat[] = " ";
|
$concat[] = " ";
|
||||||
}
|
}
|
||||||
if(!$concat[] = $this->parseTerm($tokens)) {
|
if (!$concat[] = $this->parseTerm($tokens)) {
|
||||||
throw new UnexpectedTokenException($tokens);
|
throw new UnexpectedTokenException($tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -751,6 +756,10 @@ class Template extends Render
|
|||||||
if ($op || !$exp) {
|
if ($op || !$exp) {
|
||||||
throw new UnexpectedTokenException($tokens);
|
throw new UnexpectedTokenException($tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(count($exp) == 1 && $var) {
|
||||||
|
$is_var = true;
|
||||||
|
}
|
||||||
return implode(' ', $exp);
|
return implode(' ', $exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -759,12 +768,11 @@ class Template extends Render
|
|||||||
*
|
*
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param bool $is_var is parsed term - plain variable
|
* @param bool $is_var is parsed term - plain variable
|
||||||
* @throws Error\UnexpectedTokenException
|
* @param int $allows
|
||||||
* @throws Error\TokenizeException
|
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
* @return bool|string
|
* @return bool|string
|
||||||
*/
|
*/
|
||||||
public function parseTerm(Tokenizer $tokens, &$is_var = false)
|
public function parseTerm(Tokenizer $tokens, &$is_var = false, $allows = -1)
|
||||||
{
|
{
|
||||||
$is_var = false;
|
$is_var = false;
|
||||||
if ($tokens->is(Tokenizer::MACRO_UNARY)) {
|
if ($tokens->is(Tokenizer::MACRO_UNARY)) {
|
||||||
@ -773,52 +781,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)) {
|
||||||
$code = $this->parseVariable($tokens);
|
$code = $this->parseVariable($tokens);
|
||||||
if ($tokens->is("(") && $tokens->hasBackList(T_STRING, T_OBJECT_OPERATOR)) {
|
if ($tokens->is("(") && $tokens->hasBackList(T_STRING, T_OBJECT_OPERATOR)) {
|
||||||
if ($this->_options & Fenom::DENY_METHODS) {
|
if ($this->_options & Fenom::DENY_METHODS) {
|
||||||
throw new \LogicException("Forbidden to call methods");
|
throw new \LogicException("Forbidden to call methods");
|
||||||
}
|
}
|
||||||
return $unary . $this->parseChain($tokens, $code);
|
$code = $unary . $this->parseChain($tokens, $code);
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
||||||
if($this->_options & Fenom::FORCE_VERIFY) {
|
if($this->_options & Fenom::FORCE_VERIFY) {
|
||||||
return $unary . '(isset(' . $code . ') ? ' . $code . $tokens->getAndNext() . ' : null)';
|
$code = $unary . '(isset(' . $code . ') ? ' . $code . $tokens->getAndNext() . ' : null)';
|
||||||
} else {
|
} else {
|
||||||
return $unary . $code . $tokens->getAndNext();
|
$code = $unary . $code . $tokens->getAndNext();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if($this->_options & Fenom::FORCE_VERIFY) {
|
if($this->_options & Fenom::FORCE_VERIFY) {
|
||||||
return $unary . '(isset(' . $code . ') ? ' . $code . ' : null)';
|
$code = $unary . '(isset(' . $code . ') ? ' . $code . ' : null)';
|
||||||
} else {
|
} else {
|
||||||
$is_var = true;
|
$is_var = true;
|
||||||
return $unary . $code;
|
$code = $unary . $code;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($tokens->is('$')) {
|
} elseif ($tokens->is('$')) {
|
||||||
$is_var = false;
|
$is_var = false;
|
||||||
$var = $this->parseAccessor($tokens);
|
$code = $unary . $this->parseAccessor($tokens);
|
||||||
return $unary . $var;
|
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
||||||
if($this->_options & Fenom::FORCE_VERIFY) {
|
if($this->_options & Fenom::FORCE_VERIFY) {
|
||||||
$var = $this->parseVariable($tokens);
|
$var = $this->parseVariable($tokens);
|
||||||
return $unary . '(isset(' . $var . ') ? ' . $tokens->getAndNext() . $this->parseVariable($tokens).' : null)';
|
$code = $unary . '(isset(' . $var . ') ? ' . $tokens->getAndNext() . $this->parseVariable($tokens).' : null)';
|
||||||
} else {
|
} else {
|
||||||
return $unary . $tokens->getAndNext() . $this->parseVariable($tokens);
|
$code = $unary . $tokens->getAndNext() . $this->parseVariable($tokens);
|
||||||
}
|
}
|
||||||
} elseif ($tokens->is("(")) {
|
} elseif ($tokens->is("(")) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$code = $unary . "(" . $this->parseExpr($tokens) . ")";
|
$code = $unary . "(" . $this->parseExpr($tokens) . ")";
|
||||||
$tokens->need(")")->next();
|
$tokens->need(")")->next();
|
||||||
return $code;
|
|
||||||
} 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($modifier = $tokens->current(), $this);
|
$func = $this->_fenom->getModifier($modifier = $tokens->current(), $this);
|
||||||
if (!$func) {
|
if (!$func) {
|
||||||
@ -829,11 +835,11 @@ class Template extends Render
|
|||||||
} else {
|
} else {
|
||||||
$call = $func . $this->parseArgs($tokens->next());
|
$call = $func . $this->parseArgs($tokens->next());
|
||||||
}
|
}
|
||||||
return $unary . $this->parseChain($tokens, $call);
|
$code = $unary . $this->parseChain($tokens, $call);
|
||||||
} elseif ($tokens->isNext(T_NS_SEPARATOR, T_DOUBLE_COLON)) {
|
} elseif ($tokens->isNext(T_NS_SEPARATOR, T_DOUBLE_COLON)) {
|
||||||
$method = $this->parseStatic($tokens);
|
$method = $this->parseStatic($tokens);
|
||||||
$args = $this->parseArgs($tokens);
|
$args = $this->parseArgs($tokens);
|
||||||
return $unary . $this->parseChain($tokens, $method . $args);
|
$code = $unary . $this->parseChain($tokens, $method . $args);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -842,7 +848,6 @@ class Template extends Render
|
|||||||
if ($tokens->is("(") && $tokens->isNext(T_VARIABLE)) {
|
if ($tokens->is("(") && $tokens->isNext(T_VARIABLE)) {
|
||||||
$code = $unary . $func . "(" . $this->parseVariable($tokens->next()) . ")";
|
$code = $unary . $func . "(" . $this->parseVariable($tokens->next()) . ")";
|
||||||
$tokens->need(')')->next();
|
$tokens->need(')')->next();
|
||||||
return $code;
|
|
||||||
} 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");
|
||||||
}
|
}
|
||||||
@ -850,12 +855,22 @@ 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) {
|
||||||
throw new UnexpectedTokenException($tokens->back());
|
throw new UnexpectedTokenException($tokens->back());
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (($allows & self::TERM_MODS) && $tokens->is('|')) {
|
||||||
|
$code = $this->parseModifier($tokens, $code);
|
||||||
|
$is_var = false;
|
||||||
|
}
|
||||||
|
if(($allows & self::TERM_RANGE) && $tokens->is('.') && $tokens->isNext('.')) {
|
||||||
|
$tokens->next()->next();
|
||||||
|
$code = 'range('.$code.', '.$this->parseTerm($tokens, $var, self::TERM_MODS).')';
|
||||||
|
$is_var = false;
|
||||||
|
}
|
||||||
|
return $code;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -901,6 +916,9 @@ class Template extends Render
|
|||||||
$key = "[" . $tokens->getAndNext() . "]";
|
$key = "[" . $tokens->getAndNext() . "]";
|
||||||
} elseif ($tokens->is('"')) {
|
} elseif ($tokens->is('"')) {
|
||||||
$key = "[" . $this->parseQuote($tokens) . "]";
|
$key = "[" . $this->parseQuote($tokens) . "]";
|
||||||
|
} elseif($tokens->is('.')) {
|
||||||
|
$tokens->back();
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
throw new UnexpectedTokenException($tokens);
|
throw new UnexpectedTokenException($tokens);
|
||||||
}
|
}
|
||||||
@ -1153,16 +1171,15 @@ class Template extends Render
|
|||||||
case T_LNUMBER:
|
case T_LNUMBER:
|
||||||
case T_DNUMBER:
|
case T_DNUMBER:
|
||||||
return $tokens->getAndNext();
|
return $tokens->getAndNext();
|
||||||
break;
|
|
||||||
case T_ENCAPSED_AND_WHITESPACE:
|
case T_ENCAPSED_AND_WHITESPACE:
|
||||||
case '"':
|
case '"':
|
||||||
return $this->parseQuote($tokens);
|
return $this->parseQuote($tokens);
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
throw new UnexpectedTokenException($tokens);
|
throw new UnexpectedTokenException($tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse string with or without variable
|
* Parse string with or without variable
|
||||||
*
|
*
|
||||||
@ -1254,7 +1271,7 @@ class Template extends Render
|
|||||||
|
|
||||||
$args = array();
|
$args = array();
|
||||||
while ($tokens->is(":")) {
|
while ($tokens->is(":")) {
|
||||||
if (($args[] = $this->parseTerm($tokens->next())) === false) {
|
if (($args[] = $this->parseTerm($tokens->next(), $is_var, 0)) === false) {
|
||||||
throw new UnexpectedTokenException($tokens);
|
throw new UnexpectedTokenException($tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,25 +186,48 @@ class Tokenizer
|
|||||||
if ($token === '"' || $token === "'" || $token === "`") {
|
if ($token === '"' || $token === "'" || $token === "`") {
|
||||||
$this->quotes++;
|
$this->quotes++;
|
||||||
}
|
}
|
||||||
$tokens[] = array(
|
$token = array(
|
||||||
$token,
|
$token,
|
||||||
$token,
|
$token,
|
||||||
"",
|
|
||||||
$line,
|
$line,
|
||||||
);
|
);
|
||||||
$i++;
|
|
||||||
} elseif ($token[0] === \T_WHITESPACE) {
|
} elseif ($token[0] === \T_WHITESPACE) {
|
||||||
$tokens[$i - 1][2] = $token[1];
|
$tokens[$i - 1][2] = $token[1];
|
||||||
} else {
|
continue;
|
||||||
$tokens[] = array(
|
} elseif ($token[0] === \T_DNUMBER) { // fix .1 and 1.
|
||||||
$token[0],
|
if(strpos($token[1], '.') === 0) {
|
||||||
$token[1],
|
$tokens[] = array(
|
||||||
"",
|
'.',
|
||||||
$line = $token[2],
|
'.',
|
||||||
token_name($token[0]) // debug
|
"",
|
||||||
);
|
$line = $token[2]
|
||||||
$i++;
|
);
|
||||||
|
$token = array(
|
||||||
|
T_LNUMBER,
|
||||||
|
ltrim($token[1], '.'),
|
||||||
|
$line = $token[2]
|
||||||
|
);
|
||||||
|
} elseif(strpos($token[1], '.') === strlen($token[1]) - 1) {
|
||||||
|
$tokens[] = array(
|
||||||
|
T_LNUMBER,
|
||||||
|
rtrim($token[1], '.'),
|
||||||
|
"",
|
||||||
|
$line = $token[2]
|
||||||
|
);
|
||||||
|
$token = array(
|
||||||
|
'.',
|
||||||
|
'.',
|
||||||
|
$line = $token[2]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
$tokens[] = array(
|
||||||
|
$token[0],
|
||||||
|
$token[1],
|
||||||
|
"",
|
||||||
|
$line = $token[2]
|
||||||
|
);
|
||||||
|
$i++;
|
||||||
|
|
||||||
}
|
}
|
||||||
unset($tokens[-1]);
|
unset($tokens[-1]);
|
||||||
|
@ -5,6 +5,9 @@ namespace Fenom;
|
|||||||
|
|
||||||
class SandboxTest extends TestCase {
|
class SandboxTest extends TestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group sb
|
||||||
|
*/
|
||||||
public function test()
|
public function test()
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -13,9 +16,9 @@ class SandboxTest extends TestCase {
|
|||||||
// return '<?php ' . $tag->cutContent();
|
// return '<?php ' . $tag->cutContent();
|
||||||
// });
|
// });
|
||||||
// $this->tpl('welcome.tpl', '{$a}');
|
// $this->tpl('welcome.tpl', '{$a}');
|
||||||
// $this->fenom->addModifier('min', function () {});
|
// var_dump($this->fenom->compileCode('{set $a=$one|min:0..$three|max:4}')->getBody());
|
||||||
// try {
|
// try {
|
||||||
// var_dump($this->fenom->compileCode('{time() + min(1, 10)}')->getBody());
|
// var_dump($this->fenom->compileCode('{foreach $a as $k => $v} {/foreach}')->getBody());
|
||||||
// } catch (\Exception $e) {
|
// } catch (\Exception $e) {
|
||||||
// print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
// print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
||||||
// while ($e->getPrevious()) {
|
// while ($e->getPrevious()) {
|
||||||
|
@ -8,17 +8,17 @@ class TagsTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @group test-for
|
* @group test-for
|
||||||
*/
|
*/
|
||||||
public function testFor()
|
// public function testFor()
|
||||||
{
|
// {
|
||||||
$this->assertRender('{for $i=0 to=3}{$i},{/for}', "0,1,2,3,");
|
// $this->assertRender('{for $i=0 to=3}{$i},{/for}', "0,1,2,3,");
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider providerScalars
|
* @dataProvider providerScalars
|
||||||
*/
|
*/
|
||||||
public function testVar($tpl_val, $val)
|
public function testVar($tpl_val, $val)
|
||||||
{
|
{
|
||||||
$this->assertRender("{var \$a=$tpl_val}\nVar: {\$a}", "Var: " . $val);
|
$this->assertRender("{set \$a=$tpl_val}\nVar: {\$a}", "Var: " . $val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,7 +26,7 @@ class TagsTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testVarBlock($tpl_val, $val)
|
public function testVarBlock($tpl_val, $val)
|
||||||
{
|
{
|
||||||
$this->assertRender("{var \$a}before {{$tpl_val}} after{/var}\nVar: {\$a}", "Var: before " . $val . " after");
|
$this->assertRender("{set \$a}before {{$tpl_val}} after{/set}\nVar: {\$a}", "Var: before " . $val . " after");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,14 +35,14 @@ class TagsTest extends TestCase
|
|||||||
public function testVarBlockModified($tpl_val, $val)
|
public function testVarBlockModified($tpl_val, $val)
|
||||||
{
|
{
|
||||||
$this->assertRender(
|
$this->assertRender(
|
||||||
"{var \$a|low|dots}before {{$tpl_val}} after{/var}\nVar: {\$a}",
|
"{set \$a|low|dots}before {{$tpl_val}} after{/set}\nVar: {\$a}",
|
||||||
"Var: " . strtolower("before " . $val . " after") . "..."
|
"Var: " . strtolower("before " . $val . " after") . "..."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCycle()
|
public function testCycle()
|
||||||
{
|
{
|
||||||
$this->assertRender('{for $i=0 to=4}{cycle ["one", "two"]}, {/for}', "one, two, one, two, one, ");
|
$this->assertRender('{foreach 0..4 as $i}{cycle ["one", "two"]}, {/foreach}', "one, two, one, two, one, ");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +51,7 @@ class TagsTest extends TestCase
|
|||||||
public function testCycleIndex()
|
public function testCycleIndex()
|
||||||
{
|
{
|
||||||
$this->assertRender(
|
$this->assertRender(
|
||||||
'{var $a=["one", "two"]}{for $i=1 to=5}{cycle $a index=$i}, {/for}',
|
'{set $a=["one", "two"]}{foreach 1..5 as $i}{cycle $a index=$i}, {/foreach}',
|
||||||
"two, one, two, one, two, "
|
"two, one, two, one, two, "
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -688,105 +688,28 @@ class TemplateTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function providerForeach()
|
|
||||||
{
|
|
||||||
$a = array(
|
|
||||||
"list" => array(1 => "one", 2 => "two", 3 => "three"),
|
|
||||||
"empty" => array(),
|
|
||||||
"obj" => new Helper("testing")
|
|
||||||
);
|
|
||||||
return array(
|
|
||||||
array('Foreach: {foreach $list as $e} {$e}, {/foreach} end', $a, 'Foreach: one, two, three, end'),
|
|
||||||
array('Foreach: {foreach $list as $e} {$e},{break} break {/foreach} end', $a, 'Foreach: one, end'),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach $list as $e} {$e},{continue} continue {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: one, two, three, end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach ["one", "two", "three"] as $e} {$e}, {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: one, two, three, end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach $list as $k => $e} {$k} => {$e}, {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: 1 => one, 2 => two, 3 => three, end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach [1 => "one", 2 => "two", 3 => "three"] as $k => $e} {$k} => {$e}, {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: 1 => one, 2 => two, 3 => three, end'
|
|
||||||
),
|
|
||||||
array('Foreach: {foreach $empty as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: end'),
|
|
||||||
array('Foreach: {foreach [] as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: end'),
|
|
||||||
array('Foreach: {foreach $obj->getArray() as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: 0 => 1, 1 => 2, 2 => 3, end'),
|
|
||||||
array('Foreach: {foreach $unexists as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: end'),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach $empty as $k => $e} {$k} => {$e}, {foreachelse} empty {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: empty end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach $list as $e index=$i} {$i}: {$e}, {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: 0: one, 1: two, 2: three, end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach $list as $k => $e index=$i} {$i}: {$k} => {$e}, {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: 0: 1 => one, 1: 2 => two, 2: 3 => three, end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach $empty as $k => $e index=$i} {$i}: {$k} => {$e}, {foreachelse} empty {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: empty end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach $list as $k => $e first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach $list as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, last end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach $empty as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {foreachelse} empty {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: empty end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'Foreach: {foreach [1 => "one", 2 => "two", 3 => "three"] as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {/foreach} end',
|
|
||||||
$a,
|
|
||||||
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, last end'
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function providerForeachInvalid()
|
public static function providerForeachInvalid()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach} {$e}, {/foreach} end',
|
'Foreach: {foreach} {$e}, {/foreach} end',
|
||||||
'Fenom\Error\CompileException',
|
'Fenom\Error\CompileException',
|
||||||
"Unexpected end of tag {foreach}"
|
"Unexpected end of expression"
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach $list} {$e}, {/foreach} end',
|
'Foreach: {foreach $list} {$e}, {/foreach} end',
|
||||||
'Fenom\Error\CompileException',
|
'Fenom\Error\CompileException',
|
||||||
"Unexpected end of expression"
|
"Unexpected end of expression"
|
||||||
),
|
),
|
||||||
array(
|
// array(
|
||||||
'Foreach: {foreach $list+1 as $e} {$e}, {/foreach} end',
|
// 'Foreach: {foreach $list+1 as $e} {$e}, {/foreach} end',
|
||||||
'Fenom\Error\CompileException',
|
// 'Fenom\Error\CompileException',
|
||||||
"Unexpected token '+'"
|
// "Unexpected token '+'"
|
||||||
),
|
// ),
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach array_random() as $e} {$e}, {/foreach} end',
|
'Foreach: {foreach array_random() as $e} {$e}, {/foreach} end',
|
||||||
'Fenom\Error\CompileException',
|
'Fenom\Error\CompileException',
|
||||||
"Unexpected token 'array_random'"
|
"Function array_random not found"
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach $list as $e+1} {$e}, {/foreach} end',
|
'Foreach: {foreach $list as $e+1} {$e}, {/foreach} end',
|
||||||
@ -826,7 +749,7 @@ class TemplateTest extends TestCase
|
|||||||
array(
|
array(
|
||||||
'Foreach: {foreach last=$l $list as $e } {$e}, {/foreach} end',
|
'Foreach: {foreach last=$l $list as $e } {$e}, {/foreach} end',
|
||||||
'Fenom\Error\CompileException',
|
'Fenom\Error\CompileException',
|
||||||
"Unexpected token 'last' in tag {foreach}"
|
"Unexpected token 'last' in expression"
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'Foreach: {foreach $list as $e unknown=1} {$e}, {/foreach} end',
|
'Foreach: {foreach $list as $e unknown=1} {$e}, {/foreach} end',
|
||||||
@ -966,95 +889,6 @@ class TemplateTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function providerFor()
|
|
||||||
{
|
|
||||||
$a = array("c" => 1, "s" => 1, "m" => 3);
|
|
||||||
return array(
|
|
||||||
array('For: {for $a=4 to=6} $a: {$a}, {/for} end', $a, 'For: $a: 4, $a: 5, $a: 6, end'),
|
|
||||||
array('For: {for $a=4 step=2 to=10} $a: {$a}, {/for} end', $a, 'For: $a: 4, $a: 6, $a: 8, $a: 10, end'),
|
|
||||||
array('For: {for $a=4 step=-2 to=0} $a: {$a}, {/for} end', $a, 'For: $a: 4, $a: 2, $a: 0, end'),
|
|
||||||
array('For: {for $a=$c step=$s to=$m} $a: {$a}, {/for} end', $a, 'For: $a: 1, $a: 2, $a: 3, end'),
|
|
||||||
array('For: {for $a=-1 step=-max(1,2) to=-5} $a: {$a}, {/for} end', $a, 'For: $a: -1, $a: -3, $a: -5, end'),
|
|
||||||
array('For: {for $a=4 step=2 to=10} $a: {$a}, {break} break {/for} end', $a, 'For: $a: 4, end'),
|
|
||||||
array(
|
|
||||||
'For: {for $a=4 step=2 to=8} $a: {$a}, {continue} continue {/for} end',
|
|
||||||
$a,
|
|
||||||
'For: $a: 4, $a: 6, $a: 8, end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'For: {for $a=4 step=2 to=8 index=$i} $a{$i}: {$a}, {/for} end',
|
|
||||||
$a,
|
|
||||||
'For: $a0: 4, $a1: 6, $a2: 8, end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'For: {for $a=4 step=2 to=8 index=$i first=$f} {if $f}first{/if} $a{$i}: {$a}, {/for} end',
|
|
||||||
$a,
|
|
||||||
'For: first $a0: 4, $a1: 6, $a2: 8, end'
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'For: {for $a=4 step=2 to=8 index=$i first=$f last=$l} {if $f} first {/if} $a{$i}: {$a}, {if $l} last {/if} {/for} end',
|
|
||||||
$a,
|
|
||||||
'For: first $a0: 4, $a1: 6, $a2: 8, last end'
|
|
||||||
),
|
|
||||||
array('For: {for $a=1 to=-1 } $a: {$a}, {forelse} empty {/for} end', $a, 'For: empty end'),
|
|
||||||
array(
|
|
||||||
'For: {for $a=1 to=-1 index=$i first=$f last=$l} {if $f} first {/if} $a{$i}: {$a}, {if $l} last {/if} {forelse} empty {/for} end',
|
|
||||||
$a,
|
|
||||||
'For: empty end'
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function providerForInvalid()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
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+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 '='"
|
|
||||||
),
|
|
||||||
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 first=$i $a=3 to=6} block1 {/for} end',
|
|
||||||
'Fenom\Error\CompileException',
|
|
||||||
"Unexpected token 'first'"
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'For: {for last=$i $a=3 to=6} block1 {/for} end',
|
|
||||||
'Fenom\Error\CompileException',
|
|
||||||
"Unexpected token 'last'"
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'For: {for $a=4 to=6 unk=4} block1 {/for} end',
|
|
||||||
'Fenom\Error\CompileException',
|
|
||||||
"Unknown parameter 'unk'"
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'For: {for $a=4 to=6 step=0} block1 {/for} end',
|
|
||||||
'Fenom\Error\CompileException',
|
|
||||||
"Invalid step value"
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'For: {for $a=4 to=6} $a: {$a}, {forelse} {break} {/for} end',
|
|
||||||
'Fenom\Error\CompileException',
|
|
||||||
"Improper usage of the tag {break}"
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'For: {for $a=4 to=6} $a: {$a}, {forelse} {continue} {/for} end',
|
|
||||||
'Fenom\Error\CompileException',
|
|
||||||
"Improper usage of the tag {continue}"
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function providerLayersInvalid()
|
public static function providerLayersInvalid()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
@ -1070,14 +904,14 @@ class TemplateTest extends TestCase
|
|||||||
),
|
),
|
||||||
array('Layers: {blah} end', 'Fenom\Error\CompileException', "Unexpected tag 'blah'"),
|
array('Layers: {blah} end', 'Fenom\Error\CompileException', "Unexpected tag 'blah'"),
|
||||||
array(
|
array(
|
||||||
'Layers: {for $a=4 to=6} block1 {if 1} {forelse} {/if} {/for} end',
|
'Layers: {foreach 4..6 as $a} block1 {if 1} {foreachelse} {/if} {/foreach} end',
|
||||||
'Fenom\Error\CompileException',
|
'Fenom\Error\CompileException',
|
||||||
"Unexpected tag 'forelse' (this tag can be used with 'for')"
|
"Unexpected tag 'foreachelse' (this tag can be used with 'foreach')"
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'Layers: {for $a=4 to=6} block1 {if 1} {/for} {/if} end',
|
'Layers: {foreach 4..6 as $a} block1 {if 1} {/foreach} {/if} end',
|
||||||
'Fenom\Error\CompileException',
|
'Fenom\Error\CompileException',
|
||||||
"Unexpected closing of the tag 'for'"
|
"Unexpected closing of the tag 'foreach'"
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'Layers: {switch 1} {if 1} {case 1} {/if} {/switch} end',
|
'Layers: {switch 1} {if 1} {case 1} {/if} {/switch} end',
|
||||||
@ -1464,11 +1298,101 @@ class TemplateTest extends TestCase
|
|||||||
$this->exec(__FUNCTION__ . ": $code end", $vars, __FUNCTION__ . ": $result end");
|
$this->exec(__FUNCTION__ . ": $code end", $vars, __FUNCTION__ . ": $result end");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function providerForeach()
|
||||||
|
{
|
||||||
|
$a = array(
|
||||||
|
"list" => array(1 => "one", 2 => "two", 3 => "three"),
|
||||||
|
"empty" => array(),
|
||||||
|
"obj" => new Helper("testing")
|
||||||
|
);
|
||||||
|
return array(
|
||||||
|
array('Foreach: {foreach $list as $e} {$e}, {/foreach} end', $a, 'Foreach: one, two, three, end'),
|
||||||
|
array('Foreach: {foreach $list as $e} {$e},{break} break {/foreach} end', $a, 'Foreach: one, end'),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $list as $e} {$e},{continue} continue {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: one, two, three, end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach ["one", "two", "three"] as $e} {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: one, two, three, end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $list as $k => $e} {$k} => {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: 1 => one, 2 => two, 3 => three, end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach [1 => "one", 2 => "two", 3 => "three"] as $k => $e} {$k} => {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: 1 => one, 2 => two, 3 => three, end'
|
||||||
|
),
|
||||||
|
array('Foreach: {foreach $empty as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: end'),
|
||||||
|
array('Foreach: {foreach [] as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: end'),
|
||||||
|
array('Foreach: {foreach $obj->getArray() as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: 0 => 1, 1 => 2, 2 => 3, end'),
|
||||||
|
array('Foreach: {foreach $unexists as $k => $e} {$k} => {$e}, {/foreach} end', $a, 'Foreach: end'),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $empty as $k => $e} {$k} => {$e}, {foreachelse} empty {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: empty end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $list as $e index=$i} {$i}: {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: 0: one, 1: two, 2: three, end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $list as $k => $e index=$i} {$i}: {$k} => {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: 0: 1 => one, 1: 2 => two, 2: 3 => three, end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $empty as $k => $e index=$i} {$i}: {$k} => {$e}, {foreachelse} empty {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: empty end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $list as $k => $e first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $list as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, last end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $empty as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {foreachelse} empty {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: empty end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach [1 => "one", 2 => "two", 3 => "three"] as $k => $e last=$l first=$f index=$i} {if $f}first{/if} {$i}: {$k} => {$e}, {if $l}last{/if} {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: first 0: 1 => one, 1: 2 => two, 2: 3 => three, last end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach 1..3 as $k => $e} {$k} => {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: 0 => 1, 1 => 2, 2 => 3, end'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Foreach: {foreach $.get.items as $e} {$e}, {/foreach} end',
|
||||||
|
$a,
|
||||||
|
'Foreach: one, two, three, end'
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider providerForeach
|
* @dataProvider providerForeach
|
||||||
|
* @backupGlobals
|
||||||
*/
|
*/
|
||||||
public function testForeach($code, $vars, $result)
|
public function testForeach($code, $vars, $result)
|
||||||
{
|
{
|
||||||
|
$_GET['items'] = array('one', 'two', 'three');
|
||||||
$this->exec($code, $vars, $result);
|
$this->exec($code, $vars, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1483,18 +1407,18 @@ class TemplateTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider providerFor
|
* @dataProvider providerFor
|
||||||
*/
|
*/
|
||||||
public function testFor($code, $vars, $result)
|
// public function testFor($code, $vars, $result)
|
||||||
{
|
// {
|
||||||
$this->exec($code, $vars, $result);
|
// $this->exec($code, $vars, $result);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider providerForInvalid
|
* @dataProvider providerForInvalid
|
||||||
*/
|
*/
|
||||||
public function testForInvalid($code, $exception, $message, $options = 0)
|
// public function testForInvalid($code, $exception, $message, $options = 0)
|
||||||
{
|
// {
|
||||||
$this->execError($code, $exception, $message, $options);
|
// $this->execError($code, $exception, $message, $options);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group testIgnores
|
* @group testIgnores
|
||||||
@ -1629,5 +1553,39 @@ class TemplateTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->execError($code, $exception, $message, $options);
|
$this->execError($code, $exception, $message, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function providerRange()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('{set $a=1..3}', "1,2,3,"),
|
||||||
|
array('{set $a="a".."f"}', "a,b,c,d,e,f,"),
|
||||||
|
array('{set $a=1.."f"}', "1,0,"),
|
||||||
|
array('{set $a="a"..2}', "0,1,2,"),
|
||||||
|
array('{set $a=$one..$three}', "1,2,3,"),
|
||||||
|
array('{set $a=$one..3}', "1,2,3,"),
|
||||||
|
array('{set $a=1..$three}', "1,2,3,"),
|
||||||
|
array('{set $a=$one..$three++}', "1,2,3,"),
|
||||||
|
array('{set $a=$one..++$three}', "1,2,3,4,"),
|
||||||
|
array('{set $a=$one--..$three++}', "1,2,3,"),
|
||||||
|
array('{set $a=--$one..++$three}', "0,1,2,3,4,"),
|
||||||
|
array('{set $a="a"|up.."f"|up}', "A,B,C,D,E,F,"),
|
||||||
|
array('{set $a=$one|min:0..$three|max:4}', "0,1,2,3,4,"),
|
||||||
|
array('{set $a=$one|min:0..4}', "0,1,2,3,4,"),
|
||||||
|
array('{set $a=0..$three|max:4}', "0,1,2,3,4,"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerRange
|
||||||
|
* @group testRange
|
||||||
|
* @param string $code
|
||||||
|
* @param string $result
|
||||||
|
*/
|
||||||
|
public function testRange($code, $result)
|
||||||
|
{
|
||||||
|
$this->exec($code.'{foreach $a as $v}{$v},{/foreach}', self::getVars(), $result);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,8 +43,7 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
|
|||||||
T_STRING,
|
T_STRING,
|
||||||
'please',
|
'please',
|
||||||
' ',
|
' ',
|
||||||
1,
|
1
|
||||||
'T_STRING'
|
|
||||||
),
|
),
|
||||||
$tokens->curr
|
$tokens->curr
|
||||||
);
|
);
|
||||||
@ -110,4 +109,13 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertNull($tokens->undef);
|
$this->assertNull($tokens->undef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFixFloats() {
|
||||||
|
$text = "1..3";
|
||||||
|
$tokens = new Tokenizer($text);
|
||||||
|
$this->assertTrue($tokens->is(T_LNUMBER));
|
||||||
|
$this->assertTrue($tokens->next()->is('.'));
|
||||||
|
$this->assertTrue($tokens->next()->is('.'));
|
||||||
|
$this->assertTrue($tokens->next()->is(T_LNUMBER));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user