
# Parser

Phasis nodrošina savu JavaScript parsētāju kā atsevišķu PHP API. Varat parsēt avota tekstu tipizētā AST, apstaigāt to un eksportēt kā ESTree formas masīvus vai JSON, neveidojot `Engine` un neko neizpildot.

## parseSource

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

Vienas funkcijas ieejas punkts objektā `Phasis\Parser\Parser`. Parsē `$source` un atgriež saknes mezglu `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` izvēlas gramatikas mērķi, kas nosaukts tāpat kā attiecīgā opcija JS parsētājos:

| Vērtība | Mērķis |
|---|---|
| `script` | klasisks Script. Augšējā līmeņa `import`/`export` ir sintakses kļūdas, `await` ir identifikators |
| `module` | ES modulis. Netieši stingrais režīms; tiek parsēti `import`/`export` un augšējā līmeņa `await` |

Jebkura cita vērtība izraisa `\InvalidArgumentException`.

Precīzākai kontrolei (stingrā režīma iepriekšējai iestatīšanai tiešas eval izsaukuma kontekstā, `//# sourceURL` pragmas nolasīšanai) izveidojiet parsētāju tieši: `new Parser($source)` kopā ar `setModuleMode()`, `setStrictMode()` un `parse()`.

## Mezgli

Katra AST klase paplašina `Phasis\Ast\Node` un atrodas zem `Phasis\Ast\{Declaration, Expression, Pattern, Statement}`. Mezgli ir vienkārši tikai lasāmi vērtību objekti:

- `$node->type()` atgriež mezgla tipa virkni, kas ir klases nosaukums bez telpas nosaukuma (`'BinaryExpression'`, `'ArrowFunction'`, ...).
- `$node->location` ir `Phasis\Lexer\SourceLocation` ar `line` (sākot no 1), `column` (sākot no 0) un `offset` (baitu nobīdi). Tiek saglabātas tikai sākuma pozīcijas; mezgliem nav beigu nobīdes.
- Visi pārējie publiskie lauki ir mezgla bērni un atribūti (`$binary->left`, `$binary->operator`, `$binary->right`).

Vairums tipu nosaukumu atbilst [ESTree](https://github.com/estree/estree). Atšķirības:

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

Atšķiras arī dažas struktūras: klases mezgla klases pamatdaļa ir vienkāršs elementu masīvs (bez `ClassBody` ietvara); importēšanas/eksportēšanas nosaukumi, priekšrakstu etiķetes un `FunctionExpression` nosaukumi tiek glabāti kā virknes, nevis ligzdoti `Identifier` mezgli; savukārt `super` tiek parsēts kā `Identifier` ar nosaukumu `super` (nav `Super` mezgla klases). `Phasis\Ast\EstreeSerializer` pārveido to visu ESTree formā.

## Sintakses kļūdas

Nederīga ievade izraisa `Phasis\Exceptions\SyntaxError` (parasti tās apakšklasi `Phasis\Parser\ParseError`). Izņēmuma ziņojums beidzas ar pozīciju, un strukturētā atrašanās vieta ir pieejama izņēmuma objektā:

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

## Apstaigātājs

`Phasis\Ast\Walker` apstaigā koku dziļumā vispirms, izmantojot ieejas un izejas atzvanus, līdzīgi kā estraverse:

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

Abi atzvani saņem `(Node $node, ?Node $parent)`. Ja `$enter` atgriež `Walker::SKIP`, mezgla bērni netiek apstaigāti; paša mezgla `$leave` joprojām tiek izsaukts.

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

Apstaigāšana ir tikai lasāma. Mezgli ir tikai lasāmi vērtību objekti, tāpēc tos nevar aizstāt vai mainīt.

## Serializētājs

`Phasis\Ast\Serializer` pārveido tipizēto AST par masīviem vai JSON, izmantojot Phasis tipu nosaukumus un lauku izkārtojumu, un noņem parsētāja iekšējās kešatmiņas laukus:

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

Šo formātu izvada `bin/phasis --ast`.

## EstreeSerializer

`Phasis\Ast\EstreeSerializer` tipizēto AST pārveido par ESTree formas masīviem: ar ESTree tipu nosaukumiem (atbilstoši iepriekšējai atšķirību tabulai), ESTree lauku nosaukumiem un secību, izveidotiem `ClassBody` / specifikatora / avota-`Literal` mezgliem un `start` baitu nobīdi katram no avota parsētam mezglam. `end` nobīžu nav, jo mezglos tiek glabātas tikai sākuma pozīcijas, un virkņu `Literal` mezglos nav teksta `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()` izvada deterministisku kopsavilkumu vienā rindā katram mezglam (tips un atribūti `name=` / `value=` / `op=` / `kind=`, divu atstarpju atkāpe katram dziļuma līmenim). Formāts baitu līmenī ir identisks AST kopsavilkumam, ko izveido acorn testa dati `tests/Popular/acorn`, tāpēc tas pats etalons pārbauda gan parsētāja ceļu JS, gan šo PHP eksportu:

```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` parsē failu (script mērķī) un izvada `Serializer` JSON izdruku ar divu atstarpju atkāpi. Pilnu karodziņu aprakstu skatiet [CLI](https://phasis.inline0.dev/lv/docs/cli).
