
# Parser

Phasis espone il proprio parser JavaScript come PHP API autonomo. Puoi analizzare il testo sorgente in un AST tipizzato, attraversarlo ed esportarlo come array con struttura ESTree o JSON senza creare un `Engine` né eseguire alcunché.

## parseSource

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

Il punto di ingresso con una sola chiamata di `Phasis\Parser\Parser`. Analizza `$source` e restituisce il nodo radice `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` seleziona l'obiettivo grammaticale, denominato come la stessa opzione nei parser JS:

| Valore | Obiettivo |
|---|---|
| `script` | Script classico. `import`/`export` di primo livello sono errori di sintassi, `await` è un identificatore |
| `module` | Modulo ES. Modalità rigorosa implicita; `import`/`export` e `await` di primo livello vengono analizzati |

Qualsiasi altro valore genera `\InvalidArgumentException`.

Per un controllo più preciso (attivazione preventiva della modalità rigorosa per un contesto direct-eval, lettura del pragma `//# sourceURL`), crea direttamente il parser: `new Parser($source)` più `setModuleMode()`, `setStrictMode()` e `parse()`.

## Nodi

Ogni classe AST estende `Phasis\Ast\Node` e si trova sotto `Phasis\Ast\{Declaration, Expression, Pattern, Statement}`. I nodi sono semplici oggetti valore in sola lettura:

- `$node->type()` restituisce la stringa del tipo del nodo, che corrisponde al nome della classe senza namespace (`'BinaryExpression'`, `'ArrowFunction'`, ...).
- `$node->location` è un `Phasis\Lexer\SourceLocation` con `line` (a partire da 1), `column` (a partire da 0) e `offset` (offset in byte). Vengono memorizzate solo le posizioni iniziali; i nodi non contengono un offset finale.
- Tutti gli altri campi pubblici sono figli e attributi del nodo (`$binary->left`, `$binary->operator`, `$binary->right`).

La maggior parte dei nomi dei tipi corrisponde a [ESTree](https://github.com/estree/estree). Le differenze:

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

Anche alcune strutture sono diverse: i corpi delle classi sono semplici array di elementi nel nodo di classe (senza wrapper `ClassBody`); i nomi di import/export, le etichette delle istruzioni e i nomi `FunctionExpression` sono stringhe anziché nodi `Identifier` annidati; inoltre `super` viene analizzato come `Identifier` denominato `super` (non esiste una classe di nodi `Super`). `Phasis\Ast\EstreeSerializer` rimodella tutto secondo il formato ESTree.

## Errori di sintassi

Un input non valido genera `Phasis\Exceptions\SyntaxError` (di solito la sua sottoclasse `Phasis\Parser\ParseError`). Il messaggio dell'eccezione termina con la posizione, mentre la posizione strutturata è disponibile sull'eccezione:

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

## Attraversamento

`Phasis\Ast\Walker` attraversa un albero in profondità, con callback di ingresso/uscita, secondo lo stile di estraverse:

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

Entrambe le callback ricevono `(Node $node, ?Node $parent)`. Se da `$enter` viene restituito `Walker::SKIP`, i nodi figli vengono ignorati, ma viene comunque eseguita la callback `$leave` del nodo stesso.

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

L'attraversamento è in sola lettura. I nodi sono oggetti valore di sola lettura, quindi non è possibile sostituirli o modificarli.

## Serializzatore

`Phasis\Ast\Serializer` converte l’AST tipizzato in array o JSON usando i nomi dei tipi e la struttura dei campi di Phasis, rimuovendo i campi della cache interna del parser:

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

Questo è il formato stampato da `bin/phasis --ast`.

## EstreeSerializer

`Phasis\Ast\EstreeSerializer` converte invece l’AST tipizzato in array strutturati secondo ESTree: nomi dei tipi ESTree (come indicato nella tabella delle differenze sopra), nomi e ordine dei campi ESTree, nodi `ClassBody` / specifier / source-`Literal` sintetizzati e un offset in byte `start` su ogni nodo analizzato dal sorgente. Non ci sono offset `end` perché i nodi memorizzano solo le posizioni iniziali, e i nodi stringa `Literal` non contengono testo `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 riepilogo deterministico, una riga per nodo (tipo più attributi `name=` / `value=` / `op=` / `kind=`, indentazione di due spazi per livello di profondità). Il formato è identico byte per byte al riepilogo AST prodotto dal fixture acorn in `tests/Popular/acorn`, quindi lo stesso oracle verifica sia il percorso del parser JS sia questa esportazione 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` analizza un file (script goal) e stampa il dump `Serializer` JSON con indentazione di due spazi. Per il riferimento completo ai flag, consultate [CLI](https://phasis.inline0.dev/it/docs/cli).
