
# Arhitektuur

Phasis on neljaastmeline puu läbiv käitur, millel on oportunistlik baitkoodiga virtuaalmasin. Andmete liikumine:

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

Iga etapp on PHP klass väikese liidesepinnaga, mida kasutab järgmine etapp. Linkimisetappi pole – parsingu tulemus on AST, mida interpretaator läbib otse.

## Leksikaalanalüsaator

`src/Lexer/Lexer.php` teisendab lähtekoodi tokenite vooguks, mis koosneb `Token` eksemplaridest. Iga token on kirjutuskaitstud struktuur: tüüp (`TokenType` enum, umbes 80 varianti), väärtus, rida ja veerg.

Leksikaalanalüsaator käsitleb järgmist:

- Arvuliteraalid – kümnend-, kuueteistkümnend- (`0x`), kaheksand- (`0o`), kahend- (`0b`) ja astmikkirjapilt ning arvude eraldajad.
- Stringiliteraalid – ühe- ja kahekordsed jutumärgid, kõik paojadad ning malliliteraalid pesastatud avaldistega.
- Regulaaravaldiste literaalid – täielik `/pattern/flags` tokeniseerimine, arvestades, kas `/` tähistab regulaaravaldist või jagamist.
- Tähised, võtmesõnad ja kirjavahemärgid.
- Kommentaarid (rea- ja plokikommentaarid), mis säilitatakse trivia osana.
- Unicode lähtekood – UTF-8 baite tõlgendatakse JS UTF-16 lähtekoodina.

Väljund on generaator, mis väljastab tokeneid laisalt. Parser tarbib neid ühe tokeni võrra ette vaadates.

## Parser

`src/Parser/Parser.php` on käsitsi kirjutatud Pratti parser. Avaldiste prioriteedid on määratud `src/Parser/Precedence.php`-s. Lausetel on oma rekursiivne laskumine.

See loob `src/Ast/` põhjal muutmatud AST-sõlmed. Iga sõlm sisaldab oma lähtekohta pinu jälgede ja vigadest teatamise jaoks.

Märkimisväärsed vormid:

- **Avaldis**: `Literal`, `Identifier`, `BinaryExpression`, `UnaryExpression`, `AssignmentExpression`, `CallExpression`, `MemberExpression`, `ArrowFunction`, `ObjectExpression`, `ArrayExpression`, `ConditionalExpression`, `TemplateLiteral`, `SpreadElement`, `NewExpression`, `ThisExpression`, `SequenceExpression`, `TaggedTemplate`, `ClassExpression`, `YieldExpression`, `AwaitExpression`.
- **Lause**: `BlockStatement`, `IfStatement`, `ForStatement`, `ForInStatement`, `ForOfStatement`, `WhileStatement`, `DoWhileStatement`, `SwitchStatement`, `ReturnStatement`, `ThrowStatement`, `TryStatement`, `BreakStatement`, `ContinueStatement`, `ExpressionStatement`.
- **Deklaratsioon**: `VariableDeclaration`, `FunctionDeclaration`, `ClassDeclaration`, `ImportDeclaration`.
- **Muster** (destruktureerimine): `ArrayPattern`, `ObjectPattern`, `RestElement`, `AssignmentPattern`.

Automaatne semikooloni lisamine on spetsifikatsiooni järgi rakendatud parseris (mitte leksikaalanalüsaatoris).

## Interpretaator

`src/Runtime/Interpreter.php` läbib AST-d. See külastab iga sõlme ja tagastab `JsValue` (või `Completion` juhtvoogu muutvate lausete puhul).

Peamised abiklassid:

- **`Environment`** (`src/Runtime/Environment.php`) – leksikaalsete ulatuste ahel. Iga funktsioonikutse loob uue keskkonna, mis viitab oma leksikaalsele vanemale. `var` tõstetakse funktsiooni ulatusse; `let` / `const` on plokiulatuses ja TDZ-ga.
- **`CallStack`** (`src/Runtime/CallStack.php`) – selgesõnaline pinu koos sügavuspiiranguga. Funktsiooni- ja meetodikutsed lisavad pinuraame; erandid eemaldavad need.
- **`Completion`** (`src/Runtime/Completion.php`) – eristatud ühend tüübiga `normal`, `return`, `throw`, `break`, `continue` ning valikulise väärtuse ja sildiga.
- **`Reference`** (`src/Runtime/Reference.php`) – spetsifikatsiooni Reference-tüüp omistamiste ja `delete` vasaku poole hindamiseks.

## Väärtused

JavaScript väärtused on `src/Value/` all olevad PHP objektid. Igaüks neist rakendab liidest `JsValue` ja sisaldab oma tüübiteisenduse meetodeid (`toNumber()`, `toString()`, `toBoolean()`).

| Klass | JS tüüp |
|---|---|
| `JsUndefined` | `undefined` (ainikeksemplar) |
| `JsNull` | `null` (ainikeksemplar) |
| `JsBoolean` | `true` / `false` |
| `JsNumber` | IEEE 754 topel täpsus; säilitab NaN-i, ±Infinity ja ±0 |
| `JsString` | UTF-16 stringi semantika |
| `JsObject` | põhiobjekt omaduste kaardi ja prototüübiahelaga |
| `JsArray` | laiendab `JsObject`-t, jälgides pikkust |
| `JsFunction` | sulund, milles on hõivatud `Environment` |
| `JsSymbol` | primitiivne Symbol-väärtus |
| `JsBigInt` | täppisarvutus bcmath abil |
| `JsProxy` | kõik 13 lõksu; tühistatav |
| `JsPromise` | sünkroonne täitur + mikroülesannete järjekord |
| `JsGenerator` | kaherežiimiline: kaadri hetktõmmis (baitkoodiks kompileeritud kehad; vt [Baitkoodi VM § Kaadri hetktõmmise generaatorid](https://phasis.inline0.dev/et/docs/advanced/bytecode-vm)) koos PHP Fiberi varulahendusega `yield*`, try-with-yieldi ja asünkroonsete generaatorite jaoks |
| `JsMap`, `JsSet`, `JsWeakMap`, `JsWeakSet`, `JsWeakRef`, `JsFinalizationRegistry` | kogumid |
| `JsArrayBuffer`, `JsSharedArrayBuffer`, `JsDataView`, `JsTypedArray` | binaarandmed |

Arvude käsitlemine on ajalooliselt olnud suurim vigade allikas: `NaN !== NaN` peab kehtima, `-0 === 0` peab kehtima ning ToNumberi erijuhtumid nõuavad täpsust bititasemel. Klass `Spec/TypeConversion` rakendab spetsifikatsiooni algoritme sõna-sõnalt ja seda on ammendavalt testitud.

## Sisseehitatud teek

`src/BuiltIn/` pakub kõiki standardteegi objekte: `Array`, `String`, `Object`, `Math`, `JSON`, `Date`, `RegExp`, `Map`, `Set`, `Promise`, `Proxy`, `Reflect`, `Symbol`, `BigInt`, `TypedArray`, `Temporal`, `Intl`, `console`, lisaks Web Platformi / Fetchi paketid (`URL`, `Headers`, `Request`, `Response`, `Blob`, `FormData`, täielik Streams, `EventTarget`, `AbortController`/`AbortSignal`, `DOMException`, `structuredClone`, `performance`, `TextEncoder`/`TextDecoder`, `atob`/`btoa`), `crypto` + `SubtleCrypto`, `WebSocket`, `XMLHttpRequest` ja sündmuste tsükli (`setTimeout`, `setInterval`, `queueMicrotask`, `AsyncContext`).

Iga sisseehitatud objekt on klassi staatiline `install()`-meetod. `Engine` kutsub need konstruktsiooni käigus sõltuvuste järjekorras välja. Igaüks määratleb oma prototüübiahela, paigaldab meetodid kui `JsFunction` eksemplarid, mis on ümbritsetud PHP sulunditega, ning avalikustab konstruktori globaalse objektina.

## PHP↔JS sild

Väärtuste teisendamine üle piiri toimub kahes kohas:

- **`Phasis\Interop\PhpToJs::convert()`** – PHP väärtusest `JsValue`-ks; seda kasutatakse `setGlobal()`, `call()` argumentide ja hostifunktsiooni tagastusväärtuste puhul. PHP-ga väljakutsutavast objektist saab `JsFunction`, mille sisu seda välja kutsub.
- **`PhpToJs::toPhp()`** – `JsValue`-st PHP-ks hostifunktsiooni argumentide jaoks.
- **`Engine::toPhp()`** (privaatne) – tulemuste jaoks `JsValue`-st PHP-ks: `eval()` ja `call()`.

Objektisilda pole: mitte väljakutsutavad PHP objektid teisendatakse väärtuseks `undefined` ([probleem #18](https://github.com/inline0/phasis/issues/18)). Klass `JsToPhp` failis `src/Bytecode/` pole koostalitlusvõimega seotud; see on allpool kirjeldatud transpiiler. Teisendusreeglid on kirjas jaotises [Väärtuste teisendamine](https://phasis.inline0.dev/et/docs/interop/values).

## Vigade käsitlemine

Püüdmata JS `throw` muutub objektiks PHP `Phasis\Exceptions\JsThrowable`; mootori enda tekitatud vead kuvatakse kujul `Phasis\Exceptions\TypeError`, `RangeError` või `ReferenceError`, mis kõik on klassi `Phasis\Exceptions\RuntimeError` alamklassid. Mootori sees püüab JS `try` / `catch` kinni `JsThrowable`, kõik `RuntimeError` ja `Phasis\Exceptions\SyntaxError`. Muid PHP erandeid, sealhulgas hostifunktsioonide tekitatuid, ei teisendata ning need levivad otse PHP kutsujani ([probleem #20](https://github.com/inline0/phasis/issues/20)).

Piiranguid on kaks: pinu ülempiir (`CallStack::maxDepth`, 4,096 raami, lisaks 8,192 raami piirang transpiilitud sulunditele) ja `maxLoopIterations`, mille väärtus määratakse parameetriga `Engine::setLimit()` ja mille jõustamist kontrollib ainult puu läbiv käitur ([probleem #19](https://github.com/inline0/phasis/issues/19)). Mõlemad tekitavad `Phasis\Exceptions\InternalError`. Stringi pikkusele, väljundi suurusele ega käitusajale piiranguid pole.

## Baitkoodi VM

Sageli käivitatavad funktsioonid kompileeritakse kahel viisil. `JsToPhp` (asukohas `src/Bytecode/`) väljastab PHP sulundi arvudest ja lokaalm muutujatest sõltuvatele funktsioonikehadele, mille PHP jälgiv JIT-kompilaator saab masinkoodiks kompileerida; töötlusahel teisendab `new Ctor(args)`, `obj.method(args)` ja `this.member` lugemised, mis võimaldab tüüpilisel klassimeetodi-tsüklis mustril virtuaalmasinast täielikult mööda minna. Kõik muu kompileeritakse lamendatud baitkoodiks, mida käitab `VM::execute`; sellel on kohandatud väljakutsete pinu, mis hoiab kõik JS väljakutsed ühes PHP raamis, ning prototüübimeetodite lugemiste jaoks on olemas PC-põhine vahemälu. Ka lihtsad generaatorikehad kompileeritakse baitkoodiks; `Op::YIELD` salvestab hunnikusse pinuraami hetktõmmise, selle asemel et läbida PHP Fiberit.

Iga kompilaatori poolt toetamata struktuur (e.g, `with`, `try` ümberseotud püüdmisplokiga, `yield*`, asünkroonsed generaatorid) suunatakse tagasi puu läbivale käiturile. Kogu mehhanismi kohta vt [Baitkoodi VM](https://phasis.inline0.dev/et/docs/advanced/bytecode-vm).
