
# Parser

Phasis zpřístupňuje svůj parser JavaScript jako samostatné PHP API. Zdrojový text můžete parsovat do typovaného AST, procházet jej a exportovat jako pole ve tvaru ESTree nebo JSON, aniž byste vytvářeli `Engine` nebo cokoli spouštěli.

## parseSource

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

Vstupní bod pro jedno volání v `Phasis\Parser\Parser`. Parsuje `$source` a vrací kořenový uzel `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` vybírá gramatický cíl, pojmenovaný stejně jako odpovídající volba v parserech JS:

| Hodnota | Cíl |
|---|---|
| `script` | klasický Script. Toplevel `import`/`export` jsou syntaktické chyby, `await` je identifikátor |
| `module` | modul ES. Implicitně striktní režim, parsují se `import`/`export` a nejvyšší `await` |

Jakákoli jiná hodnota vyvolá `\InvalidArgumentException`.

Pro podrobnější řízení (přednastavení striktního režimu pro kontext přímého vyhodnocení, čtení direktivy `//# sourceURL`) vytvořte parser přímo: `new Parser($source)` plus `setModuleMode()`, `setStrictMode()` a `parse()`.

## Uzly

Každá třída AST rozšiřuje `Phasis\Ast\Node` a nachází se pod `Phasis\Ast\{Declaration, Expression, Pattern, Statement}`. Uzly jsou prosté objekty hodnot pouze pro čtení:

- `$node->type()` vrací řetězec typu uzlu, což je název třídy bez jmenného prostoru (`'BinaryExpression'`, `'ArrowFunction'`, ...).
- `$node->location` je `Phasis\Lexer\SourceLocation` s položkami `line` (od 1), `column` (od 0) a `offset` (bajtový posun). Ukládají se pouze počáteční pozice; uzly nemají koncový posun.
- Všechna ostatní veřejná pole představují potomky a atributy uzlu (`$binary->left`, `$binary->operator`, `$binary->right`).

Většina názvů typů odpovídá [ESTree](https://github.com/estree/estree). Odchylky:

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

Liší se také některé tvary: těla tříd jsou na uzlu třídy prostá pole prvků (bez obalu `ClassBody`), názvy importů/exportů, popisky příkazů a názvy `FunctionExpression` jsou uloženy jako řetězce namísto vnořených uzlů `Identifier` a `super` se parsuje jako pojmenovaný `Identifier` typu `super` (třída uzlu `Super` neexistuje). `Phasis\Ast\EstreeSerializer` to vše převede do podoby ESTree.

## Syntaktické chyby

Neplatný vstup vyvolá `Phasis\Exceptions\SyntaxError` (obvykle jeho podtřídu `Phasis\Parser\ParseError`). Zpráva výjimky končí pozicí a strukturované údaje o místě jsou dostupné ve výjimce:

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

## Procházení stromu

`Phasis\Ast\Walker` prochází strom do hloubky pomocí zpětných volání při vstupu a odchodu, ve stylu estraverse:

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

Obě zpětná volání přijímají `(Node $node, ?Node $parent)`. Vrácení hodnoty `Walker::SKIP` z `$enter` přeskočí potomky uzlu; vlastní `$leave` uzlu se přesto zavolá.

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

Procházení je pouze pro čtení. Uzly jsou neměnné objekty hodnot, takže jejich nahrazování ani úpravy nejsou podporovány.

## Serializátor

`Phasis\Ast\Serializer` převádí typovaný AST na pole nebo JSON pomocí názvů typů a rozložení polí Phasis, přičemž odstraňuje interní pole mezipaměti parseru:

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

Toto je formát, který `bin/phasis --ast` vypisuje.

## EstreeSerializer

`Phasis\Ast\EstreeSerializer` místo toho převádí typovaný AST na pole ve tvaru ESTree: názvy typů ESTree (podle výše uvedené tabulky odchylek), názvy a pořadí polí ESTree, syntetizované uzly `ClassBody` / specifier / source-`Literal` a posun v bajtech `start` u každého uzlu parsovaného ze zdroje. Posuny `end` neexistují, protože uzly ukládají pouze počáteční pozice, a řetězcové uzly `Literal` neobsahují text `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()` vytváří deterministický jednořádkový souhrn pro každý uzel (typ plus atributy `name=` / `value=` / `op=` / `kind=`, odsazení o dvě mezery na každou úroveň). Formát je bajt po bajtu totožný se souhrnem AST, který vytváří acorn fixture v `tests/Popular/acorn`, takže stejný oracle ověřuje cestu parseru JS i tento export 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` parsuje soubor (cíl script) a vypisuje výpis `Serializer` JSON s odsazením o dvě mezery. Úplný přehled příznaků najdete v [CLI](https://phasis.inline0.dev/cs/docs/cli).
