
# Arhitektūra

Phasis ir četru posmu koka apstaigātājs ar oportūnistisku baitu koda virtuālo mašīnu. Datu plūsma ir šāda:

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

Katrs posms ir PHP klase ar nelielu saskarni, ko izmanto nākamais posms. Saistīšanas posma nav — parsēšana izveido AST, un interpretētājs to apstaigā tieši.

## Leksiskais analizators

`src/Lexer/Lexer.php` pārvērš avota tekstu par `Token` instanču plūsmu. Katrs tokens ir tikai lasāma struktūra: tips (`TokenType` enum ar aptuveni 80 variantiem), vērtība, rinda, kolonna.

Leksiskais analizators apstrādā:

- Skaitļu literāļus — decimālos, heksadecimālos (`0x`), oktālos (`0o`), bināros (`0b`), eksponenciālos un ar ciparu atdalītājiem.
- Virkņu literāļus — ar vienpēdiņām un dubultpēdiņām, visas atsoļa secības, veidņu literāļus ar iegultām izteiksmēm.
- Regulāro izteiksmju literāļus — pilnu `/pattern/flags` tokenizāciju, ņemot vērā, kad `/` jāinterpretē kā regulārā izteiksme vai dalīšana.
- Identifikatorus, atslēgvārdus un pieturzīmes.
- Komentārus (rindas un bloka), kas tiek saglabāti kā triviālie elementi.
- Unicode avotu — UTF-8 baitus, kas tiek interpretēti kā JS UTF-16 avots.

Izvade ir ģenerators, kas pakāpeniski izvada tokenus. Parsētājs tos patērē, vienu tokenu turot priekšskatā.

## Parsētājs

`src/Parser/Parser.php` ir ar roku rakstīts Pratt parsētājs. Izteiksmju prioritātes ir noteiktas `src/Parser/Precedence.php`. Priekšrakstiem ir sava rekursīvās nolaišanās parsēšana.

Tas no `src/Ast/` veido nemainīgus AST mezglus. Katrā mezglā ir avota atrašanās vieta steka izdrukām un kļūdu ziņojumiem.

Ievērības cienīgās formas:

- **Izteiksme**: `Literal`, `Identifier`, `BinaryExpression`, `UnaryExpression`, `AssignmentExpression`, `CallExpression`, `MemberExpression`, `ArrowFunction`, `ObjectExpression`, `ArrayExpression`, `ConditionalExpression`, `TemplateLiteral`, `SpreadElement`, `NewExpression`, `ThisExpression`, `SequenceExpression`, `TaggedTemplate`, `ClassExpression`, `YieldExpression`, `AwaitExpression`.
- **Priekšraksts**: `BlockStatement`, `IfStatement`, `ForStatement`, `ForInStatement`, `ForOfStatement`, `WhileStatement`, `DoWhileStatement`, `SwitchStatement`, `ReturnStatement`, `ThrowStatement`, `TryStatement`, `BreakStatement`, `ContinueStatement`, `ExpressionStatement`.
- **Deklarācija**: `VariableDeclaration`, `FunctionDeclaration`, `ClassDeclaration`, `ImportDeclaration`.
- **Raksts** (destrukturēšana): `ArrayPattern`, `ObjectPattern`, `RestElement`, `AssignmentPattern`.

Automātiskā semikolu ievietošana ir ieviesta parsētājā (nevis leksiskajā analizatorā) atbilstoši specifikācijai.

## Interpretētājs

`src/Runtime/Interpreter.php` ir AST apstaigātājs. Tas apmeklē katru mezglu un atgriež `JsValue` (vai `Completion` priekšrakstiem, kas maina vadības plūsmu).

Galvenās palīgklases:

- **`Environment`** (`src/Runtime/Environment.php`) — leksisko tvērumu ķēde. Katrs funkcijas izsaukums izveido jaunu vidi, kas norāda uz leksisko vecākvidi. `var` tiek pacelts uz funkcijas tvērumu; `let` / `const` ir bloka tvēruma mainīgie ar TDZ.
- **`CallStack`** (`src/Runtime/CallStack.php`) — skaidri pārvaldīts steks ar dziļuma ierobežojumu. Funkciju un metožu izsaukumi pievieno stekam kadrus; izņēmumi tos atritina.
- **`Completion`** (`src/Runtime/Completion.php`) — diskriminēts apvienojums, kurā ietilpst `normal`, `return`, `throw`, `break`, `continue`, kā arī neobligāta vērtība un etiķete.
- **`Reference`** (`src/Runtime/Reference.php`) — specifikācijā definētais Reference tips kreisās puses novērtēšanai piešķīrumos un `delete`.

## Vērtības

JavaScript vērtības ir PHP objekti zem `src/Value/`. Katrs īsteno `JsValue` saskarni un ietver savas tipu konvertēšanas metodes (`toNumber()`, `toString()`, `toBoolean()`).

| Klase | JS tips |
|---|---|
| `JsUndefined` | `undefined` (singleton) |
| `JsNull` | `null` (singleton) |
| `JsBoolean` | `true` / `false` |
| `JsNumber` | IEEE 754 double; saglabā NaN, ±Infinity, ±0 |
| `JsString` | UTF-16 virkņu semantika |
| `JsObject` | bāzes objekts ar īpašību karti un prototipu ķēdi |
| `JsArray` | paplašina `JsObject`, sekojot līdzi garumam |
| `JsFunction` | slēgums ar tvertu `Environment` |
| `JsSymbol` | primitīvs Symbol |
| `JsBigInt` | patvaļīga precizitāte, izmantojot bcmath |
| `JsProxy` | visi 13 trapi; atsaucams |
| `JsPromise` | sinhrons izpildītājs un mikrouzdevumu rinda |
| `JsGenerator` | divu režīmu: kadru momentuzņēmuma režīms (baitu kodā kompilēti pamatkodi; skatiet [Baitu koda virtuālā mašīna § Ģeneratori ar kadru momentuzņēmumiem](https://phasis.inline0.dev/lv/docs/advanced/bytecode-vm)), ar PHP Fiber rezerves režīmu priekš `yield*`, try-with-yield un asinhronajiem ģeneratoriem |
| `JsMap`, `JsSet`, `JsWeakMap`, `JsWeakSet`, `JsWeakRef`, `JsFinalizationRegistry` | kolekcijas |
| `JsArrayBuffer`, `JsSharedArrayBuffer`, `JsDataView`, `JsTypedArray` | binārie dati |

Skaitļu apstrāde vēsturiski ir lielākais kļūdu avots: `NaN !== NaN` jābūt true, `-0 === 0` jābūt true, un ToNumber robežgadījumiem nepieciešama precizitāte bitu līmenī. Klase `Spec/TypeConversion` īsteno specifikācijas algoritmus vārds vārdā, un tā ir izsmeļoši testēta.

## Iebūvētā bibliotēka

`src/BuiltIn/` nodrošina visus standarta bibliotēkas objektus: `Array`, `String`, `Object`, `Math`, `JSON`, `Date`, `RegExp`, `Map`, `Set`, `Promise`, `Proxy`, `Reflect`, `Symbol`, `BigInt`, `TypedArray`, `Temporal`, `Intl`, `console`, kā arī Web Platform / Fetch pakotnes (`URL`, `Headers`, `Request`, `Response`, `Blob`, `FormData`, pilnas Streams, `EventTarget`, `AbortController`/`AbortSignal`, `DOMException`, `structuredClone`, `performance`, `TextEncoder`/`TextDecoder`, `atob`/`btoa`), `crypto` + `SubtleCrypto`, `WebSocket`, `XMLHttpRequest` un notikumu cilpu (`setTimeout`, `setInterval`, `queueMicrotask`, `AsyncContext`).

Katrs iebūvētais objekts ir statiska `install()` metode klasē. `Engine` izsauc šīs metodes izveides laikā, ievērojot atkarību secību. Katra metode definē prototipu ķēdi, instalē metodes kā `JsFunction` instances, kas ietītas ap PHP slēgumiem, un padara konstruktoru pieejamu kā globālu objektu.

## PHP↔JS tilts

Vērtību konvertēšana pāri robežai notiek divās vietās:

- **`Phasis\Interop\PhpToJs::convert()`** — PHP vērtība uz `JsValue`; izmanto `setGlobal()`, `call()` argumentiem un resursdatora funkciju atgrieztajām vērtībām. Izsaucams PHP kļūst par `JsFunction`, kura pamatā ir tā izsaukšana.
- **`PhpToJs::toPhp()`** — no `JsValue` uz PHP resursdatora funkcijas argumentiem.
- **`Engine::toPhp()`** (privāta) — no `JsValue` uz PHP `eval()` un `call()` rezultātiem.

Objektu tilta nav: PHP objekti, kas nav izsaucami, tiek konvertēti uz `undefined` ([problēma #18](https://github.com/inline0/phasis/issues/18)). Klase `JsToPhp` `src/Bytecode/` nav saistīta ar sadarbspēju; tas ir tālāk aprakstītais transpilers. Konvertēšanas noteikumi ir dokumentēti sadaļā [Vērtību konvertēšana](https://phasis.inline0.dev/lv/docs/interop/values).

## Kļūdu apstrāde

Nepārtverts JS `throw` kļūst par PHP `Phasis\Exceptions\JsThrowable`; paša dzinēja radītās kļūdas tiek parādītas kā `Phasis\Exceptions\TypeError`, `RangeError` vai `ReferenceError` — visas ir `Phasis\Exceptions\RuntimeError` apakšklases. Dzinēja iekšienē JS `try` / `catch` pārtver `JsThrowable`, ikvienu `RuntimeError` un `Phasis\Exceptions\SyntaxError`. Citi PHP izņēmumi, tostarp resursdatora funkciju izmestie, netiek konvertēti un tiek nodoti tieši PHP izsaucējam ([problēma #20](https://github.com/inline0/phasis/issues/20)).

Pastāv divi ierobežojumi: izsaukumu steka maksimums (`CallStack::maxDepth`, 4,096 kadri, kā arī 8,192 kadru aizsardzība transpilerētajiem slēgumiem) un `maxLoopIterations`, kas iestatāms ar `Engine::setLimit()` un ko ievēro tikai koka apstaigātājs ([problēma #19](https://github.com/inline0/phasis/issues/19)). Abi izraisa `Phasis\Exceptions\InternalError`. Nav virknes garuma, izvades lieluma vai izpildes laika ierobežojumu.

## Baitu koda virtuālā mašīna

Bieži izsauktās funkcijas tiek pārveidotas divos veidos. `JsToPhp` (`src/Bytecode/`) izveido PHP slēgumu skaitliskiem vai lokālo mainīgo ziņā intensīviem pamatkodiem, ko PHP trasējošais JIT var kompilēt uz mašīnkodu; konveijers pārveido `new Ctor(args)`, `obj.method(args)` un `this.member` nolasīšanu, kas ļauj standarta klases metodes izsaukumam ciklā pilnībā apiet virtuālo mašīnu. Viss pārējais tiek kompilēts plakanā baitu kodā, ko izpilda `VM::execute`, izmantojot pielāgotu izsaukumu steku, kas visus JS izsaukumus uztur vienā PHP kadrā, un katram PC ir iekļautā kešatmiņa prototipa metožu nolasīšanai. Arī vienkārši ģeneratoru pamatkodi tiek kompilēti baitu kodā, un `Op::YIELD` tver steka kadra momentuzņēmumu kaudzē, nevis pāriet uz PHP Fiber.

Jebkura forma, ko kompilators nepārveido (e.g. `with`, `try` ar atkārtotu piesaisti tvēruma blokā, `yield*`, asinhronie ģeneratori), tiek nodota koka apstaigātājam. Pilnu mehānisma aprakstu skatiet sadaļā [Baitu koda virtuālā mašīna](https://phasis.inline0.dev/lv/docs/advanced/bytecode-vm).
