Ugrás a tartalomhoz

Elemző

A Phasis önálló PHP API csomagként teszi elérhetővé a saját JavaScript elemzőjét. A forrásszöveg típusos AST-vé elemezhető, bejárható, majd ESTree-alakú tömbként vagy JSON-ként exportálható, mindezt Engine létrehozása vagy kód futtatása nélkül.

parseSource

PHP
public static function parseSource(string $source, string $sourceType = 'script'): Program

A Phasis\Parser\Parser egyhívásos belépési pontja. Elemzi a $source-t, majd visszaadja a Phasis\Ast\Program gyökércsomópontját.

PHP
use Phasis\Parser\Parser;

$program = Parser::parseSource('const x = [1, 2].map(n => n * 2);');
$module = Parser::parseSource('import { x } from "./x.js"; export default x;', 'module');

A $sourceType választja ki a nyelvtani célt, az JS elemzők azonos nevű beállítása alapján:

Érték Cél
script klasszikus Script. A legfelső szintű import/export szintaktikai hibát okoz, a await azonosító
module ES-modul. Implicit módon szigorú, a import/export és a legfelső szintű await elemezhető

Minden más érték esetén \InvalidArgumentException keletkezik.

Részletesebb vezérléshez (például a szigorú mód előzetes bekapcsolásához közvetlen eval-kontextusban vagy a //# sourceURL pragma beolvasásához) hozza létre közvetlenül az elemzőt: new Parser($source), valamint setModuleMode(), setStrictMode() és parse() használatával.

Csomópontok

Minden AST-osztály a Phasis\Ast\Node osztályból származik, és a Phasis\Ast\{Declaration, Expression, Pattern, Statement} alatt található. A csomópontok egyszerű, csak olvasható értékobjektumok:

  • A $node->type() adja vissza a csomópont típusát jelölő karakterláncot, amely az osztály alapneve ('BinaryExpression', 'ArrowFunction', ...).
  • A $node->location egy Phasis\Lexer\SourceLocation, amely tartalmazza a line-t (1-től számozva), a column-t (0-tól számozva) és a offset-t (bájtoffset). A rendszer csak a kezdőpozíciókat tárolja; a csomópontok végpozíciót nem tartalmaznak.
  • Minden más nyilvános mező a csomópont gyermekét vagy attribútumát jelöli ($binary->left, $binary->operator, $binary->right).

A legtöbb típusnév megegyezik az ESTree megfelelőjével. Az eltérések:

Phasis típus ESTree-típus
ArrowFunction ArrowFunctionExpression
TaggedTemplate TaggedTemplateExpression
ClassMethod MethodDefinition
ClassProperty PropertyDefinition
AssignmentProperty Property (a ObjectPattern belsejében)
ExportDeclaration ExportNamedDeclaration / ExportDefaultDeclaration / ExportAllDeclaration
ImportSpecifier ImportSpecifier / ImportDefaultSpecifier / ImportNamespaceSpecifier

Néhány adatforma is eltér: az osztály törzse egyszerű elemtömb az osztálycsomóponton (nincs ClassBody burkoló), az import/exportnevek, utasításcímkék és FunctionExpression-nevek karakterláncként tárolódnak beágyazott Identifier csomópontok helyett, a super pedig egy Identifier típusú, super nevű elemként kerül feldolgozásra (nincs Super csomópontosztály). A Phasis\Ast\EstreeSerializer mindezt ESTree-formára alakítja.

Szintaktikai hibák

Érvénytelen bemenet esetén Phasis\Exceptions\SyntaxError keletkezik (általában az Phasis\Parser\ParseError altípusa). A kivételüzenet végén szerepel a pozíció, a strukturált hely pedig a kivétel objektumán érhető el:

PHP
use Phasis\Exceptions\SyntaxError;
use Phasis\Parser\Parser;

try {
    Parser::parseSource("const a = 1;\nconst b = ;");
} catch (SyntaxError $e) {
    echo $e->getMessage();          // Unexpected token (got ; ";") at line 2, column 10
    echo $e->location->line;        // 2
    echo $e->location->column;      // 10
    echo $e->location->offset;      // 23
}

Bejáró

A Phasis\Ast\Walker mélységi bejárással halad végig a fán, belépési és kilépési visszahívásokkal, az estraverse mintájára:

PHP
public static function walk(Node $node, callable $enter, ?callable $leave = null): void

Mindkét visszahívás megkapja a (Node $node, ?Node $parent)-t. Ha a $enter visszatérési értéke Walker::SKIP, a csomópont gyermekei kimaradnak a bejárásból, de a saját $leave eseménye továbbra is lefut.

PHP
use Phasis\Ast\Expression\Identifier;
use Phasis\Ast\Node;
use Phasis\Ast\Walker;

$names = [];
Walker::walk($program, function (Node $node) use (&$names) {
    if ($node instanceof Identifier) {
        $names[] = $node->name;
    }
    if ($node instanceof \Phasis\Ast\Expression\ArrowFunction) {
        return Walker::SKIP;
    }
});

A bejárás csak olvasásra szolgál. A csomópontok csak olvasható értékobjektumok, ezért nem támogatott a csere és a módosítás.

Sorosító

A Phasis\Ast\Serializer a típusozott AST-t tömbökké vagy JSON alakítja a Phasis típusnevek és mezőelrendezés használatával, a parser belső gyorsítótármezőinek elhagyásával:

PHP
public static function toArray(Node $node): array
public static function toJson(Node $node, bool $pretty = false): string

Ezt a formátumot írja ki a bin/phasis --ast.

EstreeSerializer

A Phasis\Ast\EstreeSerializer ehelyett ESTree-formájú tömbökké alakítja a típusozott AST-t: ESTree-típusneveket (a fenti eltéréstáblázat szerint), ESTree-mezőneveket és -sorrendet, létrehozott ClassBody / specifier / source-Literal csomópontokat, valamint a forrásból elemzett minden csomóponthoz start bájtoffsetet. end offset nincs, mert a csomópontok csak kezdőpozíciót tárolnak, a string Literal csomópontok pedig nem tartalmaznak raw szöveget.

PHP
public static function toArray(Node $node): array
public static function toJson(Node $node, bool $pretty = false): string
public static function summarize(Node $node): string

A summarize() determinisztikus, csomópontonként egysoros összefoglalót készít (típus, valamint name= / value= / op= / kind= attribútumok, mélységi szintenként két szóköznyi behúzás). A formátum bájtról bájtra megegyezik azzal az AST-összefoglalóval, amelyet az acorn fixture a tests/Popular/acorn alatt készít, így ugyanaz az oracle ellenőrzi a JS parserútvonalat és ezt a PHP exportot is:

PHP
use Phasis\Ast\EstreeSerializer;
use Phasis\Parser\Parser;

echo EstreeSerializer::summarize(Parser::parseSource('let x = a + 1;'));
// Program
//   VariableDeclaration kind=let
//     VariableDeclarator
//       Identifier name=x
//       BinaryExpression op=+
//         Identifier name=a
//         Literal value=1

CLI

A bin/phasis --ast script.js elemzi a fájlt (script célként), majd kiírja a Serializer JSON dumpot két szóközös behúzással. A jelzők teljes leírását lásd: CLI.