Lewati ke konten

Parser

Phasis menyediakan parser JavaScript sebagai PHP API mandiri. Anda dapat mem-parse teks sumber menjadi AST bertipe, menelusurinya, lalu mengekspornya sebagai array berbentuk ESTree atau JSON tanpa membuat Engine atau menjalankan apa pun.

parseSource

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

Titik masuk satu pemanggilan pada Phasis\Parser\Parser. Mem-parse $source dan mengembalikan node akar 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 memilih tujuan tata bahasa, dengan nama yang sama seperti opsi pada parser JS:

Nilai Tujuan
script Script klasik. import/export tingkat teratas adalah kesalahan sintaks, await adalah identifier
module Modul ES. Secara implisit strict, import/export dan await tingkat teratas dapat di-parse

Nilai lainnya akan memunculkan \InvalidArgumentException.

Untuk kontrol yang lebih terperinci (menetapkan mode strict terlebih dahulu untuk konteks direct-eval, membaca pragma //# sourceURL), buat parser secara langsung: new Parser($source) beserta setModuleMode(), setStrictMode(), dan parse().

Node

Setiap kelas AST memperluas Phasis\Ast\Node dan berada di bawah Phasis\Ast\{Declaration, Expression, Pattern, Statement}. Node adalah objek nilai readonly biasa:

  • $node->type() mengembalikan string tipe node, yaitu nama dasar kelas ('BinaryExpression', 'ArrowFunction', ...).
  • $node->location adalah Phasis\Lexer\SourceLocation dengan line (mulai dari 1), column (mulai dari 0), dan offset (offset byte). Hanya posisi awal yang disimpan; node tidak memiliki offset akhir.
  • Semua field publik lainnya adalah anak dan atribut node ($binary->left, $binary->operator, $binary->right).

Sebagian besar nama tipe sesuai dengan ESTree. Perbedaannya:

Tipe Phasis Tipe ESTree
ArrowFunction ArrowFunctionExpression
TaggedTemplate TaggedTemplateExpression
ClassMethod MethodDefinition
ClassProperty PropertyDefinition
AssignmentProperty Property (di dalam ObjectPattern)
ExportDeclaration ExportNamedDeclaration / ExportDefaultDeclaration / ExportAllDeclaration
ImportSpecifier ImportSpecifier / ImportDefaultSpecifier / ImportNamespaceSpecifier

Beberapa bentuk juga berbeda: isi kelas berupa array elemen biasa pada node kelas (tanpa wrapper ClassBody), nama import/export, label pernyataan, dan nama FunctionExpression disimpan sebagai string, bukan node Identifier bertingkat, dan super di-parse sebagai Identifier bernama super (tidak ada kelas node Super). Phasis\Ast\EstreeSerializer mengubah semuanya ke bentuk ESTree.

Kesalahan sintaks

Input yang tidak valid memunculkan Phasis\Exceptions\SyntaxError (biasanya subkelasnya, Phasis\Parser\ParseError). Pesan exception diakhiri dengan posisi, dan lokasi terstruktur tersedia pada exception:

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
}

Penelusur

Phasis\Ast\Walker menelusuri pohon secara depth-first dengan callback masuk/keluar, mengikuti gaya estraverse:

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

Kedua callback menerima (Node $node, ?Node $parent). Mengembalikan Walker::SKIP dari $enter memangkas anak-anak node; callback $leave milik node itu sendiri tetap dijalankan.

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

Penelusuran hanya-baca. Node adalah objek nilai readonly, jadi tidak ada dukungan untuk mengganti atau mengubahnya.

Serializer

Phasis\Ast\Serializer mengonversi AST bertipe menjadi array atau JSON menggunakan nama tipe dan tata letak field Phasis, dengan field cache internal parser dihapus:

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

Inilah format yang dicetak oleh bin/phasis --ast.

EstreeSerializer

Phasis\Ast\EstreeSerializer mengonversi AST bertipe menjadi array berbentuk ESTree: nama tipe ESTree (sesuai tabel perbedaan di atas), nama dan urutan field ESTree, node ClassBody / specifier / source-Literal yang disintesis, serta offset byte start pada setiap node yang diurai dari sumber. Tidak ada offset end karena node hanya menyimpan posisi awal, dan node string Literal tidak membawa teks 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() menghasilkan ringkasan deterministik satu baris per node (tipe ditambah atribut name= / value= / op= / kind=, indentasi dua spasi per tingkat kedalaman). Formatnya identik byte demi byte dengan ringkasan AST yang dihasilkan fixture acorn di tests/Popular/acorn, sehingga oracle yang sama memeriksa jalur parser JS dan ekspor PHP ini:

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 mengurai file (tujuan skrip) dan mencetak dump Serializer JSON dengan indentasi dua spasi. Lihat CLIreferensi lengkap semua flag.