
# Elemző

A Phasis önálló PHP API csomagként teszi elérhetővé a saját JavaScript elemzőjét. A forrásszöveg típusos AST-vé elemezhető, bejárható, majd ESTree-alakú tömbként vagy JSON-ként exportálható, mindezt `Engine` létrehozása vagy kód futtatása nélkül.

## parseSource

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

A `Phasis\Parser\Parser` egyhívásos belépési pontja. Elemzi a `$source`-t, majd visszaadja a `Phasis\Ast\Program` gyökércsomópontját.

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

A `$sourceType` választja ki a nyelvtani célt, az JS elemzők azonos nevű beállítása alapján:

| Érték | Cél |
|---|---|
| `script` | klasszikus Script. A legfelső szintű `import`/`export` szintaktikai hibát okoz, a `await` azonosító |
| `module` | ES-modul. Implicit módon szigorú, a `import`/`export` és a legfelső szintű `await` elemezhető |

Minden más érték esetén `\InvalidArgumentException` keletkezik.

Részletesebb vezérléshez (például a szigorú mód előzetes bekapcsolásához közvetlen eval-kontextusban vagy a `//# sourceURL` pragma beolvasásához) hozza létre közvetlenül az elemzőt: `new Parser($source)`, valamint `setModuleMode()`, `setStrictMode()` és `parse()` használatával.

## Csomópontok

Minden AST-osztály a `Phasis\Ast\Node` osztályból származik, és a `Phasis\Ast\{Declaration, Expression, Pattern, Statement}` alatt található. A csomópontok egyszerű, csak olvasható értékobjektumok:

- A `$node->type()` adja vissza a csomópont típusát jelölő karakterláncot, amely az osztály alapneve (`'BinaryExpression'`, `'ArrowFunction'`, ...).
- A `$node->location` egy `Phasis\Lexer\SourceLocation`, amely tartalmazza a `line`-t (1-től számozva), a `column`-t (0-tól számozva) és a `offset`-t (bájtoffset). A rendszer csak a kezdőpozíciókat tárolja; a csomópontok végpozíciót nem tartalmaznak.
- Minden más nyilvános mező a csomópont gyermekét vagy attribútumát jelöli (`$binary->left`, `$binary->operator`, `$binary->right`).

A legtöbb típusnév megegyezik az [ESTree](https://github.com/estree/estree) megfelelőjével. Az eltérések:

| Phasis típus | ESTree-típus |
|---|---|
| `ArrowFunction` | `ArrowFunctionExpression` |
| `TaggedTemplate` | `TaggedTemplateExpression` |
| `ClassMethod` | `MethodDefinition` |
| `ClassProperty` | `PropertyDefinition` |
| `AssignmentProperty` | `Property` (a `ObjectPattern` belsejében) |
| `ExportDeclaration` | `ExportNamedDeclaration` / `ExportDefaultDeclaration` / `ExportAllDeclaration` |
| `ImportSpecifier` | `ImportSpecifier` / `ImportDefaultSpecifier` / `ImportNamespaceSpecifier` |

Néhány adatforma is eltér: az osztály törzse egyszerű elemtömb az osztálycsomóponton (nincs `ClassBody` burkoló), az import/exportnevek, utasításcímkék és `FunctionExpression`-nevek karakterláncként tárolódnak beágyazott `Identifier` csomópontok helyett, a `super` pedig egy `Identifier` típusú, `super` nevű elemként kerül feldolgozásra (nincs `Super` csomópontosztály). A `Phasis\Ast\EstreeSerializer` mindezt ESTree-formára alakítja.

## Szintaktikai hibák

Érvénytelen bemenet esetén `Phasis\Exceptions\SyntaxError` keletkezik (általában az `Phasis\Parser\ParseError` altípusa). A kivételüzenet végén szerepel a pozíció, a strukturált hely pedig a kivétel objektumán érhető el:

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

## Bejáró

A `Phasis\Ast\Walker` mélységi bejárással halad végig a fán, belépési és kilépési visszahívásokkal, az estraverse mintájára:

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

Mindkét visszahívás megkapja a `(Node $node, ?Node $parent)`-t. Ha a `$enter` visszatérési értéke `Walker::SKIP`, a csomópont gyermekei kimaradnak a bejárásból, de a saját `$leave` eseménye továbbra is lefut.

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

A bejárás csak olvasásra szolgál. A csomópontok csak olvasható értékobjektumok, ezért nem támogatott a csere és a módosítás.

## Sorosító

A `Phasis\Ast\Serializer` a típusozott AST-t tömbökké vagy JSON alakítja a Phasis típusnevek és mezőelrendezés használatával, a parser belső gyorsítótármezőinek elhagyásával:

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

Ezt a formátumot írja ki a `bin/phasis --ast`.

## EstreeSerializer

A `Phasis\Ast\EstreeSerializer` ehelyett ESTree-formájú tömbökké alakítja a típusozott AST-t: ESTree-típusneveket (a fenti eltéréstáblázat szerint), ESTree-mezőneveket és -sorrendet, létrehozott `ClassBody` / specifier / source-`Literal` csomópontokat, valamint a forrásból elemzett minden csomóponthoz `start` bájtoffsetet. `end` offset nincs, mert a csomópontok csak kezdőpozíciót tárolnak, a string `Literal` csomópontok pedig nem tartalmaznak `raw` szöveget.

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

A `summarize()` determinisztikus, csomópontonként egysoros összefoglalót készít (típus, valamint `name=` / `value=` / `op=` / `kind=` attribútumok, mélységi szintenként két szóköznyi behúzás). A formátum bájtról bájtra megegyezik azzal az AST-összefoglalóval, amelyet az acorn fixture a `tests/Popular/acorn` alatt készít, így ugyanaz az oracle ellenőrzi a JS parserútvonalat és ezt a PHP exportot is:

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

A `bin/phasis --ast script.js` elemzi a fájlt (script célként), majd kiírja a `Serializer` JSON dumpot két szóközös behúzással. A jelzők teljes leírását lásd: [CLI](https://phasis.inline0.dev/hu/docs/cli).
