
# Arhitectură

Phasis este un arbore de sintaxă parcurs în patru etape, cu o mașină virtuală de bytecode folosită oportunist. Fluxul de date este:

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

Fiecare etapă este o clasă PHP cu o interfață restrânsă, consumată de etapa următoare. Nu există etapă de legare — parsarea produce un AST, pe care interpretorul îl parcurge direct.

## Lexer

`src/Lexer/Lexer.php` transformă textul sursă într-un flux de instanțe `Token`. Fiecare jeton este o structură doar pentru citire: tip (enumerare `TokenType`, aproximativ 80 de cazuri), valoare, linie, coloană.

Lexerul gestionează:

- Literali numerici — zecimali, hexazecimali (`0x`), octali (`0o`), binari (`0b`), exponențiali și separatori numerici.
- Literali șir — ghilimele simple și duble, toate secvențele de escape, literali șablon cu expresii imbricate.
- Literali de expresii regulate — tokenizare completă `/pattern/flags`, cu detectarea situațiilor în care un `/` trebuie interpretat ca expresie regulată sau ca împărțire.
- Identificatori, cuvinte cheie, semne de punctuație.
- Comentarii (pe linie și în bloc), păstrate ca elemente auxiliare.
- Sursă Unicode — octeți UTF-8 interpretați ca sursa UTF-16 JS.

Rezultatul este un generator care furnizează leneș jetoanele. Parserul le consumă anticipând un singur jeton.

## Parser

`src/Parser/Parser.php` este un parser Pratt scris manual. Prioritatea expresiilor este definită în `src/Parser/Precedence.php`. Instrucțiunile folosesc propria analiză descendentă recursivă.

Acesta produce noduri AST imuabile din `src/Ast/`. Fiecare nod include locația din sursă pentru urmele stivei și raportarea erorilor.

Forme importante:

- **Expresie**: `Literal`, `Identifier`, `BinaryExpression`, `UnaryExpression`, `AssignmentExpression`, `CallExpression`, `MemberExpression`, `ArrowFunction`, `ObjectExpression`, `ArrayExpression`, `ConditionalExpression`, `TemplateLiteral`, `SpreadElement`, `NewExpression`, `ThisExpression`, `SequenceExpression`, `TaggedTemplate`, `ClassExpression`, `YieldExpression`, `AwaitExpression`.
- **Instrucțiune**: `BlockStatement`, `IfStatement`, `ForStatement`, `ForInStatement`, `ForOfStatement`, `WhileStatement`, `DoWhileStatement`, `SwitchStatement`, `ReturnStatement`, `ThrowStatement`, `TryStatement`, `BreakStatement`, `ContinueStatement`, `ExpressionStatement`.
- **Declarație**: `VariableDeclaration`, `FunctionDeclaration`, `ClassDeclaration`, `ImportDeclaration`.
- **Tipar** (destructurare): `ArrayPattern`, `ObjectPattern`, `RestElement`, `AssignmentPattern`.

Inserarea automată a punctului și virgulei este implementată în parser (nu în lexer), conform specificației.

## Interpretor

`src/Runtime/Interpreter.php` este componenta care parcurge AST-ul. Vizitează fiecare nod și returnează o `JsValue` (sau o `Completion` pentru instrucțiunile care modifică fluxul de control).

Clase de suport importante:

- **`Environment`** (`src/Runtime/Environment.php`) — lanțul domeniilor de vizibilitate lexicale. Fiecare apel de funcție creează un mediu nou, legat de părintele său lexical. `var` este ridicat la nivelul funcției; `let` / `const` au domeniu de bloc și o zonă de inițializare temporală (TDZ).
- **`CallStack`** (`src/Runtime/CallStack.php`) — stivă explicită cu limită de adâncime. Apelurile de funcții și metode adaugă cadre; excepțiile le elimină.
- **`Completion`** (`src/Runtime/Completion.php`) — reuniune discriminată de valori `normal`, `return`, `throw`, `break`, `continue`, plus o valoare opțională și o etichetă.
- **`Reference`** (`src/Runtime/Reference.php`) — tipul Reference din specificație, pentru evaluarea membrului stâng în atribuiri și `delete`.

## Valori

Valorile JavaScript sunt obiecte PHP în cadrul `src/Value/`. Fiecare implementează interfața `JsValue` și are propriile metode de conversie a tipului (`toNumber()`, `toString()`, `toBoolean()`).

| Clasă | Tipul JS |
|---|---|
| `JsUndefined` | `undefined` (singleton) |
| `JsNull` | `null` (singleton) |
| `JsBoolean` | `true` / `false` |
| `JsNumber` | IEEE 754 dublă precizie; păstrează NaN, ±Infinity, ±0 |
| `JsString` | Semantică de șir UTF-16 |
| `JsObject` | Obiect de bază cu mapă de proprietăți și lanț de prototipuri |
| `JsArray` | Extinde `JsObject` cu urmărirea lungimii |
| `JsFunction` | Închidere cu `Environment` capturat |
| `JsSymbol` | Primitiv Symbol |
| `JsBigInt` | Precizie arbitrară prin bcmath |
| `JsProxy` | Toate cele 13 capcane, revocabile |
| `JsPromise` | Executor sincron + coadă de microtaskuri |
| `JsGenerator` | Mod dual: instantaneu al cadrului (corpuri compilate în bytecode; consultați [Generatoare cu instantaneu al cadrului pentru mașina virtuală de bytecode](https://phasis.inline0.dev/ro/docs/advanced/bytecode-vm)), cu fallback la Fiber PHP pentru `yield*`, try-with-yield și generatoare asincrone |
| `JsMap`, `JsSet`, `JsWeakMap`, `JsWeakSet`, `JsWeakRef`, `JsFinalizationRegistry` | colecții |
| `JsArrayBuffer`, `JsSharedArrayBuffer`, `JsDataView`, `JsTypedArray` | date binare |

Gestionarea numerelor este cea mai importantă sursă de erori istorice: `NaN !== NaN` trebuie să fie adevărat, `-0 === 0` trebuie să fie adevărat, iar cazurile-limită ToNumber necesită atenție exactă la nivel de biți. Clasa `Spec/TypeConversion` implementează algoritmii specificației întocmai și este testată exhaustiv.

## Biblioteca încorporată

`src/BuiltIn/` oferă toate obiectele bibliotecii standard: `Array`, `String`, `Object`, `Math`, `JSON`, `Date`, `RegExp`, `Map`, `Set`, `Promise`, `Proxy`, `Reflect`, `Symbol`, `BigInt`, `TypedArray`, `Temporal`, `Intl`, `console`, plus pachetele Web Platform / Fetch (`URL`, `Headers`, `Request`, `Response`, `Blob`, `FormData`, Streams complet, `EventTarget`, `AbortController`/`AbortSignal`, `DOMException`, `structuredClone`, `performance`, `TextEncoder`/`TextDecoder`, `atob`/`btoa`), `crypto` + `SubtleCrypto`, `WebSocket`, `XMLHttpRequest` și bucla de evenimente (`setTimeout`, `setInterval`, `queueMicrotask`, `AsyncContext`).

Fiecare componentă încorporată este o metodă statică `install()` a unei clase. `Engine` le apelează în ordinea dependențelor la construire. Fiecare definește lanțul de prototipuri, instalează metodele ca instanțe `JsFunction` încapsulate în închideri PHP și expune constructorul ca globală.

## Puntea PHP↔JS

Conversia valorilor la trecerea graniței are loc în două puncte:

- **`Phasis\Interop\PhpToJs::convert()`** — valoare PHP în `JsValue`, folosită pentru `setGlobal()`, argumentele `call()` și valorile returnate de funcțiile gazdă. Un callable PHP devine un `JsFunction` al cărui corp îl apelează.
- **`PhpToJs::toPhp()`** — `JsValue` în PHP pentru argumentele unei funcții gazdă.
- **`Engine::toPhp()`** (privat) — `JsValue` în PHP pentru rezultatele din `eval()` și `call()`.

Nu există o punte pentru obiecte: obiectele PHP care nu sunt apelabile se convertesc în `undefined` ([problema #18](https://github.com/inline0/phasis/issues/18)). Clasa `JsToPhp` din `src/Bytecode/` nu are legătură cu interoperabilitatea; este transpilerul descris mai jos. Regulile de conversie sunt documentate în [Conversia valorilor](https://phasis.inline0.dev/ro/docs/interop/values).

## Tratarea erorilor

Un JS `throw` neprins devine un PHP `Phasis\Exceptions\JsThrowable`; erorile generate chiar de motor sunt semnalate ca `Phasis\Exceptions\TypeError`, `RangeError` sau `ReferenceError`, toate subclase ale lui `Phasis\Exceptions\RuntimeError`. În interiorul motorului, un JS `try` / `catch` prinde `JsThrowable`, orice `RuntimeError` și `Phasis\Exceptions\SyntaxError`. Celelalte excepții PHP, inclusiv cele aruncate de funcțiile gazdă, nu sunt convertite și se propagă direct către apelantul PHP ([problema #20](https://github.com/inline0/phasis/issues/20)).

Există două limite: plafonul stivei de apeluri (`CallStack::maxDepth`, 4,096 cadre, plus o protecție de 8,192 cadre pentru închiderile transpuse) și `maxLoopIterations`, setată prin `Engine::setLimit()`, aplicată doar de componenta care parcurge arborele ([problema #19](https://github.com/inline0/phasis/issues/19)). Ambele generează `Phasis\Exceptions\InternalError`. Nu există limite pentru lungimea șirurilor, dimensiunea rezultatului sau timpul de execuție.

## Mașina virtuală de bytecode

Funcțiile intens solicitate sunt reduse în două moduri. `JsToPhp` (în `src/Bytecode/`) emite o închidere PHP pentru corpuri cu multe operații numerice sau variabile locale, pe care JIT-ul de urmărire al PHP îl poate compila în cod nativ; fluxul de compilare reduce accesările `new Ctor(args)`, `obj.method(args)` și `this.member`, ceea ce permite tiparului canonic „metodă de clasă într-o buclă” să ocolească complet mașina virtuală. Orice altceva este compilat în bytecode liniar, consumat de `VM::execute`, cu o stivă de apeluri personalizată care păstrează fiecare apel JS într-un singur cadru PHP și o memorie cache inline per PC pentru accesările metodelor prototipului. Corpurile simple ale generatoarelor sunt compilate și ele în bytecode, iar `Op::YIELD` capturează un instantaneu al cadrului din heap, fără a trece prin Fiber PHP.

Orice formă pe care compilatorul nu o poate reduce (e.g. `with`, `try` cu o captură ce reatribuie variabile, `yield*`, generatoare asincrone) revine la componenta care parcurge arborele. Consultați [Mașina virtuală de bytecode](https://phasis.inline0.dev/ro/docs/advanced/bytecode-vm) pentru mecanismul complet.
