diff options
| author | Laria Carolin Chabowski <laria@laria.me> | 2020-05-01 17:33:13 +0200 | 
|---|---|---|
| committer | Laria Carolin Chabowski <laria@laria.me> | 2020-05-01 17:33:13 +0200 | 
| commit | 7449faaa76a5b4008fd51a6562cca2e0a852ea6b (patch) | |
| tree | 9e6bc34afe9e4e7d49b1a26f0b67485869b0a9de /src/ste | |
| parent | b0c9a4aeb61aff8a8fa60746cd566e6dbe05a3b5 (diff) | |
| download | ste-7449faaa76a5b4008fd51a6562cca2e0a852ea6b.tar.gz ste-7449faaa76a5b4008fd51a6562cca2e0a852ea6b.tar.bz2 ste-7449faaa76a5b4008fd51a6562cca2e0a852ea6b.zip | |
Clean up code and improve documentation
This switches the code documentation genarator (we're now using phpdoc
instead of NaturalDoc).
Also various small code cleanup tasks:
- Remove unused code
- Get rid of `and` / `or`, we're using `&&` / `||` now
- Adding missing return values
- Helping PhpStorm to detect some dynamically called functions
  (mark_builtin_callable in Transcompiler)
- Reword transcompiling => compiling in documentation
Diffstat (limited to 'src/ste')
| -rw-r--r-- | src/ste/ASTNode.php | 8 | ||||
| -rw-r--r-- | src/ste/Calc.php | 48 | ||||
| -rw-r--r-- | src/ste/CantLoadTemplate.php | 8 | ||||
| -rw-r--r-- | src/ste/CantSaveTemplate.php | 8 | ||||
| -rw-r--r-- | src/ste/FatalRuntimeError.php | 6 | ||||
| -rw-r--r-- | src/ste/FilesystemStorageAccess.php | 28 | ||||
| -rw-r--r-- | src/ste/Misc.php | 4 | ||||
| -rw-r--r-- | src/ste/ParseCompileError.php | 8 | ||||
| -rw-r--r-- | src/ste/Parser.php | 114 | ||||
| -rw-r--r-- | src/ste/RuntimeError.php | 8 | ||||
| -rw-r--r-- | src/ste/STECore.php | 177 | ||||
| -rw-r--r-- | src/ste/STEStandardLibrary.php | 74 | ||||
| -rw-r--r-- | src/ste/Scope.php | 39 | ||||
| -rw-r--r-- | src/ste/StorageAccess.php | 51 | ||||
| -rw-r--r-- | src/ste/TagNode.php | 11 | ||||
| -rw-r--r-- | src/ste/TextNode.php | 7 | ||||
| -rw-r--r-- | src/ste/Transcompiler.php | 181 | ||||
| -rw-r--r-- | src/ste/VariableNode.php | 13 | 
18 files changed, 593 insertions, 200 deletions
| diff --git a/src/ste/ASTNode.php b/src/ste/ASTNode.php index 2163161..3e74635 100644 --- a/src/ste/ASTNode.php +++ b/src/ste/ASTNode.php @@ -4,8 +4,16 @@ namespace kch42\ste;  abstract class ASTNode  { +    /** @var string */      public $tpl; + +    /** @var int */      public $offset; + +    /** +     * @param string $tpl +     * @param int $off +     */      public function __construct($tpl, $off)      {          $this->tpl    = $tpl; diff --git a/src/ste/Calc.php b/src/ste/Calc.php index 64d2b7a..2f2d09d 100644 --- a/src/ste/Calc.php +++ b/src/ste/Calc.php @@ -2,15 +2,25 @@  namespace kch42\ste; -/* Class Calc contains static methods needed by <ste:calc /> */ +/** + * Class Calc contains static methods needed by <ste:calc /> + */  class Calc  {      private function __construct()      {      } -    /* We could also just eval() the $infix_math code, but this is much cooler :-D (Parser inception) */ -    public static function shunting_yard($infix_math) +    /** +     * Parse a mathematical expression with the shunting yard algorithm (https://en.wikipedia.org/wiki/Shunting-yard_algorithm) +     * +     * We could also just eval() the $infix_math code, but this is much cooler :-D (Parser inception) + +     * @param string $infix_math +     * @return array +     * @throws RuntimeError +     */ +    private static function shunting_yard($infix_math)      {          $operators = array(              "+" => array("l", 2), @@ -68,11 +78,17 @@ class Calc              } else {                  $priority = $operators[$token][1];                  if ($operators[$token][0] == "l") { -                    while ((!empty($op_stack)) and ($priority <= $operators[$op_stack[count($op_stack)-1]][1])) { +                    while ( +                        !empty($op_stack) +                        && $priority <= $operators[$op_stack[count($op_stack)-1]][1] +                    ) {                          $output_queue[] = array_pop($op_stack);                      }                  } else { -                    while ((!empty($op_stack)) and ($priority < $operators[$op_stack[count($op_stack)-1]][1])) { +                    while ( +                        !empty($op_stack) +                        && $priority < $operators[$op_stack[count($op_stack)-1]][1] +                    ) {                          $output_queue[] = array_pop($op_stack);                      }                  } @@ -91,7 +107,12 @@ class Calc          return $output_queue;      } -    public static function pop2(&$array) +    /** +     * @param array $array +     * @return array +     * @throws RuntimeError +     */ +    private static function pop2(&$array)      {          $rv = array(array_pop($array), array_pop($array));          if (array_search(null, $rv, true) !== false) { @@ -100,7 +121,12 @@ class Calc          return $rv;      } -    public static function calc_rpn($rpn) +    /** +     * @param array $rpn A mathematical expression in reverse polish notation +     * @return int|float +     * @throws RuntimeError +     */ +    private static function calc_rpn($rpn)      {          $stack = array();          foreach ($rpn as $token) { @@ -140,6 +166,14 @@ class Calc          return array_pop($stack);      } +    /** +     * Calculate a simple mathematical expression. Supported operators are +, -, *, /, ^. +     * You can use ( and ) to group expressions together. +     * +     * @param string $expr +     * @return float|int +     * @throws RuntimeError +     */      public static function calc($expr)      {          return self::calc_rpn(self::shunting_yard($expr)); diff --git a/src/ste/CantLoadTemplate.php b/src/ste/CantLoadTemplate.php index 20200d6..92604cc 100644 --- a/src/ste/CantLoadTemplate.php +++ b/src/ste/CantLoadTemplate.php @@ -1,13 +1,9 @@  <?php -// File: CantLoadTemplate.php - -// Namespace: kch42\ste  namespace kch42\ste; -/* - * Class: CantLoadTemplate - * An exception that a <StorageAccess> implementation can throw, if it is unable to load a template. +/** + * An exception that a {@see StorageAccess} implementation can throw, if it is unable to load a template.   */  class CantLoadTemplate extends StorageAccessFailure  { diff --git a/src/ste/CantSaveTemplate.php b/src/ste/CantSaveTemplate.php index edbb93e..92cdfe7 100644 --- a/src/ste/CantSaveTemplate.php +++ b/src/ste/CantSaveTemplate.php @@ -1,13 +1,9 @@  <?php -// File: CantSaveTemplate.php - -// Namespace: kch42\ste  namespace kch42\ste; -/* - * Class: CantSaveTemplate - * An exception that a <StorageAccess> implementation can throw, if it is unable to save a template. +/** + * An exception that a {@see StorageAccess} implementation can throw, if it is unable to save a template.   */  class CantSaveTemplate extends StorageAccessFailure  { diff --git a/src/ste/FatalRuntimeError.php b/src/ste/FatalRuntimeError.php index ab40af5..3f5183f 100644 --- a/src/ste/FatalRuntimeError.php +++ b/src/ste/FatalRuntimeError.php @@ -1,12 +1,8 @@  <?php -// File: FatalRuntimeError.php - -// Namespace: kch42\ste  namespace kch42\ste; -/* - * Class: FatalRuntimeError +/**   * An Exception a tag can throw, if a fatal (irreparable) runtime error occurred.   * This Exception will always "bubble up" so you probably want to catch them. Remember that this exception is also in the namespace ste!   */ diff --git a/src/ste/FilesystemStorageAccess.php b/src/ste/FilesystemStorageAccess.php index d477e36..cb2fe7f 100644 --- a/src/ste/FilesystemStorageAccess.php +++ b/src/ste/FilesystemStorageAccess.php @@ -1,25 +1,21 @@  <?php -// File: FilesystemStorageAccess.php - -// Namespace: kch42\ste  namespace kch42\ste; -/* - * Class: FilesystemStorageAccess - * The default <StorageAccess> implementation for loading / saving templates into a directory structure. +/** + * The default {@see StorageAccess} implementation for loading / saving templates into a directory structure.   */  class FilesystemStorageAccess implements StorageAccess  { +    /** @var string */      protected $sourcedir; + +    /** @var string */      protected $transcompileddir; -    /* -     * Constructor: __construct -     * -     * Parameters: -     *  $src - The directory with the sources (Writing permissions are not mandatory, because STE does not save template sources). -     *  $transc - The directory with the transcompiled templates (the PHP instance / the HTTP Server needs writing permissions to this directory). +    /** +     * @param string $src - The directory with the sources (Writing permissions are not mandatory, because STE does not save template sources). +     * @param string $transc - The directory with the compiled templates (the PHP instance / the HTTP Server needs writing permissions to this directory).       */      public function __construct($src, $transc)      { @@ -43,13 +39,16 @@ class FilesystemStorageAccess implements StorageAccess          $src_stat    = @stat($src_fn);          $transc_stat = @stat($transc_fn); -        if (($src_stat === false) and ($transc_stat === false)) { +        if ($src_stat === false && $transc_stat === false) {              throw new CantLoadTemplate("Template not found.");          } elseif ($transc_stat === false) {              $mode = StorageAccess::MODE_SOURCE;              return file_get_contents($src_fn);          } elseif ($src_stat === false) {              include($transc_fn); +            if (!isset($transcompile_fx)) { +                throw new CantLoadTemplate("Compiled template file $transc_fn does not set \$transcompile_fx"); +            }              return $transcompile_fx;          } else {              if ($src_stat["mtime"] > $transc_stat["mtime"]) { @@ -57,6 +56,9 @@ class FilesystemStorageAccess implements StorageAccess                  return file_get_contents($src_fn);              } else {                  include($transc_fn); +                if (!isset($transcompile_fx)) { +                    throw new CantLoadTemplate("Compiled template file $transc_fn does not set \$transcompile_fx"); +                }                  return $transcompile_fx;              }          } diff --git a/src/ste/Misc.php b/src/ste/Misc.php index d017ee3..330b3d2 100644 --- a/src/ste/Misc.php +++ b/src/ste/Misc.php @@ -4,6 +4,10 @@ namespace kch42\ste;  class Misc  { +    /** +     * @param string $text +     * @return string +     */      public static function escape_text($text)      {          return addcslashes($text, "\r\n\t\$\0..\x1f\\\"\x7f..\xff"); diff --git a/src/ste/ParseCompileError.php b/src/ste/ParseCompileError.php index f5f0272..29590da 100644 --- a/src/ste/ParseCompileError.php +++ b/src/ste/ParseCompileError.php @@ -2,6 +2,9 @@  namespace kch42\ste; +/** + * An exception thrown by the parser or compiler + */  class ParseCompileError extends \Exception  {      public $msg; @@ -16,10 +19,13 @@ class ParseCompileError extends \Exception          $this->message = "$msg (Template $tpl, Offset $offset)";      } +    /** +     * Update the message to include a human readable offset. +     * @param string $code +     */      public function rewrite($code)      {          $line = substr_count(str_replace("\r\n", "\n", substr($code, 0, $this->off)), "\n") + 1;          $this->message = "{$this->msg} (Template {$this->tpl}, Line $line)"; -        $this->is_rewritten = true;      }  } diff --git a/src/ste/Parser.php b/src/ste/Parser.php index 40f5f20..0280f6d 100644 --- a/src/ste/Parser.php +++ b/src/ste/Parser.php @@ -1,20 +1,25 @@  <?php -// File: Parser.php - -// Namespace: kch42\ste  namespace kch42\ste; -/* - * Class: Parser +use LogicException; + +/**   * The class, where the parser lives in. Can not be constructed manually.   * Use the static method parse.   */  class Parser  { +    /** @var string */      private $text; + +    /** @var string */      private $name; + +    /** @var int */      private $off; + +    /** @var int */      private $len;      const PARSE_SHORT = 1; @@ -22,6 +27,10 @@ class Parser      const ESCAPES_DEFAULT = '$?~{}|\\'; +    /** +     * @param string $text +     * @param string $name +     */      private function __construct($text, $name)      {          $this->text = $text; @@ -30,6 +39,10 @@ class Parser          $this->len  = mb_strlen($text);      } +    /** +     * @param int $n +     * @return string +     */      private function next($n = 1)      {          if ($n <= 0) { @@ -40,11 +53,17 @@ class Parser          return $c;      } +    /** +     * @return bool +     */      private function eof()      {          return ($this->off == $this->len);      } +    /** +     * @param int $n +     */      private function back($n = 1)      {          if ($n <= 0) { @@ -53,11 +72,19 @@ class Parser          $this->off = max($this->off - $n, 0);      } +    /** +     * @param string $needle +     * @return false|int +     */      private function search_off($needle)      {          return mb_strpos($this->text, $needle, $this->off);      } +    /** +     * @param string[] $needles +     * @return array 4-tuple of found key, offset, text preceding offset, old offset +     */      private function search_multi($needles)      {          $oldoff = $this->off; @@ -81,6 +108,10 @@ class Parser          return array($which, $minoff, mb_substr($this->text, $oldoff, $minoff - $oldoff), $oldoff);      } +    /** +     * @param string $needle +     * @return array 3-tuple of offset (or false), text preceding offset, old offset +     */      private function search($needle)      {          $oldoff = $this->off; @@ -95,7 +126,11 @@ class Parser          return array($off, mb_substr($this->text, $oldoff, $off - $oldoff), $oldoff);      } -    private function take_while($cb) +    /** +     * @param callable $cb +     * @return string +     */ +    private function take_while(callable $cb)      {          $s = "";          while (($c = $this->next()) !== "") { @@ -113,6 +148,10 @@ class Parser          $this->take_while("ctype_space");      } +    /** +     * @return string +     * @throws ParseCompileError +     */      private function get_name()      {          $off = $this->off; @@ -125,21 +164,16 @@ class Parser          return $name;      } -    /* -     * Function: parse +    /**       * Parses the input into an AST.       * -     * You only need this function, if you want to manually trnascompile a template. +     * You only need this function, if you want to manually compile a template.       * -     * Parameters: -     *  $text - The input code. -     *  $name - The name of the template. +     * @param string $text The input code. +     * @param string $name The name of the template.       * -     * Returns: -     *  An array of <ASTNode> objects. -     * -     * Throws: -     *  <ParseCompileError> +     * @return ASTNode[] +     * @throws ParseCompileError       */      public static function parse($text, $name)      { @@ -151,10 +185,15 @@ class Parser          return self::tidyup_ast($res[0]);      } +    /** +     * @param ASTNode[] $ast +     * @return ASTNode[] +     */      private static function tidyup_ast($ast)      {          $out = array(); +        /** @var TextNode|null $prevtext */          $prevtext = null;          $first = true; @@ -206,6 +245,17 @@ class Parser          return $out;      } +    /** +     * @param string $escapes +     * @param int $flags +     * @param string|null $breakon +     * @param string|null $separator +     * @param null $nullaction +     * @param string|null $opentag +     * @param int $openedat +     * @return ASTNode[][] +     * @throws ParseCompileError +     */      private function parse_text($escapes, $flags, $breakon = null, $separator = null, $nullaction = null, $opentag = null, $openedat = -1)      {          $elems = array(); @@ -250,14 +300,14 @@ class Parser                  }                  break;              case "commentopen": -                list($off, $before, $offbefore) = $this->search("</ste:comment>"); +                list($off, , $offbefore) = $this->search("</ste:comment>");                  if ($off === false) {                      throw new ParseCompileError("ste:comment was not closed", $this->name, $offbefore);                  }                  break;              case "rawopen":                  $off_start = $off; -                list($off, $before, $offbefore) = $this->search("</ste:rawtext>"); +                list($off, $before, ) = $this->search("</ste:rawtext>");                  if ($off === false) {                      throw new ParseCompileError("ste:rawtext was not closed", $this->name, $off_start);                  } @@ -352,6 +402,12 @@ class Parser          return $elems;      } +    /** +     * @param string $shortname +     * @param int $openedat +     * @return ASTNode[][] +     * @throws ParseCompileError +     */      private function parse_short($shortname, $openedat)      {          $tplname = $this->name; @@ -369,6 +425,12 @@ class Parser          );      } +    /** +     * @param int $openedat +     * @param bool $curly +     * @return VariableNode +     * @throws ParseCompileError +     */      private function parse_var($openedat, $curly)      {          $varnode = new VariableNode($this->name, $openedat); @@ -377,12 +439,16 @@ class Parser              $varnode->arrayfields = $this->parse_array();          } -        if (($curly) && ($this->next() != "}")) { +        if ($curly && ($this->next() != "}")) {              throw new ParseCompileError("Unclosed '\${'", $this->name, $openedat);          }          return $varnode;      } +    /** +     * @return ASTNode[] +     * @throws ParseCompileError +     */      private function parse_array()      {          $tplname = $this->name; @@ -409,6 +475,11 @@ class Parser          return $arrayfields;      } +    /** +     * @param int $openedat +     * @return TagNode +     * @throws ParseCompileError +     */      private function parse_tag($openedat)      {          $tplname = $this->name; @@ -475,5 +546,8 @@ class Parser                  $tag->params[$param] = $paramval[0];              }          } + +        // Help PhpStorm detect that we shouldn't be here +        throw new LogicException("Somehow we left the infinite loop?");      }  } diff --git a/src/ste/RuntimeError.php b/src/ste/RuntimeError.php index dace1d4..51fd29d 100644 --- a/src/ste/RuntimeError.php +++ b/src/ste/RuntimeError.php @@ -1,14 +1,10 @@  <?php -// File: RuntimeError.php - -// Namespace: kch42\ste  namespace kch42\ste; -/* - * Class: RuntimeError +/**   * An Exception that a tag can throw, if a non-fatal runtime error occurred. - * By default this will return in no output at all. But if <STECore::$mute_runtime_errors> is false, this will generate a error message instead of the tag's output. + * By default this will return in no output at all. But if {@see STECore::$mute_runtime_errors} is false, this will generate a error message instead of the tag's output.   */  class RuntimeError extends \Exception  { diff --git a/src/ste/STECore.php b/src/ste/STECore.php index 13fb2f6..40d680a 100644 --- a/src/ste/STECore.php +++ b/src/ste/STECore.php @@ -1,43 +1,64 @@  <?php -// File: STECore.php - -// Namespace: kch42\ste  namespace kch42\ste; -/* - * Class: STECore +use Exception; + +/**   * The Core of STE   */  class STECore  { +    /** @var callable[] */      private $tags; + +    /** @var StorageAccess */      private $storage_access; + +    /** @var string */      private $cur_tpl_dir; + +    /** @var Scope */      public $scope; -    /* -     * Variables: Public variables -     * -     * $blocks - Associative array of blocks (see the language definition). -     * $blockorder - The order of the blocks (an array) -     * $mute_runtime_errors - If true (default) a <RuntimeError> exception will result in no output from the tag, if false a error message will be written to output. -     * $fatal_error_on_missing_tag - If true, STE will throw a <FatalRuntimeError> if a tag was called that was not registered, otherwise (default) a regular <RuntimeError> will be thrown and automatically handled by STE (see <$mute_runtime_errors>). -     * $vars - Variables in the top scope of the template. +    /** +     * @var array +     * Associative array of blocks (see the language definition).       */      public $blocks; + +    /** +     * @var array +     * The order of the blocks (an array) +     */      public $blockorder; + +    /** +     * @var bool +     * If true (default) a {@see RuntimeError} exception will result in no +     * output from the tag, if false a error message will be written to output. +     */      public $mute_runtime_errors = true; + +    /** +     * @var bool +     * If true, STE will throw a {@see FatalRuntimeError} if a tag was called +     * that was not registered, otherwise (default) a regular +     * {@see RuntimeError} will be thrown and automatically handled by STE +     * (see {@see STECore::$mute_runtime_errors}). +     */      public $fatal_error_on_missing_tag = false; + +    /** +     * @var array +     * Variables in the top scope of the template. +     */      public $vars; -    /* -     * Constructor: __construct -     * -     * Parameters: -     *  $storage_access - An Instance of a <StorageAccess> implementation. +    /** +     * @param StorageAccess $storage_access       */ -    public function __construct($storage_access) +    public function __construct(StorageAccess $storage_access)      {          $this->storage_access = $storage_access;          $this->cur_tpl_dir = "/"; @@ -50,42 +71,47 @@ class STECore          $this->scope->vars =& $this->vars;      } -    /* -     * Function: register_tag +    /**       * Register a custom tag.       *       * Parameters: -     *  $name - The name of the tag. -     *  $callback - A callable function (This must take three parameters: The <STECore> instance, an associative array of parameters, and a function representing the tags content(This expects the <STECore> instance as its only parameter and returns its text result, i.e to get the text, you neeed to call this function with the <STECore> instance as a parameter)). +     * @param string $name The name of the tag. +     * @param callable $callback A callable function +     *                           Must take three parameters:       * -     * Throws: -     *  An Exception if the tag could not be registered (if $callback is not callable or if $name is empty) +     *                           The {@see STECore} instance, +     *                           an associative array of parameters, +     *                           and a function representing the tags content +     *                           (This expects the {@see STECore} instance as +     *                           its only parameter and returns its text result, +     *                           i.e to get the text, you need to call this +     *                           function with the {@see STECore} instance as a +     *                           parameter). +     * +     * @throws Exception If the tag could not be registered (if $callback is not callable or if $name is empty)       */      public function register_tag($name, $callback)      {          if (!is_callable($callback)) { -            throw new \Exception("Can not register tag \"$name\", not callable."); +            throw new Exception("Can not register tag \"$name\", not callable.");          }          if (empty($name)) { -            throw new \Exception("Can not register tag, empty name."); +            throw new Exception("Can not register tag, empty name.");          }          $this->tags[$name] = $callback;      } -    /* -     * Function: call_tag +    /**       * Calling a custom tag (builtin ones can not be called)       * -     * Parameters: -     *  $name - The Tag's name -     *  $params - Associative array of parameters -     *  $sub - A callable function (expecting an <STECore> instance as it's parameter) that represents the tag's content. +     * @param string $name The Tag's name +     * @param array $params Associative array of parameters +     * @param callable $sub A callable function (expecting an {@see STECore} instance as it's parameter) that represents the tag's content.       * -     * Throws: -     *  Might throw a <FatalRuntimeError> (see <$fatal_error_on_missing_tag>. +     * @throws FatalRuntimeError see {@see STECore::$fatal_error_on_missing_tag}.       * -     * Returns: -     *  The output of the tag or, if a <RuntimeError> was thrown, the appropiate result (see <$mute_runtime_errors>). +     * @return string The output of the tag or, if a {@see RuntimeError} was thrown, the appropriate result +     *                (see {@see STECore::$mute_runtime_errors}).       */      public function call_tag($name, $params, $sub)      { @@ -103,28 +129,37 @@ class STECore                  return "RuntimeError occurred on tag '$name': " . $e->getMessage();              }          } + +        return "";      } +    /** +     * {@see Calc::calc()} +     * +     * @param string $expression +     * @return float|int +     * @throws RuntimeError +     */      public function calc($expression)      {          return Calc::calc($expression);      } -    /* -     * Function: exectemplate -     * Executes a template and returns the result. The huge difference to <load> is that this function will also output all blocks. +    /** +     * Executes a template and returns the result.       * -     * Parameters: -     *  $tpl - The name of the template to execute. +     * The huge difference to {@see STECore::load()} is that this function will also output all blocks.       * -     * Throws: -     *  * A <CantLoadTemplate> exception if the template could not be loaded. -     *  * A <ParseCompileError> if the template could not be parsed or transcompiled. -     *  * A <FatalRuntimeError> if a tag threw it or if a tag was not found and <$fatal_error_on_missing_tag> is true. -     *  * Might also throw different exceptions, if a external tag threw it (but they should use <RuntimeError> or <FatalRuntimeError> to make it possible for STE to handle them correctly). +     * @param string $tpl The name of the template to execute.       * -     * Returns: -     *  The output of the template. +     * @throws CantLoadTemplate If the template could not be loaded. +     * @throws ParseCompileError If the template could not be parsed or compiled. +     * @throws FatalRuntimeError If a tag threw it or if a tag was not found and <$fatal_error_on_missing_tag> is true. +     * +     * Might also throw different exceptions, if a external tag threw it +     * (but they should use {@see RuntimeError} or {@see FatalRuntimeError} to make it possible for STE to handle them correctly). +     * +     * @return string The output of the template.       */      public function exectemplate($tpl)      { @@ -211,22 +246,21 @@ class STECore          return $this->scope->get_var_by_name($name);      } -    /* -     * Function: load -     * Load a template and return its result (blocks not included, use <exectemplate> for this). +    /** +     * Load a template and return its result (blocks not included, use {@see STECore::exectemplate} for this).       * -     * Parameters: -     *  $tpl - The name of the template to be loaded. -     *  $quiet - If true, do not output anything and do not modify the blocks. This can be useful to load custom tags that are programmed in the STE Template Language. Default: false. +     * @param string $tpl The name of the template to be loaded. +     * @param bool $quiet If true, do not output anything and do not modify the blocks. This can be useful to load custom tags that are programmed in the STE Template Language. Default: false.       * -     * Throws: -     *  * A <CantLoadTemplate> exception if the template could not be loaded. -     *  * A <ParseCompileError> if the template could not be parsed or transcompiled. -     *  * A <FatalRuntimeError> if a tag threw it or if a tag was not found and <$fatal_error_on_missing_tag> is true. -     *  * Might also throw different exceptions, if a external tag threw it (but they should use <RuntimeError> or <FatalRuntimeError> to make it possible for STE to handle them correctly). +     * @throws CantLoadTemplate If the template could not be loaded. +     * @throws CantSaveTemplate If the template could not be saved. +     * @throws ParseCompileError If the template could not be parsed or compiled. +     * @throws FatalRuntimeError If a tag threw it or if a tag was not found and {@see STECore::$fatal_error_on_missing_tag} is true.       * -     * Returns: -     *  The result of the template (if $quiet == false). +     * Might also throw different exceptions, if a external tag threw it +     * (but they should use {@see RuntimeError} or {@see FatalRuntimeError} to make it possible for STE to handle them correctly). +     * +     * @return string|null The result of the template (if $quiet == false).       */      public function load($tpl, $quiet = false)      { @@ -238,7 +272,7 @@ class STECore              $tpl = $this->cur_tpl_dir . "/" . $tpl;          }          $pathex = array_filter(explode("/", $tpl), function ($s) { -            return ($s != ".") and (!empty($s)); +            return $s != "." && !empty($s);          });          $pathex = array_merge($pathex);          while (($i = array_search("..", $pathex)) !== false) { @@ -277,26 +311,31 @@ class STECore          if ($quiet) {              $this->blocks     = $blocks_back;              $this->blockorder = $blockorder_back; + +            return null;          } else {              return $output;          }      }      /* -     * Function: evalbool       * Test, if a text represents false (an empty / only whitespace text) or true (everything else).       * -     * Parameters: -     *  $txt - The text to test. +     * @param string $txt The text to test.       * -     * Returns: -     *  true/false. +     * @return bool       */      public function evalbool($txt)      {          return trim(@(string)$txt) != "";      } +    /** +     * Internal function for implementing tag content and custom tags. +     * +     * @param callable $fx +     * @return \Closure +     */      public function make_closure($fx)      {          $bound_scope = $this->scope; @@ -312,7 +351,7 @@ class STECore                  $result = call_user_func_array($fx, $args);                  $ste->scope = $prev;                  return $result; -            } catch (\Exception $e) { +            } catch (Exception $e) {                  $ste->scope = $prev;                  throw $e;              } diff --git a/src/ste/STEStandardLibrary.php b/src/ste/STEStandardLibrary.php index 9850afe..e39b7af 100644 --- a/src/ste/STEStandardLibrary.php +++ b/src/ste/STEStandardLibrary.php @@ -13,6 +13,12 @@ class STEStandardLibrary          }      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     */      public static function escape($ste, $params, $sub)      {          if ($ste->evalbool(@$params["lines"])) { @@ -22,11 +28,24 @@ class STEStandardLibrary          }      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     */      public static function strlen($ste, $params, $sub)      {          return strlen($sub($ste));      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     * @throws RuntimeError +     */      public static function arraylen($ste, $params, $sub)      {          if (empty($params["array"])) { @@ -36,6 +55,13 @@ class STEStandardLibrary          return (is_array($a)) ? count($a) : "";      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     * @throws RuntimeError +     */      public static function inc($ste, $params, $sub)      {          if (empty($params["var"])) { @@ -45,6 +71,13 @@ class STEStandardLibrary          $ref++;      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     * @throws RuntimeError +     */      public static function dec($ste, $params, $sub)      {          if (empty($params["var"])) { @@ -54,11 +87,24 @@ class STEStandardLibrary          $ref--;      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     */      public static function date($ste, $params, $sub)      {          return @strftime($sub($ste), empty($params["timestamp"]) ? @time() : (int) $params["timestamp"]);      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     * @throws RuntimeError +     */      public static function in_array($ste, $params, $sub)      {          if (empty($params["array"])) { @@ -71,6 +117,13 @@ class STEStandardLibrary          return in_array($sub($ste), $ar) ? "y" : "";      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     * @throws RuntimeError +     */      public static function join($ste, $params, $sub)      {          if (empty($params["array"])) { @@ -79,6 +132,13 @@ class STEStandardLibrary          return implode($sub($ste), $ste->get_var_by_name($params["array"]));      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     * @throws RuntimeError +     */      public static function split($ste, $params, $sub)      {          if (empty($params["array"])) { @@ -90,6 +150,13 @@ class STEStandardLibrary          $ste->set_var_by_name($params["array"], explode($params["delim"], $sub($ste)));      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     * @throws RuntimeError +     */      public static function array_add($ste, $params, $sub)      {          if (empty($params["array"])) { @@ -104,6 +171,13 @@ class STEStandardLibrary          }      } +    /** +     * @param STECore $ste +     * @param array $params +     * @param callable $sub +     * @return string +     * @throws RuntimeError +     */      public static function array_filter($ste, $params, $sub)      {          if (empty($params["array"])) { diff --git a/src/ste/Scope.php b/src/ste/Scope.php index e312876..afb2bfc 100644 --- a/src/ste/Scope.php +++ b/src/ste/Scope.php @@ -4,9 +4,17 @@ namespace kch42\ste;  class Scope implements \ArrayAccess  { +    /** @var self|null */      private $parent = null; + +    /** @var array */      public $vars = array(); +    /** +     * @param string $name +     * @return string[] +     * @throws RuntimeError +     */      private static function parse_name($name)      {          $remain = $name; @@ -44,6 +52,12 @@ class Scope implements \ArrayAccess          return $fields;      } +    /** +     * @param string $name +     * @param bool $localonly +     * @return mixed A reference to the resolved variable +     * @throws VarNotInScope +     */      private function &get_topvar_reference($name, $localonly)      {          if (array_key_exists($name, $this->vars)) { @@ -59,6 +73,13 @@ class Scope implements \ArrayAccess          throw new VarNotInScope();      } +    /** +     * @param string $name +     * @param bool $create_if_not_exist +     * @param bool $localonly +     * @return mixed A reference to the resolved variable +     * @throws RuntimeError +     */      public function &get_var_reference($name, $create_if_not_exist, $localonly=false)      {          $nullref = null; @@ -107,24 +128,42 @@ class Scope implements \ArrayAccess          return $ref;      } +    /** +     * @param string $name +     * @param mixed $val +     * @throws RuntimeError +     */      public function set_var_by_name($name, $val)      {          $ref = &$this->get_var_reference($name, true);          $ref = $val;      } +    /** +     * @param string $name +     * @param mixed $val +     * @throws RuntimeError +     */      public function set_local_var($name, $val)      {          $ref = &$this->get_var_reference($name, true, true);          $ref = $val;      } +    /** +     * @param string $name +     * @return mixed Returns an empty string, if not found or unset +     * @throws RuntimeError +     */      public function get_var_by_name($name)      {          $ref = $this->get_var_reference($name, false);          return $ref === null ? "" : $ref;      } +    /** +     * @return self +     */      public function new_subscope()      {          $o = new self(); diff --git a/src/ste/StorageAccess.php b/src/ste/StorageAccess.php index e2e8727..38dea7e 100644 --- a/src/ste/StorageAccess.php +++ b/src/ste/StorageAccess.php @@ -1,56 +1,45 @@  <?php -// File: StorageAccess.php - -// Namespace: kch42\ste  namespace kch42\ste; -/* - * Class: StorageAccess - * An interface. +/**   * A StorageAccess implementation is used to access the templates from any storage.   * This means, that you are not limited to store the Templates inside directories, you can also use a database or something else.   */  interface StorageAccess  { -    /* -     * Constants: Template modes -     * -     * MODE_SOURCE - The Templates source -     * MODE_TRANSCOMPILED - The transcompiled template -     */ +    /** @var int The template's source */      const MODE_SOURCE        = 0; + +    /** @var int The compiled template */      const MODE_TRANSCOMPILED = 1; -    /* -     * Function: load +    /**       * Loading a template.       * -     * Parameters: -     *  $tpl - The name of the template. -     *  &$mode - Which mode is preferred? One of the <Template modes>. -     *           If <MODE_SOURCE>, the raw sourcecode is expected, if <MODE_TRANSCOMPILED> the transcompiled template *as a callable function* (expecting an <STECore> instance as first parameter) is expected. -     *           If the transcompiled version is not available or older than the source, you can set this parameter to <MODE_SOURCE> and return the source. +     * @param string $tpl The name of the template. +     * @param string &$mode Which mode is preferred? One of the MODE_* constants. +     *                      If {@see StorageAccess::MODE_SOURCE}, the raw sourcecode is expected, +     *                      if {@see StorageAccess::MODE_TRANSCOMPILED} the compiled template +     *                      *as a callable function* (expecting an {@see STECore} instance as first parameter) is expected. +     * +     *                      If the compiled version is not available or older than the source, you can set this +     *                      parameter to {@see StorageAccess::MODE_SOURCE} and return the source.       * -     * Throws: -     *  A <CantLoadTemplate> exception if the template could not be loaded. +     * @throws CantLoadTemplate If the template could not be loaded.       * -     * Returns: -     *  Either the sourcecode or a callable function (first, and only parameter: an <STECore> instance). +     * @return string|callable Either the sourcecode or a callable function (first, and only parameter: an {@see STECore} instance).       */      public function load($tpl, &$mode); -    /* -     * Function: save +    /**       * Saves a template.       * -     * Throws: -     *  A <CantSaveTemplate> exception if the template could not be saved. +     * @param string $tpl -The name of the template. +     * @param string $data - The data to be saved. +     * @param int $mode - One of the MODE_* constants.       * -     * Parameters: -     *  $tpl -The name of the template. -     *  $data - The data to be saved. -     *  $mode - A <Template mode> constant. +     * @throws CantSaveTemplate If the template could not be saved.       */      public function save($tpl, $data, $mode);  } diff --git a/src/ste/TagNode.php b/src/ste/TagNode.php index c1a14e5..18567b2 100644 --- a/src/ste/TagNode.php +++ b/src/ste/TagNode.php @@ -4,9 +4,20 @@ namespace kch42\ste;  class TagNode extends ASTNode  { +    /** @var string */      public $name; + +    /** @var ASTNode[][] */      public $params = array(); + +    /** @var ASTNode[] */      public $sub = array(); + +    /** +     * @param string $tpl +     * @param int $off +     * @param string $name +     */      public function __construct($tpl, $off, $name = "")      {          parent::__construct($tpl, $off); diff --git a/src/ste/TextNode.php b/src/ste/TextNode.php index c68dd2f..199c203 100644 --- a/src/ste/TextNode.php +++ b/src/ste/TextNode.php @@ -4,7 +4,14 @@ namespace kch42\ste;  class TextNode extends ASTNode  { +    /** @var string */      public $text; + +    /** +     * @param string $tpl +     * @param int $off +     * @param string $text +     */      public function __construct($tpl, $off, $text = "")      {          parent::__construct($tpl, $off); diff --git a/src/ste/Transcompiler.php b/src/ste/Transcompiler.php index d223b53..88c008e 100644 --- a/src/ste/Transcompiler.php +++ b/src/ste/Transcompiler.php @@ -1,13 +1,9 @@  <?php -// File: Transcompiler.php - -// Namespace: kch42\ste  namespace kch42\ste; -/* - * Class: Transcompiler - * Contains the STE transcompiler. You'll only need this, if you want to manually transcompile a STE template. +/** + * Contains the STE compiler. You'll only need this, if you want to manually compile a STE template.   */  class Transcompiler  { @@ -18,33 +14,44 @@ class Transcompiler          return $typ . '_' . str_replace('.', '_', uniqid('', true));      } +    private static function mark_builtin_callable(callable $c) +    { +        return $c; +    } +      public static function init_builtins()      {          if (self::$builtins !== null) {              return;          } +        /** @var callable[] builtins */          self::$builtins = array( -            "if" => array("\\kch42\\ste\\Transcompiler", "builtin_if"), -            "cmp" => array("\\kch42\\ste\\Transcompiler", "builtin_cmp"), -            "not" => array("\\kch42\\ste\\Transcompiler", "builtin_not"), -            "even" => array("\\kch42\\ste\\Transcompiler", "builtin_even"), -            "for" => array("\\kch42\\ste\\Transcompiler", "builtin_for"), -            "foreach" => array("\\kch42\\ste\\Transcompiler", "builtin_foreach"), -            "infloop" => array("\\kch42\\ste\\Transcompiler", "builtin_infloop"), -            "break" => array("\\kch42\\ste\\Transcompiler", "builtin_break"), -            "continue" => array("\\kch42\\ste\\Transcompiler", "builtin_continue"), -            "block" => array("\\kch42\\ste\\Transcompiler", "builtin_block"), -            "load" => array("\\kch42\\ste\\Transcompiler", "builtin_load"), -            "mktag" => array("\\kch42\\ste\\Transcompiler", "builtin_mktag"), -            "tagcontent" => array("\\kch42\\ste\\Transcompiler", "builtin_tagcontent"), -            "set" => array("\\kch42\\ste\\Transcompiler", "builtin_set"), -            "setlocal" => array("\\kch42\\ste\\Transcompiler", "builtin_setlocal"), -            "get" => array("\\kch42\\ste\\Transcompiler", "builtin_get"), -            "calc" => array("\\kch42\\ste\\Transcompiler", "builtin_calc") +            "if" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_if")), +            "cmp" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_cmp")), +            "not" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_not")), +            "even" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_even")), +            "for" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_for")), +            "foreach" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_foreach")), +            "infloop" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_infloop")), +            "break" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_break")), +            "continue" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_continue")), +            "block" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_block")), +            "load" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_load")), +            "mktag" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_mktag")), +            "tagcontent" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_tagcontent")), +            "set" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_set")), +            "setlocal" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_setlocal")), +            "get" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_get")), +            "calc" => self::mark_builtin_callable(array("\\kch42\\ste\\Transcompiler", "builtin_calc"))          );      } +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_if($ast)      {          $output = ""; @@ -53,9 +60,9 @@ class Transcompiler          $else = null;          foreach ($ast->sub as $node) { -            if (($node instanceof TagNode) and ($node->name == "then")) { +            if (($node instanceof TagNode) && $node->name == "then") {                  $then = $node->sub; -            } elseif (($node instanceof TagNode) and ($node->name == "else")) { +            } elseif (($node instanceof TagNode) && $node->name == "else") {                  $else = $node->sub;              } else {                  $condition[] = $node; @@ -78,6 +85,12 @@ class Transcompiler          }          return $output;      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_cmp($ast)      {          $operators = array( @@ -116,7 +129,10 @@ class Transcompiler          if (!isset($ast->params["op"])) {              throw new ParseCompileError("self::Transcompile error: op not given in <ste:cmp>.", $ast->tpl, $ast->offset);          } -        if ((count($ast->params["op"]) == 1) and ($ast->params["op"][0] instanceof TextNode)) { +        if ( +            count($ast->params["op"]) == 1 +            && ($ast->params["op"][0] instanceof TextNode) +        ) {              /* Operator is known at compile time, this saves *a lot* of output code! */              $op = trim($ast->params["op"][0]->text);              $op_php = null; @@ -144,6 +160,12 @@ class Transcompiler          }          return $code;      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_not($ast)      {          $code = "\$outputstack[] = '';\n\$outputstack_i++;\n"; @@ -151,6 +173,12 @@ class Transcompiler          $code .= "\$outputstack_i--;\n\$outputstack[\$outputstack_i] .= (!\$ste->evalbool(array_pop(\$outputstack))) ? 'yes' : '';\n";          return $code;      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_even($ast)      {          $code = "\$outputstack[] = '';\n\$outputstack_i++;\n"; @@ -158,6 +186,12 @@ class Transcompiler          $code .= "\$outputstack_i--;\n\$tmp_even = array_pop(\$outputstack);\n\$outputstack[\$outputstack_i] .= (is_numeric(\$tmp_even) and (\$tmp_even % 2 == 0)) ? 'yes' : '';\n";          return $code;      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_for($ast)      {          $code = ""; @@ -179,7 +213,10 @@ class Transcompiler          $step = null; /* i.e. not known at compilation time */          if (empty($ast->params["step"])) {              $step = 1; -        } elseif ((count($ast->params["step"]) == 1) and ($ast->params["step"][0] instanceof TextNode)) { +        } elseif ( +            count($ast->params["step"]) == 1 +            && ($ast->params["step"][0] instanceof TextNode) +        ) {              $step = $ast->params["step"][0]->text + 0;          } else {              list($val, $pre) = self::_transcompile($ast->params["step"], true); @@ -216,6 +253,12 @@ class Transcompiler          return $code;      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_foreach($ast)      {          $loopname = self::tempvar("foreachloop"); @@ -282,18 +325,40 @@ class Transcompiler          return $code;      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_infloop($ast)      {          return "while(true)\n{\n" . self::indent_code(self::loopbody(self::indent_code(self::_transcompile($ast->sub)))) . "\n}\n";      } + +    /** +     * @param TagNode $ast +     * @return string +     */      private static function builtin_break($ast)      {          return "throw new \\kch42\\ste\\BreakException();\n";      } + +    /** +     * @param TagNode $ast +     * @return string +     */      private static function builtin_continue($ast)      {          return "throw new \\kch42\\ste\\ContinueException();\n";      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_block($ast)      {          if (empty($ast->params["name"])) { @@ -315,6 +380,12 @@ class Transcompiler          return $code;      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_load($ast)      {          if (empty($ast->params["name"])) { @@ -325,6 +396,12 @@ class Transcompiler          $code .= "\$outputstack[\$outputstack_i] .= \$ste->load(" . $val . ");\n";          return $code;      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_mktag($ast)      {          $code = ""; @@ -356,10 +433,21 @@ class Transcompiler          return $code;      } + +    /** +     * @param TagNode $ast +     * @return string +     */      private static function builtin_tagcontent($ast)      {          return "\$outputstack[\$outputstack_i] .= \$sub(\$ste);";      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_set($ast)      {          if (empty($ast->params["var"])) { @@ -376,6 +464,12 @@ class Transcompiler          return $code;      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_setlocal($ast)      {          if (empty($ast->params["var"])) { @@ -392,6 +486,12 @@ class Transcompiler          return $code;      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_get($ast)      {          if (empty($ast->params["var"])) { @@ -401,6 +501,12 @@ class Transcompiler          list($val, $pre) = self::_transcompile($ast->params["var"], true);          return "$pre\$outputstack[\$outputstack_i] .= \$ste->get_var_by_name(" . $val . ");";      } + +    /** +     * @param TagNode $ast +     * @return string +     * @throws ParseCompileError +     */      private static function builtin_calc($ast)      {          $code = "\$outputstack[] = '';\n\$outputstack_i++;\n"; @@ -425,6 +531,12 @@ class Transcompiler          return "try\n{\n" . self::indent_code($code) . "\n}\ncatch(\\kch42\\ste\\BreakException \$e) { break; }\ncatch(\\kch42\\ste\\ContinueException \$e) { continue; }\n";      } +    /** +     * @param ASTNode[] $ast +     * @param bool $avoid_outputstack +     * @return array|string +     * @throws ParseCompileError +     */      private static function _transcompile($ast, $avoid_outputstack = false)      { /* The real self::transcompile function, does not add boilerplate code. */          $code = ""; @@ -477,16 +589,15 @@ class Transcompiler          return $code;      } -    /* -     * Function: transcompile -     * Transcompiles an abstract syntax tree to PHP. -     * You only need this function, if you want to manually transcompile a template. +    /** +     * Compiles an abstract syntax tree to PHP. +     * You only need this function, if you want to manually compile a template.       * -     * Parameters: -     *  $ast - The abstract syntax tree to transcompile. +     * @param ASTNode[] $ast The abstract syntax tree to compile.       * -     * Returns: -     *  PHP code. The PHP code is an anonymous function expecting a <STECore> instance as its parameter and returns a string (everything that was not pached into a section). +     * @return string PHP code. The PHP code is an anonymous function expecting an {@see STECore} instance as its +     *                parameter and returns a string (everything that was not packed into a section). +     * @throws ParseCompileError       */      public static function transcompile($ast)      { /* self::Transcompile and add some boilerplate code. */ diff --git a/src/ste/VariableNode.php b/src/ste/VariableNode.php index d03fdce..9a4ced8 100644 --- a/src/ste/VariableNode.php +++ b/src/ste/VariableNode.php @@ -4,13 +4,24 @@ namespace kch42\ste;  class VariableNode extends ASTNode  { +    /** @var string */      public $name; + +    /** @var ASTNode[][] */      public $arrayfields = array(); + +    /** +     * @return string +     */      public function transcompile()      {          $varaccess = '@$ste->scope[' . (is_numeric($this->name) ? $this->name : '"' . Misc::escape_text($this->name) . '"'). ']';          foreach ($this->arrayfields as $af) { -            if ((count($af) == 1) and ($af[0] instanceof TextNode) and is_numeric($af[0]->text)) { +            if ( +                count($af) == 1 +                && ($af[0] instanceof TextNode) +                && is_numeric($af[0]->text) +            ) {                  $varaccess .= '[' . $af->text . ']';              } else {                  $varaccess .= '[' . implode(".", array_map(function ($node) { | 
