diff --git a/lib/exTpl/ArithExpression.php b/lib/exTpl/ArithExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..4888b73125b14268ac22e7a0ea86847629882efa --- /dev/null +++ b/lib/exTpl/ArithExpression.php @@ -0,0 +1,29 @@ +<?php + +namespace exTpl; + +/** + * ArithExpression represents an arithmetic operator. + */ +class ArithExpression extends BinaryExpression +{ + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): mixed + { + $left = $this->left->value($context); + $right = $this->right->value($context); + + return match ($this->operator) { + '+' => $left + $right, + '-' => $left - $right, + '*' => $left * $right, + '/' => $left / $right, + '%' => $left % $right, + '~' => $left . $right, + }; + } +} diff --git a/lib/exTpl/ArrayNode.php b/lib/exTpl/ArrayNode.php new file mode 100644 index 0000000000000000000000000000000000000000..3981598a0c21cb3900ed653694a704e526cc468f --- /dev/null +++ b/lib/exTpl/ArrayNode.php @@ -0,0 +1,37 @@ +<?php + +namespace exTpl; + +/** + * ArrayNode represents a sequence of arbitrary nodes. + */ +class ArrayNode implements Node +{ + protected array $nodes = []; + + /** + * Adds a child node to this sequence node. + * + * @param Node $node child node to add + */ + public function addChild(Node $node): void + { + $this->nodes[] = $node; + } + + /** + * Returns a string representation of this node. + * + * @param Context $context symbol table + */ + public function render(Context $context): string + { + $result = ''; + + foreach ($this->nodes as $node) { + $result .= $node->render($context); + } + + return $result; + } +} diff --git a/lib/exTpl/BinaryExpression.php b/lib/exTpl/BinaryExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..1c82730e4c06755112f37c2934b3aaa7fab37ed8 --- /dev/null +++ b/lib/exTpl/BinaryExpression.php @@ -0,0 +1,27 @@ +<?php + +namespace exTpl; + +/** + * BinaryExpression represents a binary operator. + */ +abstract class BinaryExpression implements Expression +{ + protected Expression $left; + protected Expression $right; + protected mixed $operator; + + /** + * Initializes a new Expression instance. + * + * @param Expression $left left operand + * @param Expression $right right operand + * @param mixed $operator operator token + */ + public function __construct(Expression $left, Expression $right, mixed $operator) + { + $this->left = $left; + $this->right = $right; + $this->operator = $operator; + } +} diff --git a/lib/exTpl/BooleanExpression.php b/lib/exTpl/BooleanExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..0e18df02594dbaf4f80bf6b90cd4fae6f4e06e91 --- /dev/null +++ b/lib/exTpl/BooleanExpression.php @@ -0,0 +1,31 @@ +<?php + +namespace exTpl; + +/** + * BooleanExpression represents a boolean operator. + */ +class BooleanExpression extends BinaryExpression +{ + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): bool + { + $left = $this->left->value($context); + $right = $this->right->value($context); + + return match ($this->operator) { + T_IS_EQUAL => $left == $right, + T_IS_NOT_EQUAL => $left != $right, + '<' => $left < $right, + T_IS_SMALLER_OR_EQUAL => $left <= $right, + '>' => $left > $right, + T_IS_GREATER_OR_EQUAL => $left >= $right, + T_BOOLEAN_AND => $left && $right, + T_BOOLEAN_OR => $left || $right, + }; + } +} diff --git a/lib/exTpl/ConditionExpression.php b/lib/exTpl/ConditionExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..657ee3193fc0cd2eb2324bb5300df2e0817d43c6 --- /dev/null +++ b/lib/exTpl/ConditionExpression.php @@ -0,0 +1,38 @@ +<?php + +namespace exTpl; + +/** + * ConditionExpression represents the conditional operator ('?:'). + */ +class ConditionExpression implements Expression +{ + protected Expression $condition; + protected Expression $left; + protected Expression $right; + + /** + * Initializes a new Expression instance. + * + * @param Expression $condition expression + * @param Expression $left left alternative + * @param Expression $right right alternative + */ + public function __construct(Expression $condition, Expression $left, Expression $right) + { + $this->condition = $condition; + $this->left = $left; + $this->right = $right; + } + + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): mixed + { + return $this->condition->value($context) ? + $this->left->value($context) : $this->right->value($context); + } +} diff --git a/lib/exTpl/ConditionNode.php b/lib/exTpl/ConditionNode.php new file mode 100644 index 0000000000000000000000000000000000000000..bab212141f8b73f2872847a127c8dbb5b19f55d4 --- /dev/null +++ b/lib/exTpl/ConditionNode.php @@ -0,0 +1,59 @@ +<?php + +namespace exTpl; + +/** + * ConditionNode represents a single condition tag: + * "{if CONDITION}...{else}...{endif}". + */ +class ConditionNode extends ArrayNode +{ + protected Expression $condition; + protected ArrayNode|null $else_node = null; + + /** + * Initializes a new Node instance with the given expression. + * + * @param Expression $condition expression object + */ + public function __construct(Expression $condition) + { + $this->condition = $condition; + } + + /** + * Adds an else block to this condition node. + */ + public function addElse(): void + { + $this->else_node = new ArrayNode(); + } + + /** + * Adds a child node to this condition node. + * + * @param Node $node child node to add + */ + public function addChild(Node $node): void + { + if ($this->else_node) { + $this->else_node->addChild($node); + } else { + parent::addChild($node); + } + } + + /** + * Returns a string representation of this node. + * + * @param Context $context symbol table + */ + public function render(Context $context): string + { + if ($this->condition->value($context)) { + return parent::render($context); + } + + return $this->else_node ? $this->else_node->render($context) : ''; + } +} diff --git a/lib/exTpl/ConstantExpression.php b/lib/exTpl/ConstantExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..72356473a6e8ef481f4f33208f58e4632f1a31a0 --- /dev/null +++ b/lib/exTpl/ConstantExpression.php @@ -0,0 +1,31 @@ +<?php + +namespace exTpl; + +/** + * ConstantExpression represents a literal value. + */ +class ConstantExpression implements Expression +{ + protected mixed $value; + + /** + * Initializes a new Expression instance. + * + * @param mixed $value expression value + */ + public function __construct(mixed $value) + { + $this->value = $value; + } + + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): mixed + { + return $this->value; + } +} diff --git a/vendor/exTpl/Context.php b/lib/exTpl/Context.php similarity index 52% rename from vendor/exTpl/Context.php rename to lib/exTpl/Context.php index ea94b2fd25f8b917bf1330814147829ed97d8e75..309174fe02a6d806a68d3413301404cc51373d46 100644 --- a/vendor/exTpl/Context.php +++ b/lib/exTpl/Context.php @@ -1,47 +1,44 @@ <?php -/* +/** * Context.php - template parser symbol table * - * Copyright (c) 2013 Elmar Ludwig + * A Context object represents the symbol table used to resolve + * symbol names to their values in the local scope. Each context + * may inherit symbol definitions from its parent context. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * @copyright 2013 Elmar Ludwig + * @license GPL2 or any later version */ namespace exTpl; -/** - * A Context object represents the symbol table used to resolve - * symbol names to their values in the local scope. Each context - * may inherit symbol definitions from its parent context. - */ +use Closure; + class Context { - private $bindings; - private $escape; - private $parent; + private array $bindings; + private Closure|null $escape; + private Context|null $parent; /** * Initializes a new Context instance with the given bindings. * - * @param array $bindings symbol table - * @param Context $parent parent context (or NULL) + * @param array $bindings symbol table + * @param Context|null $parent parent context (or NULL) */ - public function __construct($bindings, Context $parent = NULL) + public function __construct(array $bindings, Context $parent = null) { $this->bindings = $bindings; - $this->parent = $parent; + $this->parent = $parent; } /** * Looks up the value of a symbol in this context and returns it. * The reserved symbol "this" is an alias for the current context. * - * @param string $key symbol name + * @param string $key symbol name */ - public function lookup($key) + public function lookup(string $key): mixed { if (isset($this->bindings[$key])) { return $this->bindings[$key]; @@ -49,25 +46,25 @@ class Context return $this->parent->lookup($key); } - return NULL; + return null; } /** * Enables or disables automatic escaping for template values. * - * @param callable $escape escape callback or NULL + * @param callable|null $escape escape callback or null */ - public function autoescape($escape) + public function autoescape(?callable $escape): void { - $this->escape = $escape; + $this->escape = $escape ? $escape(...) : null; } /** * Escapes the given value using the configured strategy. * - * @param mixed $value expression value + * @param mixed $value expression value */ - public function escape($value) + public function escape(mixed $value): mixed { if (isset($this->escape)) { $value = call_user_func($this->escape, $value); diff --git a/lib/exTpl/Expression.php b/lib/exTpl/Expression.php new file mode 100644 index 0000000000000000000000000000000000000000..15a485ddffb684a8674df46a6ab58d1380796497 --- /dev/null +++ b/lib/exTpl/Expression.php @@ -0,0 +1,27 @@ +<?php +/* + * Expression.php - template parser expression interface and classes + * + * Copyright (c) 2013 Elmar Ludwig + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +namespace exTpl; + +/** + * Basic interface for expressions in the template parse tree. The + * only required method is "value" to get the expression's value. + */ +interface Expression +{ + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): mixed; +} diff --git a/lib/exTpl/ExpressionNode.php b/lib/exTpl/ExpressionNode.php new file mode 100644 index 0000000000000000000000000000000000000000..061edce2497e3ae1ce7882aa3adc0633dd7a826c --- /dev/null +++ b/lib/exTpl/ExpressionNode.php @@ -0,0 +1,37 @@ +<?php + +namespace exTpl; + +/** + * ExpressionNode represents an expression tag: "{...}". + */ +class ExpressionNode implements Node +{ + protected Expression $expr; + + /** + * Initializes a new Node instance with the given expression. + * + * @param Expression $expr expression object + */ + public function __construct(Expression $expr) + { + $this->expr = $expr; + } + + /** + * Returns a string representation of this node. + * + * @param Context $context symbol table + */ + public function render(Context $context): ?string + { + $value = $this->expr->value($context); + + if (!($this->expr instanceof RawExpression)) { + $value = $context->escape($value); + } + + return $value; + } +} diff --git a/lib/exTpl/FunctionExpression.php b/lib/exTpl/FunctionExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..48d4413e6e71e1eea4498d31ff121ab35ab16806 --- /dev/null +++ b/lib/exTpl/FunctionExpression.php @@ -0,0 +1,45 @@ +<?php + +namespace exTpl; + +/** + * FunctionExpression represents a function call. + */ +class FunctionExpression implements Expression +{ + protected Expression $name; + protected array $arguments; + + /** + * Initializes a new Expression instance. + * + * @param Expression $name function name + * @param array $arguments function arguments + */ + public function __construct(Expression $name, array $arguments) + { + $this->name = $name; + $this->arguments = $arguments; + } + + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): mixed + { + $callable = $this->name->value($context); + $arguments = []; + + foreach ($this->arguments as $expr) { + $arguments[] = $expr->value($context); + } + + if (is_callable($callable)) { + return $callable(...$arguments); + } + + return null; + } +} diff --git a/lib/exTpl/IndexExpression.php b/lib/exTpl/IndexExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..ecb3241bee275c7633ea322188efbb9e1215dbff --- /dev/null +++ b/lib/exTpl/IndexExpression.php @@ -0,0 +1,22 @@ +<?php + +namespace exTpl; + +/** + * IndexExpression represents the array index operator. + */ +class IndexExpression extends BinaryExpression +{ + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): mixed + { + $left = $this->left->value($context); + $right = $this->right->value($context); + + return $left[$right]; + } +} diff --git a/lib/exTpl/IteratorNode.php b/lib/exTpl/IteratorNode.php new file mode 100644 index 0000000000000000000000000000000000000000..58dd593599a84e9907f3129f452591f5219229d0 --- /dev/null +++ b/lib/exTpl/IteratorNode.php @@ -0,0 +1,55 @@ +<?php + +namespace exTpl; + +/** + * IteratorNode represents a single iterator tag: + * "{foreach ARRAY [as [KEY =>] VALUE]}...{endforeach}". + */ +class IteratorNode extends ArrayNode +{ + protected Expression $expr; + protected string $key_name; + protected string $val_name; + + /** + * Initializes a new Node instance with the given expression. + * + * @param Expression $expr expression object + * @param string $key_name name of variable on each iteration + * @param string $val_name name of variable on each iteration + */ + public function __construct(Expression $expr, string $key_name, string $val_name) + { + $this->expr = $expr; + $this->key_name = $key_name; + $this->val_name = $val_name; + } + + /** + * Returns a string representation of this node. The IteratorNode + * renders the node sequence for each value in the expression list. + * + * @param Context $context symbol table + */ + public function render(Context $context): string + { + $values = $this->expr->value($context); + $result = ''; + + if (is_array($values) && is_int(key($values))) { + $bindings = [$this->key_name => &$key, $this->val_name => &$value]; + $context = new Context($bindings, $context); + + foreach ($values as $key => $value) { + $result .= parent::render(new Context($value, $context)); + } + } else if (is_array($values) && count($values)) { + return parent::render(new Context($values, $context)); + } else if ($values) { + return parent::render($context); + } + + return $result; + } +} diff --git a/lib/exTpl/MinusExpression.php b/lib/exTpl/MinusExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..6b81e91dd1e3c1c82424deb6cc79cb5ca6600828 --- /dev/null +++ b/lib/exTpl/MinusExpression.php @@ -0,0 +1,19 @@ +<?php + +namespace exTpl; + +/** + * MinusExpression represents the unary minus operator ('-'). + */ +class MinusExpression extends UnaryExpression +{ + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): mixed + { + return -$this->expr->value($context); + } +} diff --git a/lib/exTpl/Node.php b/lib/exTpl/Node.php new file mode 100644 index 0000000000000000000000000000000000000000..5c24cab123aff80e199da198f362c2aca4109f2e --- /dev/null +++ b/lib/exTpl/Node.php @@ -0,0 +1,28 @@ +<?php +/* + * Node.php - template parser node interface and classes + * + * Copyright (c) 2013 Elmar Ludwig + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +namespace exTpl; + + +/** + * Basic interface for nodes in the template parse tree. The only + * required method is "render" to render a node and its children. + */ +interface Node +{ + /** + * Returns a string representation of this node. + * + * @param Context $context symbol table + */ + public function render(Context $context): ?string; +} diff --git a/lib/exTpl/NotExpression.php b/lib/exTpl/NotExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..cf7472d605137b815fd629f5146304b22dfa84cb --- /dev/null +++ b/lib/exTpl/NotExpression.php @@ -0,0 +1,19 @@ +<?php + +namespace exTpl; + +/** + * NotExpression represents the logical negation operator ('!'). + */ +class NotExpression extends UnaryExpression +{ + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): bool + { + return !$this->expr->value($context); + } +} diff --git a/lib/exTpl/RawExpression.php b/lib/exTpl/RawExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..275f239a6519a6b6053ae5ffc422751b28f69a27 --- /dev/null +++ b/lib/exTpl/RawExpression.php @@ -0,0 +1,19 @@ +<?php + +namespace exTpl; + +/** + * RawExpression represents the "raw" filter function. + */ +class RawExpression extends UnaryExpression +{ + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): mixed + { + return $this->expr->value($context); + } +} diff --git a/lib/exTpl/Scanner.php b/lib/exTpl/Scanner.php new file mode 100644 index 0000000000000000000000000000000000000000..76cbc01d41429cf28e391f69cd905a2d3545b41f --- /dev/null +++ b/lib/exTpl/Scanner.php @@ -0,0 +1,87 @@ +<?php +/** + * Scanner.php - template parser lexical scanner + * + * Simple wrapper class around the Zend engine's lexical scanner. It + * automatically skips whitespace. + * + * @copyright 2013 Elmar Ludwig + * @license GPL2 or any later version + */ +namespace exTpl; + +class Scanner +{ + private array $tokens; + private mixed $token_type; + private mixed $token_value; + + /** + * Initializes a new Scanner instance for the given text. + * + * @param string $text string to parse + */ + public function __construct(string $text) + { + $this->tokens = token_get_all('<?php ' . $text); + } + + /** + * Advances the scanner to the next token and returns its token type. + * The valid token types are those defined for token_get_all() in the + * PHP documentation. Returns false when the end of input is reached. + */ + public function nextToken(): mixed + { + do { + $token = next($this->tokens); + $key = key($this->tokens); + + // FIXME this workaround should be dropped + while ( + $token && $token[0] === T_STRING + && isset($this->tokens[$key + 2]) + && $this->tokens[++$key] === '-' + && $this->tokens[++$key][0] === T_STRING + ) { + $token[1] .= '-' . $this->tokens[$key][1]; + next($this->tokens); + next($this->tokens); + } + } while (is_array($token) && $token[0] === T_WHITESPACE); + + if (is_string($token) || $token === false) { + $this->token_type = $token; + $this->token_value = null; + } else { + $this->token_type = $token[0]; + + $this->token_value = match ($token[0]) { + T_CONSTANT_ENCAPSED_STRING => stripcslashes(substr($token[1], 1, -1)), + T_DNUMBER => (double) $token[1], + T_LNUMBER => (int) $token[1], + default => $token[1], + }; + } + + return $this->token_type; + } + + /** + * Returns the current token type. The valid token types are + * those defined for token_get_all() in the PHP documentation. + */ + public function tokenType(): mixed + { + return $this->token_type; + } + + /** + * Returns the current token value if the token type supports + * a value (T_STRING, T_LNUMBER etc.). Returns null otherwise. + */ + public function tokenValue(): mixed + { + return $this->token_value; + } +} diff --git a/lib/exTpl/SymbolExpression.php b/lib/exTpl/SymbolExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..178a51f0a3c20e891e9a5b41c368bd5ea0251a4f --- /dev/null +++ b/lib/exTpl/SymbolExpression.php @@ -0,0 +1,39 @@ +<?php + +namespace exTpl; + +/** + * SymbolExpression represents a symbol (template variable). + */ +class SymbolExpression implements Expression +{ + protected string $name; + + /** + * Initializes a new Expression instance. + * + * @param string $name symbol name + */ + public function __construct(string $name) + { + $this->name = $name; + } + + /** + * Returns the name of this symbol. + */ + public function name(): string + { + return $this->name; + } + + /** + * Returns the value of this expression. + * + * @param Context $context symbol table + */ + public function value(Context $context): mixed + { + return $context->lookup($this->name); + } +} diff --git a/vendor/exTpl/Template.php b/lib/exTpl/Template.php similarity index 76% rename from vendor/exTpl/Template.php rename to lib/exTpl/Template.php index 9d5be04be159aa9614d743c2a586ba4963be3c7b..274e1156e34e352d38251e4dbd974137ecf54cb0 100644 --- a/vendor/exTpl/Template.php +++ b/lib/exTpl/Template.php @@ -12,8 +12,9 @@ namespace exTpl; -require_once 'Scanner.php'; -require_once 'Node.php'; +use Closure; +use InvalidArgumentException; + /** * The Template class is the only externally visible API of this @@ -22,37 +23,39 @@ require_once 'Node.php'; */ class Template { - private static $tag_start = '{'; - private static $tag_end = '}'; - private $escape; - private $functions; - private $template; + private static string $tag_start = '{'; + private static string $tag_end = '}'; + private Closure|string|null $escape = null; + private array $functions; + private ArrayNode $template; /** * Sets the delimiter strings used for the template tags, the * default delimiters are: $tag_start = '{', $tag_end = '}'. * * @param string $tag_start tag start marker - * @param string $tag_end tag end marker + * @param string $tag_end tag end marker */ - public static function setTagMarkers($tag_start, $tag_end) + public static function setTagMarkers(string $tag_start, string $tag_end): void { self::$tag_start = $tag_start; - self::$tag_end = $tag_end; + self::$tag_end = $tag_end; } /** * Initializes a new Template instance from the given string. * - * @param string $string template text + * @param string $string template text + * + * @throws TemplateParserException */ - public function __construct($string) + public function __construct(string $string) { - $this->template = new ArrayNode(); - $this->functions = array( - 'count' => function($a) { return count($a); }, - 'strlen' => function($a) { return mb_strlen($a); } - ); + $this->template = new ArrayNode(); + $this->functions = [ + 'count' => fn($a) => count($a), + 'strlen' => fn($a) => mb_strlen($a), + ]; self::parseTemplate($this->template, $string, 0); } @@ -60,9 +63,9 @@ class Template * Enables or disables automatic escaping for template values. * Currently supported strategies: NULL, 'html', 'json', 'xml' * - * @param string|callable $escape escape strategy or callback + * @param callable|string|null $escape escape strategy or callback */ - public function autoescape($escape) + public function autoescape(callable|string|null $escape): void { if ($escape === 'html' || $escape === 'xml') { $this->escape = 'htmlspecialchars'; @@ -70,8 +73,8 @@ class Template $this->escape = 'json_encode'; } else if (is_callable($escape)) { $this->escape = $escape; - } else if ($escape === NULL) { - $this->escape = NULL; + } else if ($escape === null) { + $this->escape = null; } else { throw new InvalidArgumentException("invalid escape strategy: $escape"); } @@ -81,11 +84,11 @@ class Template * Renders the template to a string using the given array of * bindings to resolve symbol references inside the template. * - * @param array $bindings symbol table + * @param array $bindings symbol table * * @return string string representation of the template */ - public function render(array $bindings) + public function render(array $bindings): string { $context = new Context($bindings + $this->functions); $context->autoescape($this->escape); @@ -96,15 +99,14 @@ class Template /** * Skips tokens until the end of the current tag is reached. * - * @param string $string template text - * @param int $pos offset in string + * @param string $string template text + * @param int $pos offset in string * - * @return int new offset in the string + * @return int new offset in the string */ - private static function skipTokens($string, $pos) + private static function skipTokens(string $string, int $pos): int { - for ($len = strlen($string); $pos < $len && - substr_compare($string, self::$tag_end, $pos, strlen(self::$tag_end)); ++$pos) { + for ($len = strlen($string); $pos < $len && substr_compare($string, self::$tag_end, $pos, strlen(self::$tag_end)); ++$pos) { $chr = $string[$pos]; if ($chr === '"' || $chr === "'") { while (++$pos < $len && $string[$pos] !== $chr) { @@ -128,8 +130,9 @@ class Template * @param int $pos offset in string * * @return int new offset in the string + * @throws TemplateParserException */ - private static function parseTemplate(ArrayNode $node, $string, $pos) + private static function parseTemplate(ArrayNode $node, string $string, int $pos): int { $len = strlen($string); @@ -147,15 +150,15 @@ class Template $node->addChild($child); } - $pos = $next_pos + strlen(self::$tag_start); + $pos = $next_pos + strlen(self::$tag_start); $next_pos = self::skipTokens($string, $pos); - $scanner = new Scanner(substr($string, $pos, $next_pos - $pos)); - $pos = $next_pos + strlen(self::$tag_end); + $scanner = new Scanner(substr($string, $pos, $next_pos - $pos)); + $pos = $next_pos + strlen(self::$tag_end); switch ($scanner->nextToken()) { case T_FOREACH: $scanner->nextToken(); - $expr = self::parseExpr($scanner); + $expr = self::parseExpr($scanner); $key_name = 'index'; $val_name = 'this'; @@ -183,15 +186,16 @@ class Template } $child = new IteratorNode($expr, $key_name, $val_name); - $pos = self::parseTemplate($child, $string, $pos); + $pos = self::parseTemplate($child, $string, $pos); $node->addChild($child); break; + case T_ENDIF: case T_ENDFOREACH: return $pos; case T_IF: $scanner->nextToken(); $child = new ConditionNode(self::parseExpr($scanner)); - $pos = self::parseTemplate($child, $string, $pos); + $pos = self::parseTemplate($child, $string, $pos); $node->addChild($child); break; case T_ELSEIF: @@ -204,8 +208,6 @@ class Template $scanner->nextToken(); $node->addElse(); break; - case T_ENDIF: - return $pos; default: $child = new ExpressionNode(self::parseExpr($scanner)); $node->addChild($child); @@ -221,8 +223,10 @@ class Template /** * value: NUMBER | STRING | SYMBOL | '(' expr ')' + * + * @throws TemplateParserException */ - private static function parseValue(Scanner $scanner) + private static function parseValue(Scanner $scanner): mixed { switch ($scanner->tokenType()) { case T_CONSTANT_ENCAPSED_STRING: @@ -251,15 +255,17 @@ class Template /** * function: value | function '(' ')' | function '(' expr { ',' expr } ')' + * + * @throws TemplateParserException */ - private static function parseFunction(Scanner $scanner) + private static function parseFunction(Scanner $scanner): mixed { $result = self::parseValue($scanner); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); while ($type === '(') { $scanner->nextToken(); - $arguments = array(); + $arguments = []; if ($scanner->tokenType() !== ')') { $arguments[] = self::parseExpr($scanner); @@ -276,7 +282,7 @@ class Template $scanner->nextToken(); $result = new FunctionExpression($result, $arguments); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); } return $result; @@ -284,11 +290,13 @@ class Template /** * index: function | index '[' expr ']' | index '.' SYMBOL + * + * @throws TemplateParserException */ - private static function parseIndex(Scanner $scanner) + private static function parseIndex(Scanner $scanner): mixed { $result = self::parseFunction($scanner); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); while ($type === '[' || $type === '.') { $scanner->nextToken(); @@ -315,11 +323,13 @@ class Template /** * filter: index | filter '|' SYMBOL | filter '|' SYMBOL '(' expr { ',' expr } ')' + * + * @throws TemplateParserException */ - private static function parseFilter(Scanner $scanner) + private static function parseFilter(Scanner $scanner): mixed { $result = self::parseIndex($scanner); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); while ($type === '|') { $scanner->nextToken(); @@ -328,8 +338,8 @@ class Template throw new TemplateParserException('symbol expected', $scanner); } - $arguments = array($result); - $symbol = new SymbolExpression($scanner->tokenValue()); + $arguments = [$result]; + $symbol = new SymbolExpression($scanner->tokenValue()); $scanner->nextToken(); if ($scanner->tokenType() === '(') { @@ -365,8 +375,10 @@ class Template /** * sign: '!' sign | '+' sign | '-' sign | filter + * + * @throws TemplateParserException */ - private static function parseSign(Scanner $scanner) + private static function parseSign(Scanner $scanner): mixed { switch ($scanner->tokenType()) { case '!': @@ -390,16 +402,18 @@ class Template /** * product: sign | product '*' sign | product '/' sign | product '%' sign + * + * @throws TemplateParserException */ - private static function parseProduct(Scanner $scanner) + private static function parseProduct(Scanner $scanner): mixed { $result = self::parseSign($scanner); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); while ($type === '*' || $type === '/' || $type === '%') { $scanner->nextToken(); $result = new ArithExpression($result, self::parseSign($scanner), $type); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); } return $result; @@ -407,16 +421,18 @@ class Template /** * sum: product | sum '+' product | sum '-' product | sum '~' product + * + * @throws TemplateParserException */ - private static function parseSum(Scanner $scanner) + private static function parseSum(Scanner $scanner): mixed { $result = self::parseProduct($scanner); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); while ($type === '+' || $type === '-' || $type === '~') { $scanner->nextToken(); $result = new ArithExpression($result, self::parseProduct($scanner), $type); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); } return $result; @@ -425,17 +441,19 @@ class Template /** * lt_gt: sum | lt_gt '<' concat | lt_gt IS_SMALLER_OR_EQUAL concat * | lt_gt '>' concat | lt_gt IS_GREATER_OR_EQUAL concat + * + * @throws TemplateParserException */ - private static function parseLtGt(Scanner $scanner) + private static function parseLtGt(Scanner $scanner): mixed { $result = self::parseSum($scanner); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); while ($type === '<' || $type === T_IS_SMALLER_OR_EQUAL || - $type === '>' || $type === T_IS_GREATER_OR_EQUAL) { + $type === '>' || $type === T_IS_GREATER_OR_EQUAL) { $scanner->nextToken(); $result = new BooleanExpression($result, self::parseSum($scanner), $type); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); } return $result; @@ -443,16 +461,18 @@ class Template /** * cmp: lt_gt | cmp IS_EQUAL lt_gt | cmp IS_NOT_EQUAL lt_gt + * + * @throws TemplateParserException */ - private static function parseCmp(Scanner $scanner) + private static function parseCmp(Scanner $scanner): mixed { $result = self::parseLtGt($scanner); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); while ($type === T_IS_EQUAL || $type === T_IS_NOT_EQUAL) { $scanner->nextToken(); $result = new BooleanExpression($result, self::parseLtGt($scanner), $type); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); } return $result; @@ -460,16 +480,18 @@ class Template /** * and: cmp | and BOOLEAN_AND cmp + * + * @throws TemplateParserException */ - private static function parseAnd(Scanner $scanner) + private static function parseAnd(Scanner $scanner): mixed { $result = self::parseCmp($scanner); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); while ($type === T_BOOLEAN_AND) { $scanner->nextToken(); $result = new BooleanExpression($result, self::parseCmp($scanner), $type); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); } return $result; @@ -477,16 +499,18 @@ class Template /** * or: and | or BOOLEAN_OR and + * + * @throws TemplateParserException */ - private static function parseOr(Scanner $scanner) + private static function parseOr(Scanner $scanner): mixed { $result = self::parseAnd($scanner); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); while ($type === T_BOOLEAN_OR) { $scanner->nextToken(); $result = new BooleanExpression($result, self::parseAnd($scanner), $type); - $type = $scanner->tokenType(); + $type = $scanner->tokenType(); } return $result; @@ -494,8 +518,10 @@ class Template /** * expr: or | or '?' expr ':' expr | or '?' ':' expr + * + * @throws TemplateParserException */ - private static function parseExpr(Scanner $scanner) + private static function parseExpr(Scanner $scanner): mixed { $result = self::parseOr($scanner); @@ -519,17 +545,3 @@ class Template return $result; } } - -/** - * Exception class used to report template parse errors. - */ -class TemplateParserException extends \Exception -{ - public function __construct($message, $scanner) - { - $type = $scanner->tokenType(); - $value = is_int($type) ? $scanner->tokenValue() : $type; - - return parent::__construct("$message at \"$value\""); - } -} diff --git a/lib/exTpl/TemplateParserException.php b/lib/exTpl/TemplateParserException.php new file mode 100644 index 0000000000000000000000000000000000000000..2c7abf88f7227ead22c66161d3904c829aa61c89 --- /dev/null +++ b/lib/exTpl/TemplateParserException.php @@ -0,0 +1,19 @@ +<?php + +namespace exTpl; + +use Exception; + +/** + * Exception class used to report template parse errors. + */ +class TemplateParserException extends Exception +{ + public function __construct(string $message, Scanner $scanner) + { + $type = $scanner->tokenType(); + $value = is_int($type) ? $scanner->tokenValue() : $type; + + return parent::__construct("$message at \"$value\""); + } +} diff --git a/lib/exTpl/TextNode.php b/lib/exTpl/TextNode.php new file mode 100644 index 0000000000000000000000000000000000000000..053cafc04dc28746f96e2b18638e4e897ec34bdb --- /dev/null +++ b/lib/exTpl/TextNode.php @@ -0,0 +1,31 @@ +<?php + +namespace exTpl; + +/** + * TextNode represents a verbatim text segment. + */ +class TextNode implements Node +{ + protected string $text; + + /** + * Initializes a new Node instance with the given text. + * + * @param string $text verbatim text + */ + public function __construct(string $text) + { + $this->text = $text; + } + + /** + * Returns a string representation of this node. + * + * @param Context $context symbol table + */ + public function render(Context $context): string + { + return $this->text; + } +} diff --git a/lib/exTpl/UnaryExpression.php b/lib/exTpl/UnaryExpression.php new file mode 100644 index 0000000000000000000000000000000000000000..997931160793fccb3fa5ad7fa7fd0d639da6c709 --- /dev/null +++ b/lib/exTpl/UnaryExpression.php @@ -0,0 +1,21 @@ +<?php + +namespace exTpl; + +/** + * UnaryExpression represents a unary operator. + */ +abstract class UnaryExpression implements Expression +{ + protected Expression $expr; + + /** + * Initializes a new Expression instance. + * + * @param Expression $expr expression object + */ + public function __construct(Expression $expr) + { + $this->expr = $expr; + } +} diff --git a/lib/extern/ExternPage.php b/lib/extern/ExternPage.php index d775bc4ac59658ea8dbeef8de0964f8d50e9fdf8..308caebad8b82624f9af234acc1f508050487f3e 100644 --- a/lib/extern/ExternPage.php +++ b/lib/extern/ExternPage.php @@ -13,8 +13,6 @@ * @since 5.4 */ -require_once 'vendor/exTpl/Template.php'; - abstract class ExternPage { /** diff --git a/tests/unit/_bootstrap.php b/tests/unit/_bootstrap.php index e5299a6df17e6a12123e3297f6ea6037780066a5..3aa1144f66872c84576d8bea631eee01ee697c72 100644 --- a/tests/unit/_bootstrap.php +++ b/tests/unit/_bootstrap.php @@ -53,6 +53,7 @@ StudipAutoloader::addAutoloadPath('lib/activities', 'Studip\\Activity'); StudipAutoloader::addAutoloadPath('lib/models'); StudipAutoloader::addAutoloadPath('lib/classes'); StudipAutoloader::addAutoloadPath('lib/classes', 'Studip'); +StudipAutoloader::addAutoloadPath('lib/exTpl', 'exTpl'); StudipAutoloader::addAutoloadPath('lib/exceptions'); StudipAutoloader::addAutoloadPath('lib/classes/sidebar'); StudipAutoloader::addAutoloadPath('lib/classes/helpbar'); diff --git a/vendor/exTpl/template_test.php b/tests/unit/lib/classes/extTPLTemplateTest.php similarity index 98% rename from vendor/exTpl/template_test.php rename to tests/unit/lib/classes/extTPLTemplateTest.php index 62aee1c555bc18a4cdbee81784e2c76b53bda429..43a9629c948135f88e3b5c990681592745ab5d42 100644 --- a/vendor/exTpl/template_test.php +++ b/tests/unit/lib/classes/extTPLTemplateTest.php @@ -10,15 +10,13 @@ * the License, or (at your option) any later version. */ -require 'Template.php'; - use exTpl\Template; -class template_test extends PHPUnit\Framework\TestCase +class extTplTemplateTest extends \Codeception\Test\Unit { public function testSimpleString() { - $bindings = array(); + $bindings = []; $template = 'The quick brown fox jumps over the layz dog.'; $expected = $template; $tmpl_obj = new Template($template); diff --git a/vendor/exTpl/Expression.php b/vendor/exTpl/Expression.php deleted file mode 100644 index 35ea4581001f316024ae8f380cd237b3b3c503c0..0000000000000000000000000000000000000000 --- a/vendor/exTpl/Expression.php +++ /dev/null @@ -1,329 +0,0 @@ -<?php -/* - * Expression.php - template parser expression interface and classes - * - * Copyright (c) 2013 Elmar Ludwig - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -namespace exTpl; - -/** - * Basic interface for expressions in the template parse tree. The - * only required method is "value" to get the expression's value. - */ -interface Expression -{ - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context); -} - -/** - * ConstantExpression represents a literal value. - */ -class ConstantExpression implements Expression -{ - protected $value; - - /** - * Initializes a new Expression instance. - * - * @param mixed $value expression value - */ - public function __construct($value) - { - $this->value = $value; - } - - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context) - { - return $this->value; - } -} - -/** - * SymbolExpression represents a symbol (template variable). - */ -class SymbolExpression implements Expression -{ - protected $name; - - /** - * Initializes a new Expression instance. - * - * @param string $name symbol name - */ - public function __construct($name) - { - $this->name = $name; - } - - /** - * Returns the name of this symbol. - */ - public function name() - { - return $this->name; - } - - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context) - { - return $context->lookup($this->name); - } -} - -/** - * UnaryExpression represents a unary operator. - */ -abstract class UnaryExpression implements Expression -{ - protected $expr; - - /** - * Initializes a new Expression instance. - * - * @param Expression $expr expression object - */ - public function __construct(Expression $expr) - { - $this->expr = $expr; - } -} - -/** - * MinusExpression represents the unary minus operator ('-'). - */ -class MinusExpression extends UnaryExpression -{ - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context) - { - return -$this->expr->value($context); - } -} - -/** - * NotExpression represents the logical negation operator ('!'). - */ -class NotExpression extends UnaryExpression -{ - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context) - { - return !$this->expr->value($context); - } -} - -/** - * RawExpression represents the "raw" filter function. - */ -class RawExpression extends UnaryExpression -{ - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context) - { - return $this->expr->value($context); - } -} - -/** - * BinaryExpression represents a binary operator. - */ -abstract class BinaryExpression implements Expression -{ - protected $left, $right; - protected $operator; - - /** - * Initializes a new Expression instance. - * - * @param Expression $left left operand - * @param Expression $right right operand - * @param mixed $operator operator token - */ - public function __construct(Expression $left, Expression $right, $operator) - { - $this->left = $left; - $this->right = $right; - $this->operator = $operator; - } -} - -/** - * ArithExpression represents an arithmetic operator. - */ -class ArithExpression extends BinaryExpression -{ - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context) - { - $left = $this->left->value($context); - $right = $this->right->value($context); - - switch ($this->operator) { - case '+': return $left + $right; - case '-': return $left - $right; - case '*': return $left * $right; - case '/': return $left / $right; - case '%': return $left % $right; - case '~': return $left . $right; - } - } -} - -/** - * IndexExpression represents the array index operator. - */ -class IndexExpression extends BinaryExpression -{ - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context) - { - $left = $this->left->value($context); - $right = $this->right->value($context); - - return $left[$right]; - } -} - -/** - * BooleanExpression represents a boolean operator. - */ -class BooleanExpression extends BinaryExpression -{ - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context) - { - $left = $this->left->value($context); - $right = $this->right->value($context); - - switch ($this->operator) { - case T_IS_EQUAL : return $left == $right; - case T_IS_NOT_EQUAL : return $left != $right; - case '<' : return $left < $right; - case T_IS_SMALLER_OR_EQUAL: return $left <= $right; - case '>' : return $left > $right; - case T_IS_GREATER_OR_EQUAL: return $left >= $right; - case T_BOOLEAN_AND : return $left && $right; - case T_BOOLEAN_OR : return $left || $right; - } - } -} - -/** - * ConditionExpression represents the conditional operator ('?:'). - */ -class ConditionExpression implements Expression -{ - protected $condition; - protected $left, $right; - - /** - * Initializes a new Expression instance. - * - * @param Expression $condition expression - * @param Expression $left left alternative - * @param Expression $right right alternative - */ - public function __construct($condition, $left, $right) - { - $this->condition = $condition; - $this->left = $left; - $this->right = $right; - } - - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context) - { - return $this->condition->value($context) ? - $this->left->value($context) : $this->right->value($context); - } -} - -/** - * FunctionExpression represents a function call. - */ -class FunctionExpression implements Expression -{ - protected $name; - protected $arguments; - - /** - * Initializes a new Expression instance. - * - * @param Expression $name function name - * @param array $arguments function arguments - */ - public function __construct(Expression $name, $arguments) - { - $this->name = $name; - $this->arguments = $arguments; - } - - /** - * Returns the value of this expression. - * - * @param Context $context symbol table - */ - public function value($context) - { - $callable = $this->name->value($context); - $arguments = array(); - - foreach ($this->arguments as $expr) { - $arguments[] = $expr->value($context); - } - - if ($callable instanceof \Closure) { - return call_user_func_array($callable, $arguments); - } - - return NULL; - } -} diff --git a/vendor/exTpl/Node.php b/vendor/exTpl/Node.php deleted file mode 100644 index 0dbd9463d0ca8ff308b8077efed076c81018ecc1..0000000000000000000000000000000000000000 --- a/vendor/exTpl/Node.php +++ /dev/null @@ -1,234 +0,0 @@ -<?php -/* - * Node.php - template parser node interface and classes - * - * Copyright (c) 2013 Elmar Ludwig - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -namespace exTpl; - -require_once 'Context.php'; -require_once 'Expression.php'; - -/** - * Basic interface for nodes in the template parse tree. The only - * required method is "render" to render a node and its children. - */ -interface Node -{ - /** - * Returns a string representation of this node. - * - * @param Context $context symbol table - */ - public function render($context); -} - -/** - * TextNode represents a verbatim text segment. - */ -class TextNode implements Node -{ - protected $text; - - /** - * Initializes a new Node instance with the given text. - * - * @param string $text verbatim text - */ - public function __construct($text) - { - $this->text = $text; - } - - /** - * Returns a string representation of this node. - * - * @param Context $context symbol table - */ - public function render($context) - { - return $this->text; - } -} - -/** - * ExpressionNode represents an expression tag: "{...}". - */ -class ExpressionNode implements Node -{ - protected $expr; - - /** - * Initializes a new Node instance with the given expression. - * - * @param Expression $expr expression object - */ - public function __construct(Expression $expr) - { - $this->expr = $expr; - } - - /** - * Returns a string representation of this node. - * - * @param Context $context symbol table - */ - public function render($context) - { - $value = $this->expr->value($context); - - if (!($this->expr instanceof RawExpression)) { - $value = $context->escape($value); - } - - return $value; - } -} - -/** - * ArrayNode represents a sequence of arbitrary nodes. - */ -class ArrayNode implements Node -{ - protected $nodes = array(); - - /** - * Adds a child node to this sequence node. - * - * @param Node $node child node to add - */ - public function addChild(Node $node) - { - $this->nodes[] = $node; - } - - /** - * Returns a string representation of this node. - * - * @param Context $context symbol table - */ - public function render($context) - { - $result = ''; - - foreach ($this->nodes as $node) { - $result .= $node->render($context); - } - - return $result; - } -} - -/** - * IteratorNode represents a single iterator tag: - * "{foreach ARRAY [as [KEY =>] VALUE]}...{endforeach}". - */ -class IteratorNode extends ArrayNode -{ - protected $expr; - protected $key_name; - protected $val_name; - - /** - * Initializes a new Node instance with the given expression. - * - * @param Expression $expr expression object - * @param string $key_name name of variable on each iteration - * @param string $val_name name of variable on each iteration - */ - public function __construct(Expression $expr, $key_name, $val_name) - { - $this->expr = $expr; - $this->key_name = $key_name; - $this->val_name = $val_name; - } - - /** - * Returns a string representation of this node. The IteratorNode - * renders the node sequence for each value in the expression list. - * - * @param Context $context symbol table - */ - public function render($context) - { - $values = $this->expr->value($context); - $result = ''; - - if (is_array($values) && is_int(key($values))) { - $bindings = array($this->key_name => &$key, $this->val_name => &$value); - $context = new Context($bindings, $context); - - foreach ($values as $key => $value) { - $result .= parent::render(new Context($value, $context)); - } - } else if (is_array($values) && count($values)) { - return parent::render(new Context($values, $context)); - } else if ($values) { - return parent::render($context); - } - - return $result; - } -} - -/** - * ConditionNode represents a single condition tag: - * "{if CONDITION}...{else}...{endif}". - */ -class ConditionNode extends ArrayNode -{ - protected $condition; - protected $else_node; - - /** - * Initializes a new Node instance with the given expression. - * - * @param Expression $condition expression object - */ - public function __construct(Expression $condition) - { - $this->condition = $condition; - } - - /** - * Adds an else block to this condition node. - */ - public function addElse() - { - $this->else_node = new ArrayNode(); - } - - /** - * Adds a child node to this condition node. - * - * @param Node $node child node to add - */ - public function addChild(Node $node) - { - if ($this->else_node) { - $this->else_node->addChild($node); - } else { - parent::addChild($node); - } - } - - /** - * Returns a string representation of this node. - * - * @param Context $context symbol table - */ - public function render($context) - { - if ($this->condition->value($context)) { - return parent::render($context); - } - - return $this->else_node ? $this->else_node->render($context) : ''; - } -} diff --git a/vendor/exTpl/Scanner.php b/vendor/exTpl/Scanner.php deleted file mode 100644 index b2464fbb4410a31dc82c68e70fa2d7e34fe7f184..0000000000000000000000000000000000000000 --- a/vendor/exTpl/Scanner.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php -/* - * Scanner.php - template parser lexical scanner - * - * Copyright (c) 2013 Elmar Ludwig - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -namespace exTpl; - -/** - * Simple wrapper class around the Zend engine's lexical scanner. It - * automatically skips whitespace and offers an interator interface. - */ -class Scanner -{ - private $tokens; - private $token_type; - private $token_value; - - /** - * Initializes a new Scanner instance for the given text. - * - * @param string $text string to parse - */ - public function __construct($text) - { - $this->tokens = token_get_all('<?php ' . $text); - } - - /** - * Advances the scanner to the next token and returns its token type. - * The valid token types are those defined for token_get_all() in the - * PHP documentation. Returns false when the end of input is reached. - */ - public function nextToken() - { - do { - $token = next($this->tokens); - $key = key($this->tokens); - - // FIXME this workaround should be dropped - while ($token && $token[0] === T_STRING && - isset($this->tokens[$key + 2]) && - $this->tokens[++$key] === '-' && - $this->tokens[++$key][0] === T_STRING) { - $token[1] .= '-' . $this->tokens[$key][1]; - next($this->tokens); - next($this->tokens); - } - } while (is_array($token) && $token[0] === T_WHITESPACE); - - if (is_string($token) || $token === false) { - $this->token_type = $token; - $this->token_value = NULL; - } else { - $this->token_type = $token[0]; - - switch ($token[0]) { - case T_CONSTANT_ENCAPSED_STRING: - $this->token_value = stripcslashes(substr($token[1], 1, -1)); - break; - case T_DNUMBER: - $this->token_value = (double) $token[1]; - break; - case T_LNUMBER: - $this->token_value = (int) $token[1]; - break; - default: - $this->token_value = $token[1]; - } - } - - return $this->token_type; - } - - /** - * Returns the current token type. The valid token types are - * those defined for token_get_all() in the PHP documentation. - */ - public function tokenType() - { - return $this->token_type; - } - - /** - * Returns the current token value if the token type supports - * a value (T_STRING, T_LNUMBER etc.). Returns NULL otherwise. - */ - public function tokenValue() - { - return $this->token_value; - } -}