Treci la conținut

Analizator sintactic

Phasis oferă analizatorul său JavaScript ca PHP API independent. Puteți analiza textul sursă într-un AST tipizat, îl puteți parcurge și exporta ca tablouri în format ESTree sau JSON fără să construiți un Engine și fără să executați nimic.

parseSource

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

Punctul de intrare cu un singur apel din Phasis\Parser\Parser. Analizează $source și returnează nodul rădăcină 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 selectează obiectivul gramatical, denumit după aceeași opțiune din analizatoarele JS:

Valoare Obiectiv
script script clasic. import/export de nivel superior sunt erori de sintaxă, await este un identificator
module modul ES. Strict implicit; import/export și await de nivel superior sunt analizate

Orice altă valoare aruncă \InvalidArgumentException.

Pentru control mai fin (activarea modului strict în prealabil pentru un context direct-eval, citirea directivei //# sourceURL), construiți direct analizatorul: new Parser($source) plus setModuleMode(), setStrictMode() și parse().

Noduri

Fiecare clasă AST extinde Phasis\Ast\Node și se află în Phasis\Ast\{Declaration, Expression, Pattern, Statement}. Nodurile sunt obiecte simple, doar pentru citire:

  • $node->type() returnează șirul tipului nodului, care este numele de bază al clasei ('BinaryExpression', 'ArrowFunction', ...).
  • $node->location este un Phasis\Lexer\SourceLocation cu line (de la 1), column (de la 0) și offset (poziția în octeți). Sunt stocate doar pozițiile de început; nodurile nu conțin poziția de sfârșit.
  • Toate celelalte câmpuri publice sunt copiii și atributele nodului ($binary->left, $binary->operator, $binary->right).

Majoritatea numelor de tip se potrivesc cu ESTree. Abaterile:

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

Și câteva forme diferă: corpurile claselor sunt un tablou simplu de elemente pe nodul clasei (fără wrapper ClassBody); numele de import/export, etichetele instrucțiunilor și numele FunctionExpression sunt stocate ca șiruri, nu ca noduri Identifier imbricate; iar super este analizat ca Identifier numit super (nu există o clasă de nod Super). Phasis\Ast\EstreeSerializer remodelează toate acestea în formatul ESTree.

Erori de sintaxă

O intrare nevalidă aruncă Phasis\Exceptions\SyntaxError (de obicei subclasa sa Phasis\Parser\ParseError). Mesajul excepției se termină cu poziția, iar localizarea structurată este disponibilă în excepție:

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
}

Parcurgător

Phasis\Ast\Walker parcurge arborele în adâncime, cu apeluri inverse la intrare și la ieșire, după modelul estraverse:

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

Ambele apeluri inverse primesc (Node $node, ?Node $parent). Returnarea lui Walker::SKIP din $enter omite copiii nodului; apelul invers propriu al nodului pentru $leave este totuși executat.

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

Parcurgerea este doar pentru citire. Nodurile sunt obiecte de valoare doar pentru citire, deci nu există funcționalitate de înlocuire sau modificare.

Serializator

Phasis\Ast\Serializer convertește AST-ul tipizat în tablouri sau JSON, folosind numele de tip și structura câmpurilor Phasis, după eliminarea câmpurilor cache interne analizatorului:

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

Acesta este formatul afișat de bin/phasis --ast.

EstreeSerializer

Phasis\Ast\EstreeSerializer convertește AST-ul tipizat în tablouri în format ESTree: nume de tip ESTree (conform tabelului de abateri de mai sus), nume și ordine a câmpurilor ESTree, noduri ClassBody / specifier / source-Literal sintetizate și o poziție în octeți start pentru fiecare nod analizat din sursă. Nu există poziții end deoarece nodurile stochează doar pozițiile de început, iar nodurile Literal de tip șir nu conțin textul 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() generează un rezumat determinist, cu un singur rând per nod (tip plus atributele name= / value= / op= / kind=, indentare de două spații pentru fiecare nivel de adâncime). Formatul este identic la nivel de octet cu rezumatul AST produs de fixture-ul acorn din tests/Popular/acorn, astfel încât același oracle verifică atât calea analizatorului JS, cât și acest export 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 analizează un fișier (obiectiv de tip script) și afișează rezultatul Serializer JSON, cu indentare de două spații. Consultați CLI pentru referința completă a opțiunilor.