
# Parser

Phasis udostępnia swój parser JavaScript jako samodzielny PHP API. Możesz parsować tekst źródłowy do typowanego AST, przechodzić po nim i eksportować je jako tablice w formacie ESTree lub JSON bez tworzenia `Engine` ani wykonywania czegokolwiek.

## parseSource

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

Jednopunktowe wejście API w `Phasis\Parser\Parser`. Parsuje `$source` i zwraca węzeł główny `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` wybiera cel gramatyki, nazwany tak samo jak ta opcja w parserach JS:

| Wartość | Cel |
|---|---|
| `script` | klasyczny skrypt. Konstrukcje najwyższego poziomu `import`/`export` są błędami składni, `await` jest identyfikatorem |
| `module` | moduł ES. Domyślnie działa tryb ścisły, parsowane są `import`/`export` oraz `await` najwyższego poziomu |

Każda inna wartość powoduje zgłoszenie `\InvalidArgumentException`.

Aby uzyskać większą kontrolę (wstępnie włączyć tryb ścisły dla kontekstu bezpośredniego eval, odczytać dyrektywę `//# sourceURL`), utwórz parser bezpośrednio: `new Parser($source)` oraz `setModuleMode()`, `setStrictMode()` i `parse()`.

## Węzły

Każda klasa AST rozszerza `Phasis\Ast\Node` i znajduje się pod `Phasis\Ast\{Declaration, Expression, Pattern, Statement}`. Węzły są zwykłymi obiektami tylko do odczytu:

- `$node->type()` zwraca ciąg znaków typu węzła, będący nazwą bazową klasy (`'BinaryExpression'`, `'ArrowFunction'`, ...).
- `$node->location` to `Phasis\Lexer\SourceLocation` z `line` (od 1), `column` (od 0) i `offset` (przesunięciem w bajtach). Zapisane są tylko pozycje początkowe; węzły nie zawierają przesunięcia końcowego.
- Wszystkie pozostałe pola publiczne to elementy podrzędne i atrybuty węzła (`$binary->left`, `$binary->operator`, `$binary->right`).

Większość nazw typów odpowiada [ESTree](https://github.com/estree/estree). Różnice:

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

Różni się również kilka struktur: treści klas są zwykłą tablicą elementów w węźle klasy (bez opakowującego `ClassBody`), nazwy importu/eksportu, etykiety instrukcji i nazwy `FunctionExpression` są przechowywane jako ciągi znaków, a nie zagnieżdżone węzły `Identifier`, a `super` jest parsowane jako `Identifier` o nazwie `super` (nie ma klasy węzła `Super`). `Phasis\Ast\EstreeSerializer` przekształca to wszystko do formatu ESTree.

## Błędy składni

Nieprawidłowe dane wejściowe powodują zgłoszenie `Phasis\Exceptions\SyntaxError` (zwykle jego podklasy `Phasis\Parser\ParseError`). Komunikat wyjątku kończy się pozycją, a ustrukturyzowana lokalizacja jest dostępna w wyjątku:

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

## Walker

`Phasis\Ast\Walker` przechodzi przez drzewo w głąb, wywołując funkcje zwrotne przy wejściu i wyjściu, zgodnie ze stylem estraverse:

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

Obie funkcje zwrotne otrzymują `(Node $node, ?Node $parent)`. Zwrócenie `Walker::SKIP` z `$enter` pomija elementy podrzędne węzła; funkcja `$leave` dla samego węzła nadal zostanie wywołana.

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

Przechodzenie odbywa się tylko do odczytu. Węzły są obiektami tylko do odczytu, więc nie można ich zastępować ani modyfikować.

## Serializator

`Phasis\Ast\Serializer` konwertuje typowane AST do tablic lub JSON, używając nazw typów i układu pól Phasis oraz usuwając wewnętrzne pola pamięci podręcznej parsera:

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

To format wyświetlany przez `bin/phasis --ast`.

## EstreeSerializer

`Phasis\Ast\EstreeSerializer` konwertuje typowane AST zamiast tego do tablic w formacie ESTree: używa nazw typów i kolejności pól ESTree (zgodnie z powyższą tabelą różnic), tworzy syntetyczne węzły `ClassBody` / specifier / source-`Literal` oraz dodaje przesunięcie w bajtach `start` do każdego węzła sparsowanego ze źródła. Nie ma przesunięć `end`, ponieważ węzły przechowują tylko pozycje początkowe, a węzły ciągów znaków `Literal` nie zawierają tekstu `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()` generuje deterministyczne, jednowierszowe podsumowanie każdego węzła (typ oraz atrybuty `name=` / `value=` / `op=` / `kind=`, wcięcie dwoma spacjami na poziom głębokości). Format jest identyczny bajt po bajcie z podsumowaniem AST generowanym przez fixture acorn w `tests/Popular/acorn`, więc ten sam oracle sprawdza zarówno ścieżkę parsera JS, jak i ten eksport 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 plik (cel skryptu) i wyświetla zrzut `Serializer` JSON z wcięciem dwoma spacjami. Pełny opis flag znajduje się w [CLI](https://phasis.inline0.dev/pl/docs/cli).
