Preskoči na vsebino

Razčlenjevalnik

Phasis izpostavlja svoj razčlenjevalnik JavaScript kot samostojen PHP API. Izvorno besedilo lahko razčlenite v tipiziran AST, ga prehodite in izvozite kot polja v obliki ESTree ali JSON, ne da bi ustvarili Engine ali karkoli izvedli.

parseSource

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

Enoklicna vstopna točka za Phasis\Parser\Parser. Razčleni $source in vrne korensko vozlišče Phasis\Ast\Program.

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');

$sourceType izbere slovnični cilj, poimenovan enako kot možnost v razčlenjevalnikih JS:

Vrednost Cilj
script klasični Script. Vrhunska import/export sta skladenjski napaki, await pa je identifikator
module modul ES. Implicitno strog način; import/export in vrhnji await se razčlenijo

Katera koli druga vrednost sproži \InvalidArgumentException.

Za podrobnejši nadzor (vnaprejšnja nastavitev strogega načina za kontekst neposrednega eval, branje pragma //# sourceURL) ustvarite razčlenjevalnik neposredno: new Parser($source) ter setModuleMode(), setStrictMode() in parse().

Vozlišča

Vsak razred AST razširja Phasis\Ast\Node in je v prostoru imen Phasis\Ast\{Declaration, Expression, Pattern, Statement}. Vozlišča so navadni objekti vrednosti samo za branje:

  • $node->type() vrne niz tipa vozlišča, ki je osnovno ime razreda ('BinaryExpression', 'ArrowFunction', ...).
  • $node->location je Phasis\Lexer\SourceLocation z line (od 1), column (od 0) in offset (odmik v bajtih). Shranjeni so samo začetni položaji; vozlišča nimajo končnega odmika.
  • Vsa druga javna polja so otroci in atributi vozlišča ($binary->left, $binary->operator, $binary->right).

Večina imen tipov se ujema s ESTree. Odstopanja:

Tip Phasis Tip ESTree
ArrowFunction ArrowFunctionExpression
TaggedTemplate TaggedTemplateExpression
ClassMethod MethodDefinition
ClassProperty PropertyDefinition
AssignmentProperty Property (znotraj ObjectPattern)
ExportDeclaration ExportNamedDeclaration / ExportDefaultDeclaration / ExportAllDeclaration
ImportSpecifier ImportSpecifier / ImportDefaultSpecifier / ImportNamespaceSpecifier

Nekaj oblik se razlikuje: telesa razredov so navadno polje elementov na vozlišču razreda (brez ovoja ClassBody), imena uvoza in izvoza, oznake stavkov ter imena FunctionExpression so shranjena kot nizi namesto kot ugnezdena vozlišča Identifier, super pa se razčleni kot Identifier z imenom super (razred vozlišča Super ne obstaja). Phasis\Ast\EstreeSerializer vse to preoblikuje v obliko ESTree.

Skladenjske napake

Neveljaven vhod sproži Phasis\Exceptions\SyntaxError (običajno njegov podrazred Phasis\Parser\ParseError). Sporočilo izjeme se konča s položajem, strukturirana lokacija pa je na voljo v izjema:

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
}

Sprehod po drevesu

Phasis\Ast\Walker prehodi drevo po globini s povratnimi klici ob vstopu in izstopu, podobno kot estraverse:

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

Oba povratna klica prejmeta (Node $node, ?Node $parent). Če $enter vrne Walker::SKIP, se pregled podrejenih vozlišč preskoči; sproži pa se $leave za samo vozlišče.

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;
    }
});

Prehod je samo za branje. Vozlišča so nespremenljivi objekti vrednosti, zato zamenjava ali spreminjanje nista podprta.

Serializator

Phasis\Ast\Serializer pretvori tipizirani AST v polja ali JSON z uporabo imen tipov in postavitve polj Phasis, pri čemer odstrani notranja polja predpomnilnika razčlenjevalnika:

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

To je oblika, ki jo izpiše bin/phasis --ast.

EstreeSerializer

Phasis\Ast\EstreeSerializer namesto tega pretvori tipizirani AST v polja v obliki ESTree: imena tipov ESTree (glede na zgornjo tabelo odstopanj), imena in vrstni red polj ESTree, ustvarjena vozlišča ClassBody / specifier / source-Literal ter odmik v bajtih start za vsako vozlišče, razčlenjeno iz izvorne kode. Odmikov end ni, ker vozlišča shranjujejo samo začetne položaje; vozlišča nizov Literal pa ne vsebujejo besedila raw.

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

summarize() izpiše determinističen povzetek z eno vrstico na vozlišče (tip ter atributi name= / value= / op= / kind=, zamik dveh presledkov na raven globine). Oblika je bajtno enaka povzetku AST, ki ga ustvari preizkusni primer acorn v tests/Popular/acorn, zato isti referenčni sistem preverja tako pot razčlenjevalnika JS kot ta izvoz PHP:

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

bin/phasis --ast script.js razčleni datoteko (cilj Script) in izpiše izpis Serializer JSON z zamikom dveh presledkov. Za celoten opis zastavic glejte CLI.