Fix {switch} and ternary operator

This commit is contained in:
bzick
2013-09-05 03:35:02 +04:00
parent 7a84cf4ceb
commit d5ecc1bc20
6 changed files with 60 additions and 25 deletions

View File

@ -5,6 +5,4 @@ php:
- 5.4 - 5.4
- 5.5 - 5.5
before_script: composer install
script: phpunit script: phpunit

View File

@ -30,7 +30,6 @@ $fenom->setOptions($options);
* **auto_escape**, `Fenom::AUTO_ESCAPE`, все выводящие переменные и результаты функций будут экранироваться * **auto_escape**, `Fenom::AUTO_ESCAPE`, все выводящие переменные и результаты функций будут экранироваться
* **auto_trim**, `Fenom::AUTO_TRIM`, при компиляции, все пробельные символы между тегами будут удлаены. * **auto_trim**, `Fenom::AUTO_TRIM`, при компиляции, все пробельные символы между тегами будут удлаены.
* **force_verify**, `Fenom::FORCE_VERIFY`, проверять обращение каждой переменной и возвращать NULL если переменной не существует. * **force_verify**, `Fenom::FORCE_VERIFY`, проверять обращение каждой переменной и возвращать NULL если переменной не существует.
* **deny_static_methods**, `Fenom::DENY_STATIC_METHODS`, отключает возможность вызова статичных методов в шаблоне.
```php ```php
$fenom->setOptions(array( $fenom->setOptions(array(

View File

@ -1,6 +1,12 @@
Tag {switch} Tag {switch}
============ ============
The `{switch}` tag is similar to a series of `{if}` statements on the same expression.
In many occasions, you may want to compare the same variable (or expression) with many different values,
and execute a different piece of code depending on which value it equals to. This is exactly what the `{switch}` tag is for.
Tag `{switch}` accepts any expression. But `{case}` accepts only static scalar values or constants.
```smarty ```smarty
{switch <condition>} {switch <condition>}
{case <value1>} {case <value1>}
@ -9,7 +15,7 @@ Tag {switch}
... ...
{case <value3>} {case <value3>}
... ...
{default} {default case <value1>}
... ...
{/switch} {/switch}
``` ```
@ -24,14 +30,14 @@ For example,
It is new or current item It is new or current item
{case 'current'} {case 'current'}
It is current item It is current item
{case 'new'} {case 'new', $.const.NEW_STATUS}
It is new item, again It is new item, again
{default} {default}
I don't know the type {$type} I don't know the type {$type}
{/switch} {/switch}
``` ```
set `$type = 'new'`, then template output if `$type = 'new'` then template output
``` ```
It is new item It is new item

View File

@ -332,10 +332,12 @@ class Compiler
*/ */
public static function switchOpen(Tokenizer $tokens, Scope $scope) public static function switchOpen(Tokenizer $tokens, Scope $scope)
{ {
$scope["expr"] = $scope->tpl->parseExpr($tokens); $expr = $scope->tpl->parseExpr($tokens);
$scope["case"] = array(); $scope["case"] = array();
$scope["last"] = array(); $scope["last"] = array();
$scope["default"] = ''; $scope["default"] = '';
$scope["var"] = $scope->tpl->tmpVar();
$scope["expr"] = $scope["var"].' = strval('.$expr.')';
// lazy init // lazy init
return ''; return '';
} }
@ -409,13 +411,16 @@ class Compiler
public static function switchClose(Tokenizer $tokens, Scope $scope) public static function switchClose(Tokenizer $tokens, Scope $scope)
{ {
self::_caseResort($scope); self::_caseResort($scope);
$expr = $scope["expr"]; $expr = $scope["var"];
$code = ""; $code = $scope["expr"].";\n";
$default = $scope["default"]; $default = $scope["default"];
foreach ($scope["case"] as $case => $content) { foreach ($scope["case"] as $case => $content) {
if(is_numeric($case)) {
$case = "'$case'";
}
$code .= "if($expr == $case) {\n?>$content<?php\n} else"; $code .= "if($expr == $case) {\n?>$content<?php\n} else";
} }
$code .= " {\n?>$default<?php\n}"; $code .= " {\n?>$default<?php\n}\nunset(".$scope["var"].")";
return $code; return $code;
} }

View File

@ -622,7 +622,7 @@ class Template extends Render
$var = false; $var = false;
} }
if ($tokens->is('?', '!')) { if ($tokens->is('?', '!')) {
$term = $this->parseTernary($tokens, $term, $tokens->current()); $term = $this->parseTernary($tokens, $term, $var);
$var = false; $var = false;
} }
$exp[] = $term; $exp[] = $term;
@ -873,35 +873,59 @@ class Template extends Render
* *
* @param Tokenizer $tokens * @param Tokenizer $tokens
* @param $var * @param $var
* @param $type * @param $is_var
* @return string * @return string
* @throws UnexpectedTokenException * @throws UnexpectedTokenException
*/ */
public function parseTernary(Tokenizer $tokens, $var, $type) public function parseTernary(Tokenizer $tokens, $var, $is_var)
{ {
$empty = ($type === "?"); $empty = $tokens->is('?');
$tokens->next(); $tokens->next();
if ($tokens->is(":")) { if ($tokens->is(":")) {
$tokens->next(); $tokens->next();
if ($empty) { if ($empty) {
return '(empty(' . $var . ') ? (' . $this->parseExpr($tokens) . ') : ' . $var . ')'; if($is_var) {
return '(empty(' . $var . ') ? (' . $this->parseExpr($tokens) . ') : ' . $var . ')';
} else {
return '(' . $var . ' ?: (' . $this->parseExpr($tokens) . ')';
}
} else { } else {
return '(isset(' . $var . ') ? ' . $var . ' : (' . $this->parseExpr($tokens) . '))'; if($is_var) {
return '(isset(' . $var . ') ? ' . $var . ' : (' . $this->parseExpr($tokens) . '))';
} else {
return '((' . $var . ' !== null) ? ' . $var . ' : (' . $this->parseExpr($tokens) . '))';
}
} }
} elseif ($tokens->is(Tokenizer::MACRO_BINARY, Tokenizer::MACRO_BOOLEAN, Tokenizer::MACRO_MATH) || !$tokens->valid()) { } elseif ($tokens->is(Tokenizer::MACRO_BINARY, Tokenizer::MACRO_BOOLEAN, Tokenizer::MACRO_MATH) || !$tokens->valid()) {
if ($empty) { if ($empty) {
return '!empty(' . $var . ')'; if($is_var) {
return '!empty(' . $var . ')';
} else {
return '(' . $var . ')';
}
} else { } else {
return 'isset(' . $var . ')'; if($is_var) {
return 'isset(' . $var . ')';
} else {
return '(' . $var . ' !== null)';
}
} }
} else { } else {
$expr1 = $this->parseExpr($tokens); $expr1 = $this->parseExpr($tokens);
$tokens->need(':')->skip(); $tokens->need(':')->skip();
$expr2 = $this->parseExpr($tokens); $expr2 = $this->parseExpr($tokens);
if ($empty) { if ($empty) {
return '(empty(' . $var . ') ? ' . $expr2 . ' : ' . $expr1 . ')'; if($is_var) {
return '(empty(' . $var . ') ? ' . $expr2 . ' : ' . $expr1 . ')';
} else {
return '(' . $var . ' ? ' . $expr1 . ' : ' . $expr2 . ')';
}
} else { } else {
return '(isset(' . $var . ') ? ' . $expr1 . ' : ' . $expr2 . ')'; if($is_var) {
return '(isset(' . $var . ') ? ' . $expr1 . ' : ' . $expr2 . ')';
} else {
return '((' . $var . ' !== null) ? ' . $expr1 . ' : ' . $expr2 . ')';
}
} }
} }
} }
@ -1035,22 +1059,23 @@ class Template extends Render
*/ */
public function parseScalar(Tokenizer $tokens) public function parseScalar(Tokenizer $tokens)
{ {
$_scalar = "";
$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(); return $tokens->getAndNext();
break; break;
case T_ENCAPSED_AND_WHITESPACE: case T_ENCAPSED_AND_WHITESPACE:
case '"': case '"':
$_scalar .= $this->parseQuote($tokens); return $this->parseQuote($tokens);
break; break;
case '$':
$tokens->next()->need('.')->next()->need(T_CONST)->next();
return 'constant('.$this->parseName($tokens).')';
default: default:
throw new UnexpectedTokenException($tokens); throw new UnexpectedTokenException($tokens);
} }
return $_scalar;
} }
/** /**

View File

@ -1,6 +1,8 @@
<?php <?php
require_once __DIR__ . "/../vendor/autoload.php"; $loader = include(__DIR__ . "/../vendor/autoload.php");
/* @var Composer\Autoload\ClassLoader $loader */
$loader->add('Fenom', __DIR__.'/cases');
define('FENOM_RESOURCES', __DIR__ . "/resources"); define('FENOM_RESOURCES', __DIR__ . "/resources");