
# Analisador sintático

Phasis disponibiliza seu analisador JavaScript como um PHP API independente. Você pode analisar o texto-fonte em uma AST tipada, percorrê-la e exportá-la como arrays no formato ESTree ou JSON, sem construir um `Engine` nem executar nada.

## parseSource

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

O ponto de entrada de chamada única em `Phasis\Parser\Parser`. Analisa `$source` e retorna o nó raiz `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` seleciona o objetivo gramatical, com nomes correspondentes à mesma opção nos analisadores JS:

| Valor | Objetivo |
|---|---|
| `script` | Script clássico. `import`/`export` no nível superior são erros de sintaxe; `await` é um identificador |
| `module` | Módulo ES. Modo estrito implícito; `import`/`export` e `await` no nível superior são analisados |

Qualquer outro valor lança `\InvalidArgumentException`.

Para um controle mais preciso (ativar previamente o modo estrito para um contexto de eval direto ou ler a pragma `//# sourceURL`), construa o analisador diretamente: `new Parser($source)` mais `setModuleMode()`, `setStrictMode()` e `parse()`.

## Nós

Toda classe AST estende `Phasis\Ast\Node` e fica em `Phasis\Ast\{Declaration, Expression, Pattern, Statement}`. Os nós são objetos de valor somente para leitura:

- `$node->type()` retorna a string do tipo do nó, que corresponde ao nome da classe sem o namespace (`'BinaryExpression'`, `'ArrowFunction'`, ...).
- `$node->location` é um `Phasis\Lexer\SourceLocation` com `line` (baseado em 1), `column` (baseado em 0) e `offset` (deslocamento em bytes). Somente as posições iniciais são armazenadas; os nós não têm deslocamento final.
- Todos os outros campos públicos são filhos e atributos do nó (`$binary->left`, `$binary->operator`, `$binary->right`).

A maioria dos nomes de tipo corresponde ao [ESTree](https://github.com/estree/estree). Diferenças:

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

Algumas formas também diferem: os corpos de classe são arrays simples de elementos no nó da classe (sem wrapper `ClassBody`); nomes de importação/exportação, rótulos de instruções e nomes `FunctionExpression` são armazenados como strings, e não como nós `Identifier` aninhados; e `super` é analisado como um `Identifier` denominado `super` (não existe uma classe de nó `Super`). `Phasis\Ast\EstreeSerializer` reformata tudo isso para o formato ESTree.

## Erros de sintaxe

Uma entrada inválida lança `Phasis\Exceptions\SyntaxError` (geralmente sua subclasse `Phasis\Parser\ParseError`). A mensagem da exceção termina com a posição, e a localização estruturada está disponível na exceção:

```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
}
```

## Percursor

`Phasis\Ast\Walker` percorre uma árvore em profundidade, com callbacks de entrada e saída, no estilo do estraverse:

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

Ambos os callbacks recebem `(Node $node, ?Node $parent)`. Retornar `Walker::SKIP` de `$enter` ignora os filhos do nó; ainda assim, o próprio `$leave` do nó é executado.

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

O percurso é somente para leitura. Os nós são objetos de valor somente para leitura, portanto não há suporte para substituí-los ou modificá-los.

## Serializador

`Phasis\Ast\Serializer` converte a AST tipada em arrays ou JSON usando os nomes de tipo e a disposição de campos de Phasis, removendo os campos de cache internos do parser:

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

Este é o formato que `bin/phasis --ast` imprime.

## EstreeSerializer

`Phasis\Ast\EstreeSerializer` converte a AST tipada em arrays no formato ESTree: nomes de tipo ESTree (conforme a tabela de divergências acima), nomes e ordenação de campos ESTree, nós `ClassBody` / especificador / origem-`Literal` sintetizados e um deslocamento em bytes `start` em cada nó analisado a partir da origem. Não há deslocamentos `end`, pois os nós armazenam apenas posições iniciais, e os nós de string `Literal` não contêm 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()` emite um resumo determinístico, com uma linha por nó (tipo mais atributos `name=` / `value=` / `op=` / `kind=`, indentação de dois espaços por nível). O formato é idêntico byte a byte ao resumo da AST produzido pelo fixture do acorn em `tests/Popular/acorn`, portanto o mesmo oráculo verifica tanto o caminho do parser JS quanto esta exportação 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` analisa um arquivo (objetivo de script) e imprime o despejo `Serializer` JSON com indentação de dois espaços. Consulte [CLI](https://phasis.inline0.dev/pt/docs/cli) para ver a referência completa das opções.
