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
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.
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->locationjePhasis\Lexer\SourceLocationzline(od 1),column(od 0) inoffset(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:
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:
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.
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:
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.
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:
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.