
# Architektūra

Phasis yra keturių etapų medžio interpretatorius su oportunistine baitinio kodo virtualiąja mašina. Duomenų kelias:

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

Kiekvienas etapas yra PHP klasė su nedidele sąsaja, kurią naudoja kitas etapas. Susiejimo etapo nėra – analizė sukuria AST, o interpretatorius jį eina tiesiogiai.

## Leksinis analizatorius

`src/Lexer/Lexer.php` šaltinio tekstą paverčia `Token` egzempliorių srautu. Kiekvienas leksemas yra tik skaitoma struktūra: tipas (`TokenType` išvardijimas, apie 80 atvejų), reikšmė, eilutė, stulpelis.

Leksinis analizatorius apdoroja:

- Skaičių literalius – dešimtainius, šešioliktainius (`0x`), aštuntainius (`0o`), dvejetainius (`0b`), eksponentinius ir su skaitmenų skirtukais.
- Eilučių literalius – su viengubomis ir dvigubomis kabutėmis, visomis kaitos sekomis, šablonines eilutes su įdėtinėmis išraiškomis.
- Reguliariųjų reiškinių literalius – visišką `/pattern/flags` tokenizavimą, atsižvelgiant į tai, kada `/` turėtų būti reguliarusis reiškinys, o kada dalyba.
- Identifikatorius, raktažodžius, skyrybos ženklus.
- Komentarus (eilutės ir blokų), išsaugomus kaip papildomą informaciją.
- Unicode šaltinį – UTF-8 baitai interpretuojami kaip JS UTF-16 šaltinis.

Išvestis yra generatorius, kuris leksemas pateikia tingiai. Analizatorius juos vartoja naudodamas vieno leksemo peržiūrą į priekį.

## Analizatorius

`src/Parser/Parser.php` yra rankomis parašytas Pratt analizatorius. Išraiškų pirmumo tvarka apibrėžta `src/Parser/Precedence.php`. Sakiniams taikoma atskira rekursinio nusileidimo analizė.

Jis iš `src/Ast/` sukuria nekintamus AST mazgus. Kiekviename mazge nurodyta šaltinio vieta, skirta dėklo pėdsakams ir klaidų pranešimams.

Svarbios formos:

- **Išraiška**: `Literal`, `Identifier`, `BinaryExpression`, `UnaryExpression`, `AssignmentExpression`, `CallExpression`, `MemberExpression`, `ArrowFunction`, `ObjectExpression`, `ArrayExpression`, `ConditionalExpression`, `TemplateLiteral`, `SpreadElement`, `NewExpression`, `ThisExpression`, `SequenceExpression`, `TaggedTemplate`, `ClassExpression`, `YieldExpression`, `AwaitExpression`.
- **Sakinys**: `BlockStatement`, `IfStatement`, `ForStatement`, `ForInStatement`, `ForOfStatement`, `WhileStatement`, `DoWhileStatement`, `SwitchStatement`, `ReturnStatement`, `ThrowStatement`, `TryStatement`, `BreakStatement`, `ContinueStatement`, `ExpressionStatement`.
- **Deklaracija**: `VariableDeclaration`, `FunctionDeclaration`, `ClassDeclaration`, `ImportDeclaration`.
- **Šablonas** (destruktūrizavimas): `ArrayPattern`, `ObjectPattern`, `RestElement`, `AssignmentPattern`.

Automatinis kabliataškių įterpimas vykdomas analizatoriuje (ne leksiniame analizatoriuje), kaip nurodyta specifikacijoje.

## Interpretatorius

`src/Runtime/Interpreter.php` pereina AST mazgus. Jis aplanko kiekvieną mazgą ir grąžina `JsValue` (arba `Completion` sakiniams, kurie keičia valdymo srautą).

Pagrindinės pagalbinės klasės:

- **`Environment`** (`src/Runtime/Environment.php`) – leksinių sričių grandinė. Kiekvienas funkcijos iškvietimas sukuria naują aplinką, rodančią į jos leksinę tėvinę aplinką. `var` perkeliama į funkcijos sritį; `let` / `const` priklauso blokui ir turi TDZ.
- **`CallStack`** (`src/Runtime/CallStack.php`) – aiškus dėklas su gylio riba. Funkcijų ir metodų iškvietimai įdeda kadrus; išimtys juos išvynioja.
- **`Completion`** (`src/Runtime/Completion.php`) – diskriminacinė sąjunga, apimanti `normal`, `return`, `throw`, `break`, `continue`, taip pat pasirenkamą reikšmę ir žymą.
- **`Reference`** (`src/Runtime/Reference.php`) – specifikacijos Reference tipo objektas, skirtas kairiosios pusės vertinimui priskyrimuose ir `delete`.

## Reikšmės

JavaScript reikšmės yra PHP objektai sistemoje `src/Value/`. Kiekvienas įgyvendina sąsają `JsValue` ir turi savo tipo konvertavimo metodus (`toNumber()`, `toString()`, `toBoolean()`).

| Klasė | JS tipas |
|---|---|
| `JsUndefined` | `undefined` (vienintelis egzempliorius) |
| `JsNull` | `null` (vienintelis egzempliorius) |
| `JsBoolean` | `true` / `false` |
| `JsNumber` | IEEE 754 double; išsaugo NaN, ±Infinity, ±0 |
| `JsString` | UTF-16 eilučių semantika |
| `JsObject` | pagrindinis objektas su savybių žemėlapiu ir prototipų grandine |
| `JsArray` | išplečia `JsObject` ir seka ilgį |
| `JsFunction` | uždarinys su užfiksuotu `Environment` |
| `JsSymbol` | Symbol primityvas |
| `JsBigInt` | savavališko tikslumo skaičiai naudojant bcmath |
| `JsProxy` | visi 13 perėmimo veiksmų, atšaukiamas |
| `JsPromise` | sinchroninis vykdytojas ir mikro užduočių eilė |
| `JsGenerator` | dviejų režimų: kadro momentinė kopija (baitiniu kodu sukompiliuoti kūnai; žr. [Baitinio kodo VM § Generatorių kadro momentinės kopijos](https://phasis.inline0.dev/lt/docs/advanced/bytecode-vm)) su PHP Fiber atsarginiu variantu, skirtu `yield*`, try-with-yield ir asinchroniniams generatoriams |
| `JsMap`, `JsSet`, `JsWeakMap`, `JsWeakSet`, `JsWeakRef`, `JsFinalizationRegistry` | rinkiniai |
| `JsArrayBuffer`, `JsSharedArrayBuffer`, `JsDataView`, `JsTypedArray` | dvejetainiai duomenys |

Skaičių apdorojimas yra didžiausias istorinių klaidų šaltinis: `NaN !== NaN` privalo būti true, `-0 === 0` privalo būti true, o ToNumber kraštinius atvejus reikia tikrinti bitų lygmeniu. Klasė `Spec/TypeConversion` pažodžiui įgyvendina specifikacijos algoritmus ir yra išsamiai ištestuota.

## Integruota biblioteka

`src/BuiltIn/` pateikia visus standartinės bibliotekos objektus: `Array`, `String`, `Object`, `Math`, `JSON`, `Date`, `RegExp`, `Map`, `Set`, `Promise`, `Proxy`, `Reflect`, `Symbol`, `BigInt`, `TypedArray`, `Temporal`, `Intl`, `console`, taip pat Web Platform / Fetch paketus (`URL`, `Headers`, `Request`, `Response`, `Blob`, `FormData`, visas Streams, `EventTarget`, `AbortController`/`AbortSignal`, `DOMException`, `structuredClone`, `performance`, `TextEncoder`/`TextDecoder`, `atob`/`btoa`), `crypto` + `SubtleCrypto`, `WebSocket`, `XMLHttpRequest` ir įvykių ciklą (`setTimeout`, `setInterval`, `queueMicrotask`, `AsyncContext`).

Kiekvienas integruotas elementas yra statinis `install()` metodas klasėje. Kuriant, `Engine` iškviečia juos priklausomybių tvarka. Kiekvienas apibrėžia savo prototipų grandinę, įdiegia metodus kaip `JsFunction` egzempliorius, apgaubiančius PHP uždarinius, ir pateikia konstruktorių kaip globalų objektą.

## PHP↔JS sąsaja

Reikšmių konvertavimas tarp ribų vykdomas dviejose vietose:

- **`Phasis\Interop\PhpToJs::convert()`** – PHP reikšmės į `JsValue`; naudojama `setGlobal()`, argumentams `call()` ir pagrindinio kompiuterio funkcijų grąžinamoms reikšmėms. Iškviečiamas PHP tampa `JsFunction`, kurio turinyje jis iškviečiamas.
- **`PhpToJs::toPhp()`** – `JsValue` į PHP pagrindinio kompiuterio funkcijos argumentams.
- **`Engine::toPhp()`** (privatus) – `JsValue` į PHP, skirta `eval()` ir `call()` rezultatams.

Objektų sąsajos nėra: nekviečiami PHP objektai konvertuojami į `undefined` ([problema Nr. 18](https://github.com/inline0/phasis/issues/18)). Klasė `JsToPhp` faile `src/Bytecode/` nėra susijusi su sąveika; tai toliau aprašomas transpiliatorius. Konvertavimo taisyklės aprašytos skiltyje [Reikšmių konvertavimas](https://phasis.inline0.dev/lt/docs/interop/values).

## Klaidų tvarkymas

Neapdorota JS `throw` tampa PHP `Phasis\Exceptions\JsThrowable`; pačios sistemos sukeltos klaidos pateikiamos kaip `Phasis\Exceptions\TypeError`, `RangeError` arba `ReferenceError`, visos jos yra `Phasis\Exceptions\RuntimeError` poklasiai. Sistemos viduje JS `try` / `catch` pagauna `JsThrowable`, bet kokį `RuntimeError` ir `Phasis\Exceptions\SyntaxError`. Kitos PHP išimtys, įskaitant pagrindinio kompiuterio funkcijų iškeltas, nekonvertuojamos ir perduodamos tiesiai PHP iškvietėjui ([problema Nr. 20](https://github.com/inline0/phasis/issues/20)).

Yra du apribojimai: iškvietimų dėklo riba (`CallStack::maxDepth`, 4,096 kadrai ir 8,192 kadrų apsauga transpiliuotiems uždariniams) ir `maxLoopIterations`, nustatoma per `Engine::setLimit()` ir taikoma tik medžio interpretatoriaus ([problema Nr. 19](https://github.com/inline0/phasis/issues/19)). Abu sukelia `Phasis\Exceptions\InternalError`. Eilučių ilgio, išvesties dydžio ar vykdymo trukmės apribojimų nėra.

## Baitinio kodo VM

Dažnai vykdomos funkcijos kompiliuojamos dviem būdais. `JsToPhp` (faile `src/Bytecode/`) sugeneruoja PHP uždarinį skaičiams ir vietiniams kintamiesiems intensyviems kūnams, kuriuos PHP sekimo JIT gali kompiliuoti į vietinį kodą; šis procesas supaprastina `new Ctor(args)`, `obj.method(args)` ir `this.member` skaitymus, todėl įprastas klasės metodo cikle šablonas visiškai apeina VM. Visa kita kompiliuojama į plokščią baitinį kodą, kurį apdoroja `VM::execute`; naudojamas tinkintas iškvietimų dėklas, išlaikantis kiekvieną JS iškvietimą viename PHP kadre, ir kiekvienam PC skirtas spartinančiosios atmintinės įrašas prototipo metodų skaitymui. Paprasti generatorių kūnai taip pat kompiliuojami į baitinį kodą; `Op::YIELD` užfiksuoja krūvoje laikomą kadro momentinę kopiją, todėl nereikia pereiti per PHP Fiber.

Formos, kurių kompiliatorius nesupaprastina (e.g, `with`, `try` su iš naujo susiejamu gaudymo bloku, `yield*`, asinchroniniai generatoriai), perduodamos medžio interpretatoriui. Visas veikimo principas aprašytas skiltyje [Baitinio kodo VM](https://phasis.inline0.dev/lt/docs/advanced/bytecode-vm).
