
# Analizatorius

Phasis pateikia savo JavaScript analizatorių kaip atskirą PHP API. Šaltinio tekstą galite analizuoti į tipizuotą AST, pereiti per jį ir eksportuoti kaip ESTree formos masyvus arba JSON, nekurdami `Engine` ir nieko nevykdydami.

## parseSource

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

Vieno iškvietimo įvesties taškas, skirtas `Phasis\Parser\Parser`. Analizuoja `$source` ir grąžina šakninį `Phasis\Ast\Program` mazgą.

```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` parenka gramatikos tikslą, pavadintą taip pat kaip ta pati parinktis JS analizatoriuose:

| Reikšmė | Tikslas |
|---|---|
| `script` | klasikinis scenarijus. Aukščiausio lygio `import`/`export` yra sintaksės klaidos, `await` yra identifikatorius |
| `module` | ES modulis. Veikia numanomai griežtuoju režimu, analizuojami `import`/`export` ir aukščiausio lygio `await` |

Bet kuri kita reikšmė iškelia `\InvalidArgumentException`.

Jei reikia tikslesnio valdymo (iš anksto įjungti griežtąjį režimą tiesioginio eval kontekste, nuskaityti `//# sourceURL` direktyvą), sukurkite analizatorių tiesiogiai: `new Parser($source)` kartu su `setModuleMode()`, `setStrictMode()` ir `parse()`.

## Mazgai

Kiekviena AST klasė išplečia `Phasis\Ast\Node` ir yra `Phasis\Ast\{Declaration, Expression, Pattern, Statement}`. Mazgai yra paprasti tik skaitomi reikšmių objektai:

- `$node->type()` grąžina mazgo tipo eilutę, t. y. klasės bazinį pavadinimą (`'BinaryExpression'`, `'ArrowFunction'`, ...).
- `$node->location` yra `Phasis\Lexer\SourceLocation` su `line` (nuo 1), `column` (nuo 0) ir `offset` (baito poslinkiu). Išsaugomos tik pradžios pozicijos; mazgai neturi pabaigos poslinkio.
- Visi kiti viešieji laukai yra mazgo vaikai ir atributai (`$binary->left`, `$binary->operator`, `$binary->right`).

Dauguma tipų pavadinimų sutampa su [ESTree](https://github.com/estree/estree). Skirtumai:

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

Kai kurios struktūros taip pat skiriasi: klasių turinys klasės mazge yra paprastas elementų masyvas (be `ClassBody` apvalkalo), importavimo ir eksportavimo pavadinimai, sakinių žymos bei `FunctionExpression` pavadinimai saugomi kaip eilutės, o ne įdėtiniai `Identifier` mazgai; be to, `super` analizuojamas kaip `Identifier` pavadinimu `super` (klasės `Super` mazgo nėra). `Phasis\Ast\EstreeSerializer` visa tai pertvarko į ESTree formą.

## Sintaksės klaidos

Netaisyklinga įvestis iškelia `Phasis\Exceptions\SyntaxError` (paprastai jos poklasį `Phasis\Parser\ParseError`). Išimties pranešimo pabaigoje nurodoma pozicija, o struktūrizuotą vietą galima rasti išimtyje:

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

## Pereiklis

`Phasis\Ast\Walker` pereina medį gilyn pirmiausia, vykdydamas įėjimo ir išėjimo atgalinio iškvietimo funkcijas, kaip estraverse:

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

Abi atgalinio iškvietimo funkcijos gauna `(Node $node, ?Node $parent)`. Jei iš `$enter` grąžinama `Walker::SKIP`, mazgo vaikai praleidžiami; paties mazgo `$leave` vis tiek iškviečiama.

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

Pereinama tik skaitant. Mazgai yra tik skaitomi reikšmių objektai, todėl pakeisti ar modifikuoti jų negalima.

## Serializatorius

`Phasis\Ast\Serializer` konvertuoja tipizuotą AST į masyvus arba JSON, naudodamas Phasis tipų pavadinimus ir laukų išdėstymą; analizatoriaus vidiniai spartinančiosios atmintinės laukai pašalinami:

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

Šį formatą išveda `bin/phasis --ast`.

## EstreeSerializer

`Phasis\Ast\EstreeSerializer` vietoj to konvertuoja tipizuotą AST į ESTree formos masyvus: naudojami ESTree tipų pavadinimai (pagal pirmiau pateiktą skirtumų lentelę), ESTree laukų pavadinimai ir tvarka, sukuriami `ClassBody` / specifikatoriaus / šaltinio `Literal` mazgai, o kiekviename iš šaltinio išanalizuotame mazge nurodomas `start` baito poslinkis. `end` poslinkių nėra, nes mazguose saugomos tik pradžios pozicijos, o eilutės `Literal` mazguose nėra `raw` teksto.

```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()` pateikia deterministinę santrauką po vieną eilutę kiekvienam mazgui (tipas ir `name=` / `value=` / `op=` / `kind=` atributai, kiekvienas įdėtumo lygis įtraukiamas dviem tarpais). Formatas baitas po baito sutampa su AST santrauka, kurią pateikia acorn etalonas `tests/Popular/acorn`, todėl tas pats etalonas tikrina ir JS analizatoriaus kelią, ir šį PHP eksportą:

```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` analizuoja failą (scenarijaus tikslas) ir išveda `Serializer` JSON išrašą, įtraukdamas eilutes dviem tarpais. Visą parinkčių aprašą rasite čia: [CLI](https://phasis.inline0.dev/lt/docs/cli).
