
# Jäsennin

Phasis tarjoaa JavaScript-jäsentimensä itsenäisenä PHP API -pakettina. Voit jäsentää lähdetekstin tyypitetyksi AST:ksi, käydä sen läpi ja viedä sen ESTree-muotoisina taulukoina tai JSON:na rakentamatta `Engine`:ta tai suorittamatta mitään.

## parseSource

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

Yhden kutsun käynnistyspiste kohteessa `Phasis\Parser\Parser`. Jäsentää `$source`:n ja palauttaa `Phasis\Ast\Program`-juurisolmun.

```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` valitsee kieliopin tavoitteen, joka on nimetty samoin kuin JS-jäsentimien vastaava asetus:

| Arvo | Tavoite |
|---|---|
| `script` | perinteinen Script. Tason ylimmät `import`/`export` ovat syntaksivirheitä, `await` on tunniste |
| `module` | ES-moduuli. Implisiittisesti tiukka tila; `import`/`export` ja ylimmän tason `await` jäsennetään |

Mikä tahansa muu arvo aiheuttaa poikkeuksen `\InvalidArgumentException`.

Tarkempaa hallintaa varten (esimerkiksi tiukan tilan alustaminen suoraa eval-kontekstia varten tai `//# sourceURL`-pragmaan lukeminen) rakenna jäsennin suoraan: `new Parser($source)` sekä `setModuleMode()`, `setStrictMode()` ja `parse()`.

## Solmut

Jokainen AST-luokka perii luokan `Phasis\Ast\Node` ja sijaitsee kohteessa `Phasis\Ast\{Declaration, Expression, Pattern, Statement}`. Solmut ovat tavallisia vain luku -arvo-olioita:

- `$node->type()` palauttaa solmun tyyppimerkkijonon, joka on luokan perusnimi (`'BinaryExpression'`, `'ArrowFunction'`, ...).
- `$node->location` on `Phasis\Lexer\SourceLocation`, jossa on `line` (alkaa arvosta 1), `column` (alkaa arvosta 0) ja `offset` (tavusiirtymä). Tallennettuna ovat vain alkusijainnit; solmuilla ei ole loppusiirtymää.
- Kaikki muut julkiset kentät ovat solmun lapsia ja attribuutteja (`$binary->left`, `$binary->operator`, `$binary->right`).

Useimmat tyyppinimet vastaavat [ESTree](https://github.com/estree/estree)-määritystä. Poikkeamat:

| Phasis-tyyppi | ESTree-tyyppi |
|---|---|
| `ArrowFunction` | `ArrowFunctionExpression` |
| `TaggedTemplate` | `TaggedTemplateExpression` |
| `ClassMethod` | `MethodDefinition` |
| `ClassProperty` | `PropertyDefinition` |
| `AssignmentProperty` | `Property` (kohteen `ObjectPattern` sisällä) |
| `ExportDeclaration` | `ExportNamedDeclaration` / `ExportDefaultDeclaration` / `ExportAllDeclaration` |
| `ImportSpecifier` | `ImportSpecifier` / `ImportDefaultSpecifier` / `ImportNamespaceSpecifier` |

Muutamat rakenteetkin eroavat: luokan runko on luokkasolmun tavallinen elementtitaulukko (ei `ClassBody`-käärettä); tuontien ja vientien nimet, lausetunnisteet sekä `FunctionExpression`-nimet tallennetaan merkkijonoina sisäkkäisten `Identifier`-solmujen sijaan; ja `super` jäsennetään nimetyksi `Identifier`-`super`:ksi (`Super`-solmuluokkaa ei ole). `Phasis\Ast\EstreeSerializer` muokkaa nämä kaikki ESTree-muotoon.

## Syntaksivirheet

Virheellinen syöte aiheuttaa poikkeuksen `Phasis\Exceptions\SyntaxError` (yleensä sen aliluokan `Phasis\Parser\ParseError`). Poikkeusviestin lopussa on sijainti, ja jäsennelty sijainti löytyy poikkeuksesta:

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

## Läpi kävijä

`Phasis\Ast\Walker` käy puun läpi syvyyshaulla ja kutsuu sisäänmeno- ja poistumiskäsittelijöitä estraversen tapaan:

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

Molemmat käsittelijät saavat `(Node $node, ?Node $parent)`-arvon. Jos `$enter` palauttaa arvon `Walker::SKIP`, solmun lapset ohitetaan; solmun oma `$leave` kutsutaan silti.

```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äpikäynti on vain luku -toiminto. Solmut ovat vain luku -arvo-olioita, joten niitä ei voi korvata tai muuttaa.

## Sarjoitin

`Phasis\Ast\Serializer` muuntaa tyypitetyn AST:n taulukoiksi tai JSON-muotoon käyttäen Phasis-tyyppinimiä ja kenttien asettelua. Jäsennyskohtaiset välimuistikentät poistetaan:

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

Tässä muodossa `bin/phasis --ast` tulostaa tuloksen.

## EstreeSerializer

`Phasis\Ast\EstreeSerializer` muuntaa tyypitetyn AST:n sen sijaan ESTree-muotoisiksi taulukoiksi: ESTree-tyyppinimet (yllä olevan poikkeamataulukon mukaan), ESTree-kenttien nimet ja järjestys, luodut `ClassBody`-, määrittely- ja lähde-`Literal`-solmut sekä `start`-tavusiirtymä jokaisessa lähteestä jäsennetyssä solmussa. `end`-siirtymiä ei ole, koska solmuihin tallennetaan vain alkusijainnit; merkkijono-`Literal`-solmuissa ei ole tekstisisältöä `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()` tuottaa deterministisen yhteen riviin solmua kohti sisältävän yhteenvedon (tyyppi sekä `name=` / `value=` / `op=` / `kind=`-attribuutit; sisennys on kaksi välilyöntiä syvyystasoa kohti). Muoto on tavutasolla identtinen AST-yhteenvedon kanssa, jonka kohteen `tests/Popular/acorn` acorn-testiaineisto tuottaa, joten sama vertailuohjelma tarkistaa sekä JS-jäsennyspolun että tämän PHP-viennin:

```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` jäsentää tiedoston (script-tavoite) ja tulostaa `Serializer` JSON -vedoksen kahden välilyönnin sisennyksellä. Katso täydellinen valitsinten viite kohdasta [CLI](https://phasis.inline0.dev/fi/docs/cli).
