- added type annotations v0.1.0
authorSebastian Brix <sebastian.brix@graph-it.com>
Wed, 16 Feb 2022 05:33:57 +0000 (06:33 +0100)
committerSebastian Brix <sebastian.brix@graph-it.com>
Wed, 16 Feb 2022 05:33:57 +0000 (06:33 +0100)
- checked code with psalm, still a lot todo

psalm.xml [new file with mode: 0644]
src/BaseParser.php
src/ConcatParser.php
src/EBNFGenerator.php
src/EmptyParser.php
src/GrammerParser.php
src/GreedyMultiParser.php
src/LazyAltParser.php
src/RegexParser.php
src/StringParser.php

diff --git a/psalm.xml b/psalm.xml
new file mode 100644 (file)
index 0000000..3240886
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<psalm
+    errorLevel="1"
+    resolveFromConfigFile="true"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns="https://getpsalm.org/schema/config"
+    xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
+>
+    <projectFiles>
+        <directory name="src" />
+        <ignoreFiles>
+            <directory name="vendor" />
+        </ignoreFiles>
+    </projectFiles>
+</psalm>
index fe8a71ae7cc01db09535b05eaeb8db27c17f51df..33804b896ac560de7d46c410cee77198d0dcc985 100644 (file)
@@ -4,14 +4,22 @@ namespace Graphit\Parser;
 
 abstract class BaseParser
 {
+  /** @var array<BaseParser|string> */
   protected $internals;
 
+  /** @var callable */
   protected $generator;
 
+  /** @var string */
   protected $description;
 
-  protected $acceptsEmpty;
+  /** @var bool */
+  protected $acceptsEmpty = false;
 
+  /**
+   * @param array<BaseParser|string> $internals
+   * @param callable                 $generator
+   */
   public function __construct(array $internals = array(), $generator = null)
   {
     if ( !$this->description) {
@@ -35,16 +43,24 @@ abstract class BaseParser
     }
   }
 
+  /** @return array<string, BaseParser|string> */
   public function getInternals()
   {
     return $this->internals;
   }
 
+  /** @return string */
   public function getDescription()
   {
     return $this->description;
   }
 
+  /**
+   * @param string $string
+   * @param int    $p      the position
+   *
+   * @return array{ r: mixed, p: int }|false
+   */
   protected function parse($string, $p = 0)
   {
     if ( !$r = $this->accept($string, $p)) {
@@ -56,10 +72,18 @@ abstract class BaseParser
     );
   }
 
+  /**
+   * @param string $string
+   * @param int    $p      the position
+   *
+   * @return array{ r: mixed, p: int }|false
+   */
   protected abstract function accept($string, $p);
 
+  /** @return bool */
   protected abstract function evalAcceptsEmpty();
 
+  /** @return BaseParser[] */
   protected abstract function firstSet();
 
   public function __toString()
@@ -67,6 +91,10 @@ abstract class BaseParser
     return $this->description;
   }
 
+  /**
+   * @param mixed $result
+   * @return array{ t: string, r: mixed }
+   */
   protected function defaultGenerator($result)
   {
     return array(
@@ -75,6 +103,10 @@ abstract class BaseParser
     );
   }
 
+  /**
+   * @param array<BaseParser|string> $internals
+   * @return string
+   */
   protected function serializeInternals(array $internals)
   {
     $chunks = array();
index df9f80a02dd46268bef772b8c7d75df672e9ba5f..92d6e4fa25379110ba86cf9278d4a279f1b9d53c 100644 (file)
@@ -4,6 +4,10 @@ namespace Graphit\Parser;
 
 class ConcatParser extends BaseParser
 {
+  /**
+   * @param array<BaseParser|string> $internals
+   * @param callable                 $generator
+   */
   public function __construct(array $internals, $generator = null)
   {
     $this->description = 'new '.get_class().'('.$this->serializeInternals($internals).')';
@@ -12,8 +16,17 @@ class ConcatParser extends BaseParser
 
   protected function accept($string, $p)
   {
-    $r = array();
+    $internals = [];
     foreach ($this->internals as $internal) {
+      if ($internal instanceof BaseParser) {
+        $internals[] = $internal;
+      } else {
+        throw new \Exception('Expected a BaseParser!');
+      }
+    }
+
+    $r = array();
+    foreach ($internals as $internal) {
       if ($i = $internal->parse($string, $p)) {
         $r[] = $i['r'];
         $p = $i['p'];
@@ -31,7 +44,16 @@ class ConcatParser extends BaseParser
 
   protected function evalAcceptsEmpty()
   {
+    $internals = [];
     foreach ($this->internals as $internal) {
+      if ($internal instanceof BaseParser) {
+        $internals[] = $internal;
+      } else {
+        throw new \Exception('Expected a BaseParser!');
+      }
+    }
+
+    foreach ($internals as $internal) {
       if ( !$internal->acceptsEmpty) {
         return false;
       }
@@ -41,8 +63,17 @@ class ConcatParser extends BaseParser
 
   protected function firstSet()
   {
-    $firstSet = array();
+    $internals = [];
     foreach ($this->internals as $internal) {
+      if ($internal instanceof BaseParser) {
+        $internals[] = $internal;
+      } else {
+        throw new \Exception('Expected a BaseParser!');
+      }
+    }
+
+    $firstSet = array();
+    foreach ($internals as $internal) {
       $firstSet[] = $internal;
 
       if ( !$internal->acceptsEmpty) {
index 000565a8bfb1ed7b138a671c2cdfd1f62c755c30..14690d5865562d2af00249f32ce6cd2ce246c672 100644 (file)
@@ -4,6 +4,7 @@ namespace Graphit\Parser;
 
 class EBNFGenerator
 {
+  /** @var EBNFParser */
   protected $parser;
 
   public function __construct()
@@ -11,6 +12,13 @@ class EBNFGenerator
     $this->parser = new EBNFParser();
   }
 
+  /**
+   * @param string $ebnf
+   * @param string $start
+   * @param string $class
+   *
+   * @return string
+   */
   public function generate($ebnf, $start, $class)
   {
     if ( !$ast = $this->parser->ast($ebnf)) {
@@ -21,6 +29,7 @@ class EBNFGenerator
       $namespace = substr($class, 0, $pos);
       $classname = substr($class, $pos + 1);
     } else {
+      $namespace = null;
       $classname = $class;
     }
 
@@ -59,6 +68,11 @@ class EBNFGenerator
     return $code;
   }
 
+  /**
+   * @param string $generator
+   *
+   * @return string
+   */
   protected function genParser(array $object, $generator = null)
   {
     $method = 'gen'.ucfirst($object['t']).'Parser';
@@ -69,7 +83,12 @@ class EBNFGenerator
     throw new \Exception("Unknow t '{$object['t']}' or  missing method $method");
   }
 
-  protected function genSyntaxParser($object, $generator)
+  /**
+   * @param string $generator
+   *
+   * @return string
+   */
+  protected function genSyntaxParser(array $object, $generator)
   {
     $code = "\$internals = array(\n";
     foreach ($object['r'][1]['r'] as $rule) {
@@ -79,7 +98,8 @@ class EBNFGenerator
     return $code;
   }
 
-  protected function genRuleParser($object)
+  /** @return string */
+  protected function genRuleParser(array $object)
   {
     $name = $object['r'][0]['r'][0]['r'][0];
     $generator = $this->genGenerator($name);
@@ -89,7 +109,12 @@ class EBNFGenerator
     return $code;
   }
 
-  protected function genAltParser($object, $generator = null)
+  /**
+   * @param string $generator
+   *
+   * @return string
+   */
+  protected function genAltParser(array $object, $generator = null)
   {
     $code = "new \\Graphit\\Parser\\LazyAltParser(\n";
     $code.= "  array(\n";
@@ -102,7 +127,12 @@ class EBNFGenerator
     return $code;
   }
 
-  protected function genConcParser($object, $generator = null)
+  /**
+   * @param string $generator
+   *
+   * @return string
+   */
+  protected function genConcParser(array $object, $generator = null)
   {
     $code = "new \\Graphit\\Parser\\ConcatParser(\n";
     $code.= "  array(\n";
@@ -115,13 +145,21 @@ class EBNFGenerator
     return $code;
   }
 
-  protected function genBarewordParser($object)
+  /**
+   * @return string
+   */
+  protected function genBarewordParser(array $object)
   {
     $code = var_export($object['r'][0]['r'][0], true);
     return $code;
   }
 
-  protected function genSqParser($object, $generator = null)
+  /**
+   * @param string $generator
+   *
+   * @return string
+   */
+  protected function genSqParser(array $object, $generator = null)
   {
     $code = "new \\Graphit\\Parser\\StringParser(";
     $code.= $generator? "\n  ": '';
@@ -132,7 +170,12 @@ class EBNFGenerator
     return $code;
   }
 
-  protected function genDqParser($object, $generator = null)
+  /**
+   * @param string $generator
+   *
+   * @return string
+   */
+  protected function genDqParser(array $object, $generator = null)
   {
     $code = "new \\Graphit\\Parser\\StringParser(";
     $code.= $generator? "\n  ": '';
@@ -143,7 +186,12 @@ class EBNFGenerator
     return $code;
   }
 
-  protected function genRegexParser($object, $generator = null)
+  /**
+   * @param string $generator
+   *
+   * @return string
+   */
+  protected function genRegexParser(array $object, $generator = null)
   {
     $code = "new \\Graphit\\Parser\\RegexParser(";
     $code.= $generator? "\n  ": '';
@@ -153,12 +201,22 @@ class EBNFGenerator
     return $code;
   }
 
-  protected function genGroupParser($object, $generator = null)
+  /**
+   * @param string $generator
+   *
+   * @return string
+   */
+  protected function genGroupParser(array $object, $generator = null)
   {
     return $this->genParser($object['r'][2], $generator);
   }
 
-  protected function genRepetitionParser($object, $generator = null)
+  /**
+   * @param string $generator
+   *
+   * @return string
+   */
+  protected function genRepetitionParser(array $object, $generator = null)
   {
     $code = "new \\Graphit\\Parser\\GreedyMultiParser(\n";
     $code.= $this->indent($this->genParser($object['r'][2]), 2);
@@ -168,7 +226,12 @@ class EBNFGenerator
     return $code;
   }
 
-  protected function genOptionalParser($object, $generator = null)
+  /**
+   * @param string $generator
+   *
+   * @return string
+   */
+  protected function genOptionalParser(array $object, $generator = null)
   {
     $code = "new \\Graphit\\Parser\\GreedyMultiParser(\n";
     $code.= $this->indent($this->genParser($object['r'][2]), 2);
@@ -178,11 +241,22 @@ class EBNFGenerator
     return $code;
   }
 
+  /**
+   * @param string $source
+   *
+   * @return string
+   */
   protected function genGenerator($source)
   {
     return "{$source}Generator";
   }
 
+  /**
+   * @param string|null $generator
+   * @param bool        $break
+   *
+   * @return string
+   */
   protected function genGeneratorCall($generator, $break = false)
   {
     if ( !$generator) {
@@ -195,6 +269,13 @@ class EBNFGenerator
     return $code;
   }
 
+  /**
+   * @param string $lines
+   * @param int    $size
+   * @param int    $from
+   *
+   * @return string
+   */
   protected function indent($lines, $size = 2, $from = 0)
   {
     $pad = str_repeat(' ', $size);
@@ -202,7 +283,7 @@ class EBNFGenerator
 
     $lines = explode("\n", $lines);
     for ($i = 0; $i < $from; ++$i) {
-      if (($line = array_shift($lines)) === false) {
+      if ( !($line = array_shift($lines))) {
         break;
       }
       $code .= "{$line}\n";
index 47a4601c23a503a909af8a992d3cf7d6f470f44b..ffdd253988b2f29383cecba452eb0ea53f276adf 100644 (file)
@@ -4,6 +4,9 @@ namespace Graphit\Parser;
 
 class EmptyParser extends BaseParser
 {
+  /**
+   * @param callable $generator
+   */
   public function __construct($generator = null)
   {
     $this->description = 'new '.get_class().'()';
index d1a8b040f2ccab2648d60f32a7bfc86cb814ea4f..640a9c297098b189d8bdaa8e9c3b4bf936703761 100644 (file)
@@ -4,8 +4,14 @@ namespace Graphit\Parser;
 
 class GrammerParser extends BaseParser
 {
+  /** @var string */
   protected $s;
 
+  /**
+   * @param string                           $s
+   * @param array<string, BaseParser|string> $internals
+   * @param callable                         $generator
+   */
   public function __construct($s, array $internals, $generator = null)
   {
     $this->description = 'new '.get_class().'('.$this->serializeInternals($internals).')';
@@ -23,7 +29,9 @@ class GrammerParser extends BaseParser
     $this->testInifinitGreedy();
 
     foreach ($this->internals as $internal) {
+      /** @var BaseParser[] */
       $done = array();
+      /** @var BaseParser[] */
       $todo = array($internal);
       while ($current = array_shift($todo)) {
         $done[] = $current;
@@ -43,10 +51,14 @@ class GrammerParser extends BaseParser
     }
   }
 
+  /** @return void */
   protected function resolveParserNames()
   {
+    /** @var BaseParser[] */
     $done = array();
+    /** @var BaseParser[] */
     $todo = array($this);
+
     while ($current = array_shift($todo)) {
       $done[] = $current;
 
@@ -67,18 +79,30 @@ class GrammerParser extends BaseParser
     }
   }
 
+  /** @return void */
   protected function floodAcceptsEmpty()
   {
     $change = true;
     while ($change) {
       $change = false;
 
+      /** @var BaseParser[] */
       $done = array();
+      /** @var BaseParser[] */
       $todo = array($this);
       while ($current = array_shift($todo)) {
         $done[] = $current;
 
+        $internals = [];
         foreach ($current->internals as $internal) {
+          if ($internal instanceof BaseParser) {
+            $internals[] = $internal;
+          } else {
+            throw new \Exception('Expected a BaseParser!');
+          }
+        }
+
+        foreach ($internals as $internal) {
           if ($internal->acceptsEmpty) {
             continue;
           }
@@ -101,11 +125,16 @@ class GrammerParser extends BaseParser
     }
   }
 
+
+  /** @return void */
   protected function testInifinitGreedy()
   {
     $done = array();
     $todo = $this->internals;
     while ($current = array_shift($todo)) {
+      if ( !($current instanceof BaseParser)) {
+        throw new \Exception('Expected a BaseParser!');
+      }
       $done[] = $current;
 
       foreach ($current->internals as $internal) {
@@ -120,12 +149,20 @@ class GrammerParser extends BaseParser
       if ($current->getOptional() !== null) {
         continue;
       }
+
+      if ( !($current->internals[0] instanceof BaseParser)) {
+        throw new \Exception('Expected a BaseParser!');
+      }
       if ($current->internals[0]->acceptsEmpty) {
         throw new GrammerException("{$current} will cause infinite loops, because the internal parser accepts empty!");
       }
     }
   }
 
+  /**
+   * @param string $code
+   * @return mixed
+   */
   public function ast($code)
   {
     if ($r = $this->parse($code, 0)) {
@@ -140,21 +177,29 @@ class GrammerParser extends BaseParser
 
   protected function accept($string, $p)
   {
-    if ($r = $this->internals[$this->s]->parse($string, $p)) {
-      return $r;
+    if ($this->internals[$this->s] instanceof BaseParser) {
+      if ($r = $this->internals[$this->s]->parse($string, $p)) {
+        return $r;
+      }
+      return false;
     }
-
-    return false;
+    throw new \Exception('BaseParser expected');
   }
 
   protected function evalAcceptsEmpty()
   {
-    return $this->internals[$this->s]->acceptsEmpty;
+    if ($this->internals[$this->s] instanceof BaseParser) {
+      return $this->internals[$this->s]->acceptsEmpty;
+    }
+    throw new \Exception('BaseParser expected');
   }
 
   protected function firstSet()
   {
-    return array($this->internals[$this->s]);
+    if ($this->internals[$this->s] instanceof BaseParser) {
+      return array($this->internals[$this->s]);
+    }
+    throw new \Exception('BaseParser expected');
   }
 }
 
index 1e4aa73201190779518cd42064523eee04a0244c..b1176638987cb2d46912dd3bc99ea1f0fcab8ff8 100644 (file)
@@ -4,10 +4,18 @@ namespace Graphit\Parser;
 
 class GreedyMultiParser extends BaseParser
 {
+  /** @var int */
   protected $lower;
 
+  /** @var int|null */
   protected $optional;
 
+  /**
+   * @param BaseParser|string $internal
+   * @param int               $lower
+   * @param int|null          $optional
+   * @param callable          $generator
+   */
   public function __construct($internal, $lower = 0, $optional = null, $generator = null)
   {
     $this->lower = $lower;
@@ -17,11 +25,13 @@ class GreedyMultiParser extends BaseParser
     parent::__construct(array($internal), $generator);
   }
 
+  /** @return int */
   public function getLower()
   {
     return $this->lower;
   }
 
+  /** @return int|null */
   public function getOptional()
   {
     return $this->optional;
@@ -29,6 +39,9 @@ class GreedyMultiParser extends BaseParser
 
   protected function accept($string, $p)
   {
+    if ( !($this->internals[0] instanceof BaseParser)) {
+      throw new \Exception('Expected a BaseParser!');
+    }
     $r = array();
     for ($j = 0; $j < $this->lower; $j++) {
       if ($i = $this->internals[0]->parse($string, $p)) {
@@ -58,11 +71,17 @@ class GreedyMultiParser extends BaseParser
 
   protected function evalAcceptsEmpty()
   {
-    return $this->lower == 0 || $this->internals[0]->acceptsEmpty;
+    if ($this->internals[0] instanceof BaseParser) {
+      return $this->lower == 0 || $this->internals[0]->acceptsEmpty;
+    }
+    throw new \Exception('Expected a BaseParser!');
   }
 
   protected function firstSet()
   {
-    return $this->internals;
+    if ($this->internals[0] instanceof BaseParser) {
+      return array($this->internals[0]);
+    }
+    throw new \Exception('Expected a BaseParser!');
   }
 }
index 7c2efcf8f81d7e2c82c6518ceda7aeb088bf5f7f..7e8fd50f120c6934d92fd366bf2f59e43d68e8e8 100644 (file)
@@ -4,6 +4,10 @@ namespace Graphit\Parser;
 
 class LazyAltParser extends BaseParser
 {
+  /**
+   * @param array<BaseParser|string> $internals
+   * @param callable                 $generator
+   */
   public function __construct(array $internals, $generator = null)
   {
     if ( !$internals) {
@@ -16,7 +20,16 @@ class LazyAltParser extends BaseParser
 
   protected function accept($string, $p)
   {
+    $internals = [];
     foreach ($this->internals as $internal) {
+      if ($internal instanceof BaseParser) {
+        $internals[] = $internal;
+      } else {
+        throw new \Exception('Expected a BaseParser!');
+      }
+    }
+
+    foreach ($internals as $internal) {
       if ($i = $internal->parse($string, $p)) {
         return array(
           'r' => $i['r'],
@@ -29,7 +42,16 @@ class LazyAltParser extends BaseParser
 
   protected function evalAcceptsEmpty()
   {
+    $internals = [];
     foreach ($this->internals as $internal) {
+      if ($internal instanceof BaseParser) {
+        $internals[] = $internal;
+      } else {
+        throw new \Exception('Expected a BaseParser!');
+      }
+    }
+
+    foreach ($internals as $internal) {
       if ($internal->acceptsEmpty) {
         return true;
       }
@@ -39,6 +61,15 @@ class LazyAltParser extends BaseParser
 
   protected function firstSet()
   {
-    return $this->internals;
+    $internals = [];
+    foreach ($this->internals as $internal) {
+      if ($internal instanceof BaseParser) {
+        $internals[] = $internal;
+      } else {
+        throw new \Exception('Expected a BaseParser!');
+      }
+    }
+
+    return $internals;
   }
 }
index 43aae7b2f5c17a95f4a87d7469992b97ee5ef00d..ac36e940fe78cbbbfbd55d3bae59ad8f062ef6b3 100644 (file)
@@ -4,8 +4,13 @@ namespace Graphit\Parser;
 
 class RegexParser extends BaseParser
 {
+  /** @var string */
   protected $pattern;
 
+  /**
+   * @param string $pattern
+   * @param callable $generator
+   */
   public function __construct($pattern, $generator = null)
   {
     $this->pattern = (string)$pattern;
@@ -17,11 +22,18 @@ class RegexParser extends BaseParser
     parent::__construct(array(), $generator);
   }
 
+  /** @return string */
   public function getPattern()
   {
     return $this->pattern;
   }
 
+  /**
+   * @param string $string
+   * @param int    $p      the position
+   *
+   * @return array{ r: mixed, p: int }|false
+   */
   protected function accept($string, $p)
   {
     $matches = array();
@@ -35,6 +47,7 @@ class RegexParser extends BaseParser
     );
   }
 
+  /** @return bool */
   protected function evalAcceptsEmpty()
   {
     return preg_match($this->pattern, '') === 1;
index d63e86232abc7ade62228c320b2cbba10668273c..d07eeadc3a88efa6c09e7db9dd347a783a4bce9f 100644 (file)
@@ -4,8 +4,13 @@ namespace Graphit\Parser;
 
 class StringParser extends BaseParser
 {
+  /** @var string */
   protected $needle;
 
+  /**
+   * @param string   $needle
+   * @param callable $generator
+   */
   public function __construct($needle, $generator = null)
   {
     $this->needle = (string)$needle;
@@ -14,11 +19,18 @@ class StringParser extends BaseParser
     parent::__construct(array(), $generator);
   }
 
+  /** @return string */
   public function getNeedle()
   {
     return $this->needle;
   }
 
+  /**
+   * @param string $string
+   * @param int    $p
+   *
+   * @return array{ r: mixed ,p: int }|false
+   */
   protected function accept($string, $p)
   {
     if ($this->needle !== '' && strpos($string, $this->needle, $p) !== $p) {
@@ -31,6 +43,7 @@ class StringParser extends BaseParser
     );
   }
 
+  /** @return bool */
   protected function evalAcceptsEmpty()
   {
     return $this->needle === '';