Hoppa till innehåll

Parser

Phasis tillhandahåller sin JavaScript-parser som ett fristående PHP API. Du kan parsa källtext till en typad AST, traversera den och exportera den som ESTree-formade arrayer eller JSON utan att skapa en Engine eller köra något.

parseSource

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

Ingångspunkten med ett enda anrop på Phasis\Parser\Parser. Parsar $source och returnerar rotnoden 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 väljer grammatikens mål, namngivet efter samma alternativ i parsers för JS:

Värde Mål
script klassiskt Script. import/export på toppnivå är syntaxfel, await är en identifierare
module ES-modul. Implicit strikt läge; import/export och await på toppnivå kan parsas

Alla andra värden kastar \InvalidArgumentException.

För mer detaljerad kontroll (förinställning av strikt läge för en direct-eval-kontext, läsning av //# sourceURL-pragmat) konstruerar du parsern direkt: new Parser($source) plus setModuleMode(), setStrictMode() och parse().

Noder

Varje AST-klass utökar Phasis\Ast\Node och finns under Phasis\Ast\{Declaration, Expression, Pattern, Statement}. Noderna är vanliga skrivskyddade värdeobjekt:

  • $node->type() returnerar nodens typsträng, som är klassens basnamn ('BinaryExpression', 'ArrowFunction', ...).
  • $node->location är en Phasis\Lexer\SourceLocation med line (1-baserad), column (0-baserad) och offset (byteförskjutning). Endast startpositioner lagras; noder har ingen slutposition.
  • Alla andra offentliga fält är nodens barn och attribut ($binary->left, $binary->operator, $binary->right).

De flesta typnamn motsvarar ESTree. Avvikelserna:

Typ i Phasis ESTree-typ
ArrowFunction ArrowFunctionExpression
TaggedTemplate TaggedTemplateExpression
ClassMethod MethodDefinition
ClassProperty PropertyDefinition
AssignmentProperty Property (inuti ObjectPattern)
ExportDeclaration ExportNamedDeclaration / ExportDefaultDeclaration / ExportAllDeclaration
ImportSpecifier ImportSpecifier / ImportDefaultSpecifier / ImportNamespaceSpecifier

Några få former skiljer sig också: klasskroppar är en vanlig elementarray på klassnoden (utan omslaget ClassBody), import-/exportnamn, satsnamn och namn på FunctionExpression lagras som strängar i stället för nästlade noder av typen Identifier, och super parsas som en Identifier med namnet super (det finns ingen nodklass för Super). Phasis\Ast\EstreeSerializer omformar allt detta till ESTree-formatet.

Syntaxfel

Ogiltig indata kastar Phasis\Exceptions\SyntaxError (vanligen dess underklass Phasis\Parser\ParseError). Undantagsmeddelandet avslutas med positionen, och den strukturerade platsen finns på undantaget:

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
}

Traverserare

Phasis\Ast\Walker traverserar ett träd djupet först med callbacks för enter/leave, i stil med estraverse:

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

Båda callbacks tar emot (Node $node, ?Node $parent). Om $enter returnerar Walker::SKIP hoppas nodens barn över; nodens egen $leave körs ändå.

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

Traverseringen är skrivskyddad. Noderna är skrivskyddade värdeobjekt, så det går inte att ersätta eller mutera dem.

Serialiserare

Phasis\Ast\Serializer konverterar den typade AST:n till arrayer eller JSON med typnamn och fältlayout enligt Phasis, och tar bort cachefält som är interna för parsern:

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

Det här är formatet som bin/phasis --ast skriver ut.

EstreeSerializer

Phasis\Ast\EstreeSerializer konverterar i stället den typade AST:n till ESTree-formade arrayer: typnamn enligt ESTree (utifrån avvikelsetabellen ovan), ESTree-fältnamn och ordning, genererade noder av typen ClassBody / specifier / source-Literal samt en start-byteförskjutning på varje nod som parsats från källan. Det finns inga end-förskjutningar eftersom noder bara lagrar startpositioner, och strängnoder av typen Literal innehåller ingen text i 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() genererar en deterministisk sammanfattning med en rad per nod (typ plus attributen name= / value= / op= / kind=, två blanksteg per indenteringsnivå). Formatet är byteidentiskt med AST-sammanfattningen som acorn-fixturen i tests/Popular/acorn genererar, så samma oracle testar både parsersökvägen JS och denna export av typen 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 parsar en fil (Script-mål) och skriver ut Serializer JSON-dumpen med två blankstegs indrag. Se CLI för en fullständig referens till flaggorna.