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
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.
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->locationadalahPhasis\Lexer\SourceLocationdenganline(mulai dari 1),column(mulai dari 0), danoffset(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:
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:
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.
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:
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.
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:
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.