* @author David Sanchez * @copyright 2008-2013 Jordi Boggiano * @copyright 2013-2016 David Sanchez * @license http://dwoo.org/LICENSE Modified BSD License * @version 1.3.0 * @date 2016-09-19 * @link http://dwoo.org/ */ namespace Dwoo\Plugins\Blocks; use Dwoo\Compiler; use Dwoo\IElseable; use Dwoo\Block\Plugin as BlockPlugin; use Dwoo\ICompilable\Block as ICompilableBlock; use Dwoo\Compilation\Exception as CompilationException; /** * Conditional block, the syntax is very similar to the php one, allowing () || && and * other php operators. Additional operators and their equivalent php syntax are as follow :. * eq -> == * neq or ne -> != * gte or ge -> >= * lte or le -> <= * gt -> > * lt -> < * mod -> % * not -> ! * X is [not] div by Y -> (X % Y) == 0 * X is [not] even [by Y] -> (X % 2) == 0 or ((X/Y) % 2) == 0 * X is [not] odd [by Y] -> (X % 2) != 0 or ((X/Y) % 2) != 0 * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from the use of this software. */ class PluginIf extends BlockPlugin implements ICompilableBlock, IElseable { /** * @param array $rest */ public function init(array $rest) { } /** * @param array $params * @param array $tokens * @param Compiler $compiler * * @return array * @throws CompilationException */ public static function replaceKeywords(array $params, array $tokens, Compiler $compiler) { $p = array(); foreach($params as $k => $v) { $v = (string)$v; if (substr($v, 0, 1) === '"' || substr($v, 0, 1) === '\'') { $vmod = strtolower(substr($v, 1, - 1)); } else { $vmod = strtolower($v); } switch ($vmod) { case 'and': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '&&'; } else { $p[] = $v; } break; case 'or': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '||'; } else { $p[] = $v; } break; case 'xor': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '^'; } else { $p[] = $v; } break; case 'eq': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '=='; } else { $p[] = $v; } break; case 'ne': case 'neq': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '!='; } else { $p[] = $v; } break; case 'gte': case 'ge': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '>='; } else { $p[] = $v; } break; case 'lte': case 'le': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '<='; } else { $p[] = $v; } break; case 'gt': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '>'; } else { $p[] = $v; } break; case 'lt': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '<'; } else { $p[] = $v; } break; case 'mod': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '%'; } else { $p[] = $v; } break; case 'not': if ($tokens[$k] === Compiler::T_UNQUOTED_STRING) { $p[] = '!'; } else { $p[] = $v; } break; case '<>': $p[] = '!='; break; case '==': case '!=': case '>=': case '<=': case '>': case '<': case '===': case '!==': case '%': case '!': case '^': $p[] = $vmod; break; case 'is': if ($tokens[$k] !== Compiler::T_UNQUOTED_STRING) { $p[] = $v; break; } if (isset($params[$k + 1]) && strtolower(trim($params[$k + 1], '"\'')) === 'not' && $tokens[$k + 1] === Compiler::T_UNQUOTED_STRING) { $negate = true; next($params); } else { $negate = false; } $ptr = 1 + (int)$negate; if ($tokens[$k + $ptr] !== Compiler::T_UNQUOTED_STRING) { break; } if (!isset($params[$k + $ptr])) { $params[$k + $ptr] = ''; } else { $params[$k + $ptr] = trim($params[$k + $ptr], '"\''); } switch ($params[$k + $ptr]) { case 'div': if (isset($params[$k + $ptr + 1]) && strtolower(trim($params[$k + $ptr + 1], '"\'')) === 'by') { $p[] = ' % ' . $params[$k + $ptr + 2] . ' ' . ($negate ? '!' : '=') . '== 0'; next($params); next($params); next($params); } else { throw new CompilationException($compiler, 'If : Syntax error : syntax should be "if $a is [not] div by $b", found ' . $params[$k - 1] . ' is ' . ($negate ? 'not ' : '') . 'div ' . $params[$k + $ptr + 1] . ' ' . $params[$k + $ptr + 2]); } break; case 'even': $a = array_pop($p); if (isset($params[$k + $ptr + 1]) && strtolower(trim($params[$k + $ptr + 1], '"\'')) === 'by') { $b = $params[$k + $ptr + 2]; $p[] = '(' . $a . ' / ' . $b . ') % 2 ' . ($negate ? '!' : '=') . '== 0'; next($params); next($params); } else { $p[] = $a . ' % 2 ' . ($negate ? '!' : '=') . '== 0'; } next($params); break; case 'odd': $a = array_pop($p); if (isset($params[$k + $ptr + 1]) && strtolower(trim($params[$k + $ptr + 1], '"\'')) === 'by') { $b = $params[$k + $ptr + 2]; $p[] = '(' . $a . ' / ' . $b . ') % 2 ' . ($negate ? '=' : '!') . '== 0'; next($params); next($params); } else { $p[] = $a . ' % 2 ' . ($negate ? '=' : '!') . '== 0'; } next($params); break; default: throw new CompilationException($compiler, 'If : Syntax error : syntax should be "if $a is [not] (div|even|odd) [by $b]", found ' . $params[$k - 1] . ' is ' . $params[$k + $ptr + 1]); } break; default: $p[] = $v; } } return $p; } /** * @param Compiler $compiler * @param array $params * @param string $prepend * @param string $append * @param string $type * * @return string */ public static function preProcessing(Compiler $compiler, array $params, $prepend, $append, $type) { return ''; } /** * @param Compiler $compiler * @param array $params * @param string $prepend * @param string $append * @param string $content * * @return string */ public static function postProcessing(Compiler $compiler, array $params, $prepend, $append, $content) { $tokens = $compiler->getParamTokens($params); $params = $compiler->getCompiledParams($params); $pre = Compiler::PHP_OPEN . 'if (' . implode(' ', self::replaceKeywords($params['*'], $tokens['*'], $compiler)) . ") {\n" . Compiler::PHP_CLOSE; $post = Compiler::PHP_OPEN . "\n}" . Compiler::PHP_CLOSE; if (isset($params['hasElse'])) { $post .= $params['hasElse']; } return $pre . $content . $post; } }