Parser
Phasis zpřístupňuje svůj parser JavaScript jako samostatné PHP API. Zdrojový text můžete parsovat do typovaného AST, procházet jej a exportovat jako pole ve tvaru ESTree nebo JSON, aniž byste vytvářeli Engine nebo cokoli spouštěli.
parseSource
public static function parseSource(string $source, string $sourceType = 'script'): Program
Vstupní bod pro jedno volání v Phasis\Parser\Parser. Parsuje $source a vrací kořenový uzel Phasis\Ast\Program.
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 vybírá gramatický cíl, pojmenovaný stejně jako odpovídající volba v parserech JS:
| Hodnota | Cíl |
|---|---|
script |
klasický Script. Toplevel import/export jsou syntaktické chyby, await je identifikátor |
module |
modul ES. Implicitně striktní režim, parsují se import/export a nejvyšší await |
Jakákoli jiná hodnota vyvolá \InvalidArgumentException.
Pro podrobnější řízení (přednastavení striktního režimu pro kontext přímého vyhodnocení, čtení direktivy //# sourceURL) vytvořte parser přímo: new Parser($source) plus setModuleMode(), setStrictMode() a parse().
Uzly
Každá třída AST rozšiřuje Phasis\Ast\Node a nachází se pod Phasis\Ast\{Declaration, Expression, Pattern, Statement}. Uzly jsou prosté objekty hodnot pouze pro čtení:
$node->type()vrací řetězec typu uzlu, což je název třídy bez jmenného prostoru ('BinaryExpression','ArrowFunction', ...).$node->locationjePhasis\Lexer\SourceLocations položkamiline(od 1),column(od 0) aoffset(bajtový posun). Ukládají se pouze počáteční pozice; uzly nemají koncový posun.- Všechna ostatní veřejná pole představují potomky a atributy uzlu (
$binary->left,$binary->operator,$binary->right).
Většina názvů typů odpovídá ESTree. Odchylky:
| Typ Phasis | Typ ESTree |
|---|---|
ArrowFunction |
ArrowFunctionExpression |
TaggedTemplate |
TaggedTemplateExpression |
ClassMethod |
MethodDefinition |
ClassProperty |
PropertyDefinition |
AssignmentProperty |
Property (uvnitř ObjectPattern) |
ExportDeclaration |
ExportNamedDeclaration / ExportDefaultDeclaration / ExportAllDeclaration |
ImportSpecifier |
ImportSpecifier / ImportDefaultSpecifier / ImportNamespaceSpecifier |
Liší se také některé tvary: těla tříd jsou na uzlu třídy prostá pole prvků (bez obalu ClassBody), názvy importů/exportů, popisky příkazů a názvy FunctionExpression jsou uloženy jako řetězce namísto vnořených uzlů Identifier a super se parsuje jako pojmenovaný Identifier typu super (třída uzlu Super neexistuje). Phasis\Ast\EstreeSerializer to vše převede do podoby ESTree.
Syntaktické chyby
Neplatný vstup vyvolá Phasis\Exceptions\SyntaxError (obvykle jeho podtřídu Phasis\Parser\ParseError). Zpráva výjimky končí pozicí a strukturované údaje o místě jsou dostupné ve výjimce:
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
}
Procházení stromu
Phasis\Ast\Walker prochází strom do hloubky pomocí zpětných volání při vstupu a odchodu, ve stylu estraverse:
public static function walk(Node $node, callable $enter, ?callable $leave = null): void
Obě zpětná volání přijímají (Node $node, ?Node $parent). Vrácení hodnoty Walker::SKIP z $enter přeskočí potomky uzlu; vlastní $leave uzlu se přesto zavolá.
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;
}
});
Procházení je pouze pro čtení. Uzly jsou neměnné objekty hodnot, takže jejich nahrazování ani úpravy nejsou podporovány.
Serializátor
Phasis\Ast\Serializer převádí typovaný AST na pole nebo JSON pomocí názvů typů a rozložení polí Phasis, přičemž odstraňuje interní pole mezipaměti parseru:
public static function toArray(Node $node): array
public static function toJson(Node $node, bool $pretty = false): string
Toto je formát, který bin/phasis --ast vypisuje.
EstreeSerializer
Phasis\Ast\EstreeSerializer místo toho převádí typovaný AST na pole ve tvaru ESTree: názvy typů ESTree (podle výše uvedené tabulky odchylek), názvy a pořadí polí ESTree, syntetizované uzly ClassBody / specifier / source-Literal a posun v bajtech start u každého uzlu parsovaného ze zdroje. Posuny end neexistují, protože uzly ukládají pouze počáteční pozice, a řetězcové uzly Literal neobsahují text raw.
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() vytváří deterministický jednořádkový souhrn pro každý uzel (typ plus atributy name= / value= / op= / kind=, odsazení o dvě mezery na každou úroveň). Formát je bajt po bajtu totožný se souhrnem AST, který vytváří acorn fixture v tests/Popular/acorn, takže stejný oracle ověřuje cestu parseru JS i tento export 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 parsuje soubor (cíl script) a vypisuje výpis Serializer JSON s odsazením o dvě mezery. Úplný přehled příznaků najdete v CLI.