
# 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](https://github.com/estree/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](https://phasis.inline0.dev/es/docs/cli) para ver la referencia completa de opciones.
