パーサー
PhasisはJavaScriptパーサーを単独のPHP APIとして提供します。ソーステキストを型付きASTに解析し、走査して、ESTree形式の配列またはJSONとしてエクスポートできます。Engineを構築したり、何かを実行したりする必要はありません。
parseSource
public static function parseSource(string $source, string $sourceType = 'script'): Program
Phasis\Parser\Parserの1回の呼び出しで使えるエントリーポイントです。$sourceを解析し、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は文法のゴールを指定します。名前はJSパーサーの同じオプションに由来します。
| 値 | ゴール |
|---|---|
script |
従来のScript。トップレベルのimport/exportは構文エラーになり、awaitは識別子です |
module |
ES Module。暗黙にstrictモードとなり、import/exportとトップレベルのawaitを解析できます |
その他の値を指定すると\InvalidArgumentExceptionがスローされます。
より細かく制御する場合(直接evalするコンテキストでstrictモードを事前に有効化する、//# sourceURLプラグマを読み取るなど)は、パーサーを直接構築します。new Parser($source)に加え、setModuleMode()、setStrictMode()、parse()を指定します。
ノード
すべてのASTクラスはPhasis\Ast\Nodeを継承し、Phasis\Ast\{Declaration, Expression, Pattern, Statement}配下にあります。ノードは読み取り専用の単純な値オブジェクトです。
$node->type()はノードの型文字列(クラスのベース名。'BinaryExpression'、'ArrowFunction'など)を返します。$node->locationはPhasis\Lexer\SourceLocationで、line(1始まり)、column(0始まり)、offset(バイトオフセット)を持ちます。保存されるのは開始位置だけで、ノードに終了オフセットはありません。- それ以外の公開フィールドは、ノードの子要素と属性(
$binary->left、$binary->operator、$binary->right)です。
型名の大半はESTreeに一致します。異なる点は次のとおりです。
| Phasisの型 | ESTreeの型 |
|---|---|
ArrowFunction |
ArrowFunctionExpression |
TaggedTemplate |
TaggedTemplateExpression |
ClassMethod |
MethodDefinition |
ClassProperty |
PropertyDefinition |
AssignmentProperty |
Property(ObjectPattern内) |
ExportDeclaration |
ExportNamedDeclaration / ExportDefaultDeclaration / ExportAllDeclaration |
ImportSpecifier |
ImportSpecifier / ImportDefaultSpecifier / ImportNamespaceSpecifier |
構造にもいくつか違いがあります。クラス本体はクラスノード上の要素配列で、ClassBodyラッパーはありません。import/export名、文ラベル、FunctionExpression名は、入れ子のIdentifierノードではなく文字列として保存されます。また、superはsuperという名前のIdentifierとして解析されます(Superノードクラスはありません)。Phasis\Ast\EstreeSerializerはこれらすべてをESTree形式に変換します。
構文エラー
入力が無効な場合はPhasis\Exceptions\SyntaxError(通常はそのサブクラスのPhasis\Parser\ParseError)がスローされます。例外メッセージの末尾には位置が付き、構造化された位置情報は例外から取得できます。
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
}
ウォーカー
Phasis\Ast\Walkerは、estraverseのようにenter/leaveコールバックを使って、ツリーを深さ優先で走査します。
public static function walk(Node $node, callable $enter, ?callable $leave = null): void
両方のコールバックには(Node $node, ?Node $parent)が渡されます。$enterからWalker::SKIPを返すと、ノードの子要素を走査しません。ノード自身の$leaveは引き続き呼び出されます。
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;
}
});
走査は読み取り専用です。ノードは読み取り専用の値オブジェクトなので、置換や変更には対応していません。
シリアライザー
Phasis\Ast\Serializerは、パーサー内部のキャッシュフィールドを除き、Phasisの型名とフィールド構成を使って型付きASTを配列またはJSONに変換します。
public static function toArray(Node $node): array
public static function toJson(Node $node, bool $pretty = false): string
これはbin/phasis --astが出力する形式です。
EstreeSerializer
Phasis\Ast\EstreeSerializerは型付きASTをESTree形式の配列に変換します。ESTreeの型名(上の差分表に準拠)、ESTreeのフィールド名と順序、合成されたClassBody / specifier / source-Literalノードを使い、ソースから解析された各ノードにstartバイトオフセットを付与します。ノードに保存されるのは開始位置のみなので、endオフセットはありません。また、文字列のLiteralノードには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()は、型とname= / value= / op= / kind=属性を含む、ノードごとの決定的な1行サマリーを出力します(深さごとに2スペースでインデント)。この形式は、tests/Popular/acornのacornフィクスチャが生成するASTサマリーとバイト単位で一致するため、同じオラクルでJSパーサー経路とこの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はファイルを解析し(scriptゴール)、SerializerのJSONダンプを2スペースのインデントで出力します。すべてのフラグの説明はCLIを参照してください。