
# Architektura

Phasis je čtyřstupňový stromový interpret s příležitostným využitím virtuálního stroje pro bajtkód. Tok dat je následující:

```
JS text
  │
  ▼
┌──────────┐
│  Lexer   │  src/Lexer/
└────┬─────┘
     ▼ tokens
┌──────────┐
│  Parser  │  src/Parser/
└────┬─────┘
     ▼ AST nodes
┌──────────────┐
│ Interpreter  │  src/Runtime/
│  + Bytecode  │  src/Bytecode/
│      VM      │
└────┬─────────┘
     ▼ JsValue
PHP host
```

Každá fáze je třída PHP s jednoduchým rozhraním, které využívá následující fáze. Krok propojování chybí — parsování vytvoří AST a interpret jej prochází přímo.

## Lexer

`src/Lexer/Lexer.php` převádí zdrojový text na proud instancí `Token`. Každý token je neměnná struktura: typ (výčet `TokenType`, přibližně 80 možností), hodnota, řádek a sloupec.

Lexer zpracovává:

- Číselné literály — desítkové, šestnáctkové (`0x`), osmičkové (`0o`), binární (`0b`), exponenciální a s oddělovači číslic.
- Řetězcové literály — jednoduché a dvojité uvozovky, všechny escape sekvence, šablonové literály s vnořenými výrazy.
- Literály regulárních výrazů — úplné tokenizování `/pattern/flags` se zohledněním toho, kdy má být `/` regulární výraz a kdy dělení.
- Identifikátory, klíčová slova, interpunkce.
- Komentáře (řádkové i blokové), které se zachovávají jako trivia.
- Zdroj Unicode — bajty UTF-8 interpretované jako zdroj JS v UTF-16.

Výstupem je generátor, který postupně předává tokeny. Parser je zpracovává s jednokomponentním předstihem.

## Parser

`src/Parser/Parser.php` je ručně napsaný Prattův parser. Priorita výrazů je definována v `src/Parser/Precedence.php`. Příkazy používají vlastní rekurzivní sestup.

Vytváří neměnné uzly AST z `src/Ast/`. Každý uzel uchovává umístění ve zdrojovém kódu pro trasování zásobníku a hlášení chyb.

Významné tvary:

- **Výraz**: `Literal`, `Identifier`, `BinaryExpression`, `UnaryExpression`, `AssignmentExpression`, `CallExpression`, `MemberExpression`, `ArrowFunction`, `ObjectExpression`, `ArrayExpression`, `ConditionalExpression`, `TemplateLiteral`, `SpreadElement`, `NewExpression`, `ThisExpression`, `SequenceExpression`, `TaggedTemplate`, `ClassExpression`, `YieldExpression`, `AwaitExpression`.
- **Příkaz**: `BlockStatement`, `IfStatement`, `ForStatement`, `ForInStatement`, `ForOfStatement`, `WhileStatement`, `DoWhileStatement`, `SwitchStatement`, `ReturnStatement`, `ThrowStatement`, `TryStatement`, `BreakStatement`, `ContinueStatement`, `ExpressionStatement`.
- **Deklarace**: `VariableDeclaration`, `FunctionDeclaration`, `ClassDeclaration`, `ImportDeclaration`.
- **Vzor** (destrukturalizace): `ArrayPattern`, `ObjectPattern`, `RestElement`, `AssignmentPattern`.

Automatické vkládání středníků je podle specifikace implementováno v parseru, nikoli v lexeru.

## Interpret

`src/Runtime/Interpreter.php` prochází AST. Navštěvuje každý uzel a vrací `JsValue` (nebo `Completion` pro příkazy měnící tok řízení).

Hlavní podpůrné třídy:

- **`Environment`** (`src/Runtime/Environment.php`) — řetězec lexikálních rozsahů. Každé volání funkce vytvoří nové prostředí odkazující na svého lexikálního rodiče. `var` se přesouvá do rozsahu funkce; `let` / `const` mají rozsah bloku a TDZ.
- **`CallStack`** (`src/Runtime/CallStack.php`) — explicitní zásobník s omezenou hloubkou. Volání funkcí a metod přidávají rámce; výjimky je postupně odebírají.
- **`Completion`** (`src/Runtime/Completion.php`) — rozlišovaná unie typů `normal`, `return`, `throw`, `break`, `continue` doplněná volitelnou hodnotou a návěštím.
- **`Reference`** (`src/Runtime/Reference.php`) — typ Reference podle specifikace pro vyhodnocování levé strany při přiřazování a `delete`.

## Hodnoty

Hodnoty JavaScript jsou objekty PHP pod `src/Value/`. Každá implementuje rozhraní `JsValue` a má vlastní metody převodu typů (`toNumber()`, `toString()`, `toBoolean()`).

| Třída | JS typ |
|---|---|
| `JsUndefined` | `undefined` (singleton) |
| `JsNull` | `null` (singleton) |
| `JsBoolean` | `true` / `false` |
| `JsNumber` | IEEE 754 double; zachovává NaN, ±Infinity, ±0 |
| `JsString` | sémantika řetězců UTF-16 |
| `JsObject` | základní objekt s mapou vlastností a řetězcem prototypů |
| `JsArray` | rozšiřuje `JsObject` o sledování délky |
| `JsFunction` | uzávěr se zachyceným `Environment` |
| `JsSymbol` | primitivní typ Symbol |
| `JsBigInt` | libovolná přesnost pomocí bcmath |
| `JsProxy` | všech 13 pastí, odvolatelné |
| `JsPromise` | synchronní vykonavatel + fronta mikroúloh |
| `JsGenerator` | duální režim: generátory se snímkem rámce (těla zkompilovaná do bajtkódu; viz [Bajtkódový VM § Generátory se snímkem rámce](https://phasis.inline0.dev/cs/docs/advanced/bytecode-vm)) s náhradním řešením pomocí PHP Fiber pro `yield*`, try-with-yield a asynchronní generátory |
| `JsMap`, `JsSet`, `JsWeakMap`, `JsWeakSet`, `JsWeakRef`, `JsFinalizationRegistry` | kolekce |
| `JsArrayBuffer`, `JsSharedArrayBuffer`, `JsDataView`, `JsTypedArray` | binární data |

Zpracování čísel je historicky zdaleka největším zdrojem chyb: `NaN !== NaN` musí platit, `-0 === 0` musí platit a okrajové případy ToNumber vyžadují přesnou práci na úrovni bitů. Třída `Spec/TypeConversion` implementuje algoritmy specifikace doslovně a je důkladně testována.

## Vestavěná knihovna

`src/BuiltIn/` poskytuje všechny objekty standardní knihovny: `Array`, `String`, `Object`, `Math`, `JSON`, `Date`, `RegExp`, `Map`, `Set`, `Promise`, `Proxy`, `Reflect`, `Symbol`, `BigInt`, `TypedArray`, `Temporal`, `Intl`, `console` a také balíčky Web Platform / Fetch (`URL`, `Headers`, `Request`, `Response`, `Blob`, `FormData`, plné Streams, `EventTarget`, `AbortController`/`AbortSignal`, `DOMException`, `structuredClone`, `performance`, `TextEncoder`/`TextDecoder`, `atob`/`btoa`), `crypto` + `SubtleCrypto`, `WebSocket`, `XMLHttpRequest` a smyčku událostí (`setTimeout`, `setInterval`, `queueMicrotask`, `AsyncContext`).

Každá vestavěná funkce je statická metoda `install()` ve třídě. `Engine` je při vytváření volá v pořadí podle závislostí. Každá z nich definuje řetězec prototypů, instaluje metody jako instance `JsFunction` obalené kolem uzávěrů PHP a zpřístupní konstruktor jako globální proměnnou.

## Propojení PHP↔JS

Převod hodnot přes hranici probíhá na dvou místech:

- **`Phasis\Interop\PhpToJs::convert()`** — hodnota PHP na `JsValue`, používaná pro `setGlobal()`, argumenty `call()` a návratové hodnoty hostitelských funkcí. Volatelná hodnota PHP se změní na `JsFunction`, jehož tělo ji zavolá.
- **`PhpToJs::toPhp()`** — `JsValue` na PHP pro argumenty hostitelské funkce.
- **`Engine::toPhp()`** (privátní) — `JsValue` na PHP pro výsledky `eval()` a `call()`.

Pro objekty neexistuje most: objekty PHP, které nejsou volatelné, se převedou na `undefined` ([issue #18](https://github.com/inline0/phasis/issues/18)). Třída `JsToPhp` v `src/Bytecode/` nesouvisí s interoperabilitou; jde o transpiler popsaný níže. Pravidla převodu jsou popsána v části [Převod hodnot](https://phasis.inline0.dev/cs/docs/interop/values).

## Zpracování chyb

Nezachycená JS `throw` se změní na PHP `Phasis\Exceptions\JsThrowable`; chyby vyvolané samotným enginem se projeví jako `Phasis\Exceptions\TypeError`, `RangeError` nebo `ReferenceError`, což jsou vše podtřídy `Phasis\Exceptions\RuntimeError`. Uvnitř enginu zachytí JS `try` / `catch` výjimky `JsThrowable`, libovolné `RuntimeError` a `Phasis\Exceptions\SyntaxError`. Jiné výjimky PHP, včetně těch vyvolaných hostitelskými funkcemi, se nepřevádějí a předávají se přímo volajícímu PHP ([issue #20](https://github.com/inline0/phasis/issues/20)).

Existují dva limity: horní hranice hloubky zásobníku volání (`CallStack::maxDepth`, 4,096 rámců a navíc ochranný limit 8,192 rámců pro transpillované uzávěry) a `maxLoopIterations`, nastavený přes `Engine::setLimit()`, který vynucuje pouze stromový interpret ([issue #19](https://github.com/inline0/phasis/issues/19)). Oba vyvolají `Phasis\Exceptions\InternalError`. Délka řetězců, velikost výstupu ani doba běhu nejsou omezené.

## Virtuální stroj s bajtkódem

Často volané funkce se převádějí dvěma způsoby. `JsToPhp` (v `src/Bytecode/`) vytváří uzávěr PHP pro těla s převahou číselných operací a lokálních proměnných, který trasovací JIT kompilátor PHP může zkompilovat do nativního kódu; zpracování převádí čtení `new Ctor(args)`, `obj.method(args)` a `this.member`, což stačí k tomu, aby kanonický vzor volání metody třídy ve smyčce zcela obešel VM. Vše ostatní se kompiluje do plochého bajtkódu zpracovávaného pomocí `VM::execute` s vlastním zásobníkem volání, který udržuje každé volání JS v jediném rámci PHP a používá mezipaměť inline pro jednotlivá PC při čtení metod prototypu. Jednoduchá těla generátorů se také kompilují do bajtkódu; `Op::YIELD` zachytí snímek rámce na haldě, takže není nutné přecházet přes Fiber PHP.

Každý tvar, který kompilátor nedokáže převést (e.g. `with`, `try` s opětovnou vazbou v catch, `yield*`, asynchronní generátory), přejde ke stromovému interpretu. Podrobný popis mechanismu najdete v části [Virtuální stroj s bajtkódem](https://phasis.inline0.dev/cs/docs/advanced/bytecode-vm).
