Saltar al contenido

Analizador

Phasis ofrece su analizador JavaScript como PHP API independiente. Puede analizar texto fuente para obtener un AST tipado, recorrerlo y exportarlo como arrays con forma de ESTree o JSON, sin crear un Engine ni ejecutar nada.

parseSource

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

El punto de entrada de una sola llamada en Phasis\Parser\Parser. Analiza $source y devuelve el nodo raíz 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 selecciona el objetivo gramatical, cuyo nombre coincide con el de la misma opción en los analizadores de JS:

Valor Objetivo
script Script clásico. import/export de nivel superior son errores de sintaxis; await es un identificador
module Módulo ES. Estricto de forma implícita; se pueden analizar import/export y await de nivel superior

Cualquier otro valor produce \InvalidArgumentException.

Para un control más preciso (preactivar el modo estricto en un contexto de evaluación directa, leer la directiva //# sourceURL), cree el analizador directamente: new Parser($source) más setModuleMode(), setStrictMode() y parse().

Nodos

Todas las clases AST extienden Phasis\Ast\Node y se encuentran bajo Phasis\Ast\{Declaration, Expression, Pattern, Statement}. Los nodos son objetos de valor simples y de solo lectura:

  • $node->type() devuelve la cadena de tipo del nodo, que corresponde al nombre base de la clase ('BinaryExpression', 'ArrowFunction', ...).
  • $node->location es un Phasis\Lexer\SourceLocation con line (base 1), column (base 0) y offset (desplazamiento en bytes). Solo se almacenan las posiciones iniciales; los nodos no incluyen desplazamiento final.
  • Todos los demás campos públicos son los hijos y atributos del nodo ($binary->left, $binary->operator, $binary->right).

La mayoría de los nombres de tipo coinciden con ESTree. Estas son las diferencias:

Tipo de Phasis Tipo de ESTree
ArrowFunction ArrowFunctionExpression
TaggedTemplate TaggedTemplateExpression
ClassMethod MethodDefinition
ClassProperty PropertyDefinition
AssignmentProperty Property (dentro de ObjectPattern)
ExportDeclaration ExportNamedDeclaration / ExportDefaultDeclaration / ExportAllDeclaration
ImportSpecifier ImportSpecifier / ImportDefaultSpecifier / ImportNamespaceSpecifier

Algunas formas también difieren: los cuerpos de clase son un array simple de elementos en el nodo de clase (sin envoltorio ClassBody); los nombres de importación/exportación, las etiquetas de instrucciones y los nombres de FunctionExpression se almacenan como cadenas en lugar de nodos Identifier anidados; y super se analiza como un Identifier llamado super (no existe una clase de nodo Super). Phasis\Ast\EstreeSerializer transforma todo esto al formato ESTree.

Errores de sintaxis

La entrada no válida produce Phasis\Exceptions\SyntaxError (normalmente su subclase Phasis\Parser\ParseError). El mensaje de excepción termina con la posición, y la ubicación estructurada está disponible en la excepción:

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
}

Recorrido

Phasis\Ast\Walker recorre un árbol en profundidad con devoluciones de llamada de entrada y salida, al estilo de estraverse:

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

Ambas devoluciones de llamada reciben (Node $node, ?Node $parent). Si $enter devuelve Walker::SKIP, se omiten los hijos del nodo; aun así, se ejecuta su propio $leave.

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

El recorrido es de solo lectura. Los nodos son objetos de valor de solo lectura, por lo que no se pueden reemplazar ni modificar.

Serializador

Phasis\Ast\Serializer convierte el AST tipado en arrays o JSON usando los nombres de tipo y la disposición de campos de Phasis, y elimina los campos de caché internos del analizador:

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

Este es el formato que imprime bin/phasis --ast.

EstreeSerializer

Phasis\Ast\EstreeSerializer convierte el AST tipado en arrays con forma de ESTree: nombres de tipo de ESTree (según la tabla de diferencias anterior), nombres y orden de campos de ESTree, nodos ClassBody / de especificador / de origen-Literal sintetizados y un desplazamiento en bytes start en cada nodo analizado a partir del código fuente. No hay desplazamientos end porque los nodos solo almacenan posiciones iniciales, y los nodos de cadena Literal no contienen texto 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() genera un resumen determinista de una línea por nodo (tipo y atributos name= / value= / op= / kind=, con sangría de dos espacios por nivel). El formato es idéntico byte por byte al resumen AST que produce el accesorio de prueba de acorn en tests/Popular/acorn, así que el mismo oráculo evalúa tanto la ruta del analizador JS como esta exportación de 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 analiza un archivo (objetivo Script) e imprime el volcado Serializer JSON con sangría de dos espacios. Consulte CLI para ver la referencia completa de opciones.