*/ public static function unsupportedSyntax(): iterable { yield 'eval' => [' [' [' [' [' [' [' [' [' [ ' [ ' yield 1; }', 'Fiber and Generator', ]; yield 'Fiber class' => [ ' [ ' [ 'createForNewestSupportedVersion(); $nodes = $parser->parse($source); self::assertNotNull($nodes); $traverser = new NodeTraverser(); $traverser->addVisitor(new NameResolver(null, ['replaceNodes' => false])); $traverser->addVisitor(new NanoSyntaxValidationVisitor( static function (Node $node, string $message): never { throw new RuntimeException($message . ':' . $node->getStartLine()); }, )); $this->expectException(RuntimeException::class); $this->expectExceptionMessage($expected); $traverser->traverse($nodes); } public function testAcceptsNamedClassesAndOrdinaryObjectConstruction(): void { $parser = (new ParserFactory())->createForNewestSupportedVersion(); $nodes = $parser->parse( 'addVisitor(new NameResolver(null, ['replaceNodes' => false])); $traverser->addVisitor(new NanoSyntaxValidationVisitor( static function (Node $node, string $message): never { throw new RuntimeException($message . ':' . $node->getStartLine()); }, )); self::assertCount(2, $traverser->traverse($nodes)); } public function testAcceptsNamespacedUserClassNamedFiber(): void { $parser = (new ParserFactory())->createForNewestSupportedVersion(); $nodes = $parser->parse( 'addVisitor(new NameResolver(null, ['replaceNodes' => false])); $traverser->addVisitor(new NanoSyntaxValidationVisitor( static function (Node $node, string $message): never { throw new RuntimeException($message . ':' . $node->getStartLine()); }, )); self::assertCount(1, $traverser->traverse($nodes)); } public function testFullRuntimeNanoPolicyKeepsGeneratorsButRejectsVmEntrySyntax(): void { $parser = (new ParserFactory())->createForNewestSupportedVersion(); $accepted = $parser->parse( 'addVisitor(new NameResolver(null, ['replaceNodes' => false])); $traverser->addVisitor(new NanoSyntaxValidationVisitor( static function (Node $node, string $message): never { throw new RuntimeException($message . ':' . $node->getStartLine()); }, false, )); self::assertCount(1, $traverser->traverse($accepted)); foreach ([ 'parse($source); self::assertNotNull($nodes); try { $traverser->traverse($nodes); self::fail("Nano policy accepted unsupported source: {$source}"); } catch (RuntimeException) { self::addToAssertionCount(1); } } } }