diff --git a/composer.json b/composer.json index 790bfd1..9a81a05 100644 --- a/composer.json +++ b/composer.json @@ -5,9 +5,7 @@ "type": "phpstan-extension", "require": { "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^1.8", - "symfony/polyfill-php80": "^v1.27.0", - "symfony/yaml": "^5.4 || ^6.0" + "phpstan/phpstan": "^1.8" }, "require-dev": { "phpstan/phpstan-phpunit": "^1.2", diff --git a/src/ModuliteYaml/ModuliteData.php b/src/ModuliteYaml/ModuliteData.php index f4997c1..b99c6b9 100644 --- a/src/ModuliteYaml/ModuliteData.php +++ b/src/ModuliteYaml/ModuliteData.php @@ -373,11 +373,11 @@ static function create_from_composer_json(ComposerJsonData $composer_json, bool if ($has_modulite_yaml_also) { $yaml_filename = dirname($composer_json->json_filename) . '/.modulite.yaml'; try { - $y_file = \Symfony\Component\Yaml\Yaml::parseFile($yaml_filename); + $y_file = YamlParserNoSymfony::parseFromFile($yaml_filename); $parser = new ModuliteYamlParser($out); - $parser->parse_modulite_yaml_file(is_array($y_file) ? $y_file : []); - } catch (\Symfony\Component\Yaml\Exception\ParseException $ex) { - $out->fire_yaml_error($ex->getMessage(), $ex->getParsedLine()); + $parser->parse_modulite_yaml_file($y_file); + } catch (YamlParserNoSymfonyException $ex) { + $out->fire_yaml_error($ex->getMessage(), $ex->getLine()); } } @@ -393,11 +393,11 @@ static function create_from_modulite_yaml(string $yaml_filename, ?ModuliteData $ $out->is_composer_package = false; try { - $y_file = \Symfony\Component\Yaml\Yaml::parseFile($out->yaml_filename); + $y_file = YamlParserNoSymfony::parseFromFile($out->yaml_filename); $parser = new ModuliteYamlParser($out); - $parser->parse_modulite_yaml_file(is_array($y_file) ? $y_file : []); - } catch (\Symfony\Component\Yaml\Exception\ParseException $ex) { - $out->fire_yaml_error($ex->getMessage(), $ex->getParsedLine()); + $parser->parse_modulite_yaml_file($y_file); + } catch (YamlParserNoSymfonyException $ex) { + $out->fire_yaml_error($ex->getMessage(), $ex->getLine()); } return $out; diff --git a/src/ModuliteYaml/YamlParserNoSymfony.php b/src/ModuliteYaml/YamlParserNoSymfony.php new file mode 100644 index 0000000..dadaa77 --- /dev/null +++ b/src/ModuliteYaml/YamlParserNoSymfony.php @@ -0,0 +1,179 @@ + $line) { + $line = rtrim($line); + $offset = 0; + self::skipSpaces($line, $offset); + $n_spaces = $offset; + + if ($offset >= strlen($line)) { + continue; + } + + if ($line[$offset] === '#') { + continue; + } + + if ($line[$offset] === '-') { + if ($last_key === null || is_string($out[$last_key])) { + throw new YamlParserNoSymfonyException($file_name, "list in a strange place", $i + 1); + } + $offset++; + $value = self::parseString($line, $offset); + if ($value === null) { + throw new YamlParserNoSymfonyException($file_name, "expected a string", $i + 1); + } + $pushValueAtCurrentKey($value); + continue; + } + + $nameBeforeColon = self::parseNameBeforeColon($line, $offset); + if ($nameBeforeColon === null) { + throw new YamlParserNoSymfonyException($file_name, "expected ':'", $i + 1); + } + + if ($n_spaces > 0) { // support only 2 depth levels + $last_key_nested = $nameBeforeColon; + } else { + $last_key = $nameBeforeColon; + $last_key_nested = null; + } + + self::skipSpaces($line, $offset); + if ($offset < strlen($line) && $line[$offset] !== '#') { + $value = self::parseString($line, $offset); + if ($value === null) { + throw new YamlParserNoSymfonyException($file_name, "expected a string", $i + 1); + } + $assignValueAtCurrentKey($value); + } else { + $assignValueAtCurrentKey(null); + } + } + + return $out; + } + + static private function parseString(string $line, int &$offset): ?string { + self::skipSpaces($line, $offset); + if ($offset >= strlen($line)) { + return null; + } + + return $line[$offset] === '"' + ? self::parseQuotedString($line, $offset) + : self::parseNonQuotedString($line, $offset); + } + + static private function skipSpaces(string $line, int &$offset) { + while ($offset < strlen($line) && $line[$offset] === ' ') { + $offset++; + } + } + + static private function parseNameBeforeColon(string $line, int &$offset): ?string { + $name = ''; + + if ($line[$offset] === '"' || $line[$offset] === "'") { + $name = self::parseQuotedString($line, $offset); + if ($name === null || $offset >= strlen($line) || $line[$offset] !== ':') { + return null; + } + } else { + $pos = strpos($line, ':', $offset); + if ($pos === false) { + return null; + } + $name = substr($line, $offset, $pos - $offset); + $offset = $pos; + } + + $offset = $offset + 1; + return $name; + } + + static private function parseNonQuotedString(string $line, int &$offset): ?string { + $value = ''; + + for ($i = $offset; $i < strlen($line); ++$i) { + switch ($line[$i]) { + case '#': + break 2; + default: + $value .= $line[$i]; + } + } + + while ($i > $offset && $line[$i - 1] === ' ') { + $i--; + $value = substr($value, 0, -1); + } + + $offset = $i; + return $value; + } + + static private function parseQuotedString(string $line, int &$offset): ?string { + $quote = $line[$offset]; // " or ' + $value = ''; + + for ($i = $offset + 1; $i < strlen($line); ++$i) { + switch ($line[$i]) { + case '\\': + $value .= $line[++$i]; + break; + case $quote: + break 2; + default: + $value .= $line[$i]; + } + } + + if ($i == strlen($line) || $line[$i] !== $quote) { + return null; + } + + $offset = $i + 1; + return $value; + } +} diff --git a/src/ModuliteYaml/YamlParserNoSymfonyException.php b/src/ModuliteYaml/YamlParserNoSymfonyException.php new file mode 100644 index 0000000..5e431be --- /dev/null +++ b/src/ModuliteYaml/YamlParserNoSymfonyException.php @@ -0,0 +1,11 @@ +file = $file_name; + $this->line = $line_number; + } +} diff --git a/tests/YamlParserNoSymfonyTestCase.php b/tests/YamlParserNoSymfonyTestCase.php new file mode 100644 index 0000000..d0fdc07 --- /dev/null +++ b/tests/YamlParserNoSymfonyTestCase.php @@ -0,0 +1,109 @@ + '@utils', + 'namespace' => 'Algo101\\', + 'hello1' => 'hello1', + 'hello2' => 'hello2', + 'hello3' => 'hello3', + 'hello4' => 'hello4', + 'hello5' => 'hello5', + 'hello 6' => 'hello 6', + 'hello:7' => 'hello:7', + 'hello\'"8' => 'hello\'"8', + 'hello9' => null, + 'hello10' => null, + 'export' => [ + 'asdf' => [''], + 'nested' => [ + 'one', + "Export\\ Class", + "Export\\ Class", + "Export\\ Class ", + "Export\\Class::method()" + ] + ], + 'require' => 'asdf', + 'map' => [ + 'k1' => 'v1', + 'k2' => ['v2'], + 'k3' => 'v3', + ], + 'allow-internal-access' => ['Algo101'], + ]; + + $actual = YamlParserNoSymfony::parseFromString($yaml); + $this->assertSame($expected, $actual); + } + + function testError1() { + $yaml = <<<'YAML' +name: "asdf" +- asdf +YAML; + $this->expectException(YamlParserNoSymfonyException::class); + $this->expectExceptionMessage("list in a strange place"); + YamlParserNoSymfony::parseFromString($yaml); + } + + function testError2() { + $yaml = <<<'YAML' +"asdf" +YAML; + $this->expectException(YamlParserNoSymfonyException::class); + $this->expectExceptionMessage("expected ':'"); + YamlParserNoSymfony::parseFromString($yaml); + } + + function testError3() { + $yaml = <<<'YAML' +exports: +- +YAML; + $this->expectException(YamlParserNoSymfonyException::class); + $this->expectExceptionMessage("expected a string"); + YamlParserNoSymfony::parseFromString($yaml); + } +} diff --git a/tests/php/005_inheritance/005_inheritance.php b/tests/php/005_inheritance/005_inheritance.php index 72c1bae..0998e26 100644 --- a/tests/php/005_inheritance/005_inheritance.php +++ b/tests/php/005_inheritance/005_inheritance.php @@ -8,6 +8,7 @@ use Feed005\Rank005\RankImpl1; use Feed005\Rank005\RankImpl2; use Feed005\SenderFactory; +require_once 'plain005/plain005.php'; GImportTrait::pubStaticFn(); $mmm = new GImportTrait; @@ -32,6 +33,7 @@ function printCurDescInherit() { callSend(SenderFactory::createSender('sms')); printCurDescInherit(); +plainPrintCurDescInherit(); Common005\CallOthers005::accessGloDer(); Common005\CallOthers005::accessMessage(); diff --git a/tests/php/005_inheritance/ConnectNoMod005/ErrNoMod005.php b/tests/php/005_inheritance/ConnectNoMod005/ErrNoMod005.php new file mode 100644 index 0000000..0ca8653 --- /dev/null +++ b/tests/php/005_inheritance/ConnectNoMod005/ErrNoMod005.php @@ -0,0 +1,6 @@ +