Gå til indhold

Parser

Phasis stiller sin JavaScript-parser til rådighed som en selvstændig PHP API. Du kan parse kildetekst til et typet AST, gennemløbe det og eksportere det som ESTree-formede arrays eller JSON uden at oprette en Engine eller udføre noget.

parseSource

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

Indgangspunktet med ét kald på Phasis\Parser\Parser. Parser $source og returnerer rodknuden 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ælger grammatikmålet, opkaldt efter den samme indstilling i JS-parsers:

Værdi Mål
script klassisk Script. import/export på øverste niveau er syntaksfejl, await er en identifikator
module ES-modul. Implicit strict mode, import/export og await på øverste niveau parses

Alle andre værdier udløser \InvalidArgumentException.

Hvis du har brug for finere kontrol (forudindstil strict mode til en direkte eval-kontekst, læs //# sourceURL-pragmaet), skal du konstruere parseren direkte: new Parser($source) plus setModuleMode(), setStrictMode() og parse().

Knuder

Hver AST-klasse udvider Phasis\Ast\Node og findes under Phasis\Ast\{Declaration, Expression, Pattern, Statement}. Knuderne er skrivebeskyttede værdiobjekter uden anden funktionalitet:

  • $node->type() returnerer knudens typ streng, som er klassens basenavn ('BinaryExpression', 'ArrowFunction', ...).
  • $node->location er en Phasis\Lexer\SourceLocation med line (1-baseret), column (0-baseret) og offset (byteforskydning). Kun startpositioner gemmes; knuder har ingen slutposition.
  • Alle andre offentlige felter er knudens underknuder og attributter ($binary->left, $binary->operator, $binary->right).

De fleste typenavne følger ESTree. Afvigelserne:

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

Nogle former er også forskellige: klasseblokke er et almindeligt elementarray på klassenoden (uden wrapperen ClassBody), import-/eksportnavne, sætningsetiketter og FunctionExpression-navne gemmes som strenge i stedet for indlejrede Identifier-knuder, og super parses som en Identifier med navnet super (der findes ingen Super-klasse). Phasis\Ast\EstreeSerializer omformer alt dette til ESTree-formatet.

Syntaksfejl

Ugyldigt input udløser Phasis\Exceptions\SyntaxError (normalt dens underklasse Phasis\Parser\ParseError). Undtagelsesmeddelelsen slutter med positionen, og den strukturerede placering findes på undtagelsen:

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
}

Gennemløber

Phasis\Ast\Walker gennemløber et træ i dybden med enter-/leave-callbacks, efter samme mønster som estraverse:

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

Begge callbacks modtager (Node $node, ?Node $parent). Hvis $enter returnerer Walker::SKIP, springes knudens underknuder over; knudens egen $leave udføres stadig.

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

Gennemløbet er skrivebeskyttet. Knuderne er skrivebeskyttede værdiobjekter, så de kan ikke erstattes eller ændres.

Serialisator

Phasis\Ast\Serializer konverterer det typede AST til arrays eller JSON ved hjælp af Phasis-typenavne og feltlayoutet, mens parserens interne cachefelter fjernes:

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

Dette er det format, bin/phasis --ast udskriver.

EstreeSerializer

Phasis\Ast\EstreeSerializer konverterer i stedet det typede AST til arrays formet efter ESTree: ESTree-typenavne (ifølge afvigelsestabellen ovenfor), ESTree-feltnavne og -rækkefølge, syntetiserede ClassBody / specifikator- / source-Literal-noder samt en start-byteforskydning på hver node, der parses fra kildekoden. Der er ingen end-forskydninger, fordi noder kun gemmer startpositioner, og streng-Literal-noder ikke indeholder nogen raw-tekst.

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() udsender en deterministisk oversigt med én linje pr. node (type plus attributterne name= / value= / op= / kind=, indrykning på to mellemrum pr. dybdeniveau). Formatet er byteidentisk med AST-oversigten, som acorn-fixturen i tests/Popular/acorn producerer, så den samme oracle kontrollerer både parserstien for JS og denne eksport fra 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 parser en fil (script-mål) og udskriver Serializer-JSON-dumpet med indrykning på to mellemrum. Se CLI for den fulde oversigt over flag.