İçeriğe geç

Mimari

Phasis, fırsatçı bir bayt kodu VM'siyle çalışan dört aşamalı bir ağaç gezginidir. Veri akışı şöyledir:

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

Her aşama, sonraki aşamanın kullandığı küçük bir arayüze sahip PHP sınıfıdır. Bağlama adımı yoktur; ayrıştırma bir AST üretir ve yorumlayıcı bu ağacı doğrudan gezer.

Lexer

src/Lexer/Lexer.php, kaynak metni Token örneklerinden oluşan bir akışa dönüştürür. Her belirteç salt okunur bir yapıdır: tür (TokenType enum'u, yaklaşık 80 durum), değer, satır ve sütun.

Lexer şunları işler:

  • Sayı sabitleri — ondalık, onaltılık (0x), sekizlik (0o), ikilik (0b), üstel gösterim ve sayısal ayraçlar.
  • Dize sabitleri — tek ve çift tırnaklar, tüm kaçış dizileri, iç içe ifadeler içeren şablon dizeleri.
  • Düzenli ifade sabitleri — bir / ifadesinin düzenli ifade mi yoksa bölme mi olması gerektiğini göz önünde bulundurarak tam /pattern/flags belirteçleştirmesi.
  • Tanımlayıcılar, anahtar sözcükler ve noktalama işaretleri.
  • Açıklamalar (satır ve blok), önemsiz bilgi olarak korunur.
  • Unicode kaynağı — UTF-8 baytları, JS UTF-16 kaynağı olarak yorumlanır.

Çıktı, belirteçleri ihtiyaç duyuldukça üreten bir generator'dır. Ayrıştırıcı bunları tek belirteçlik ileri bakışla tüketir.

Ayrıştırıcı

src/Parser/Parser.php elle yazılmış bir Pratt ayrıştırıcısıdır. İfade önceliği src/Parser/Precedence.php içinde tanımlıdır. Deyimler kendi özyinelemeli iniş ayrıştırıcısını kullanır.

Değişmez AST düğümlerini src/Ast/ üzerinden üretir. Her düğüm, yığın izleri ve hata raporlaması için kaynak konumunu taşır.

Dikkat çeken yapılar:

  • İfade: Literal, Identifier, BinaryExpression, UnaryExpression, AssignmentExpression, CallExpression, MemberExpression, ArrowFunction, ObjectExpression, ArrayExpression, ConditionalExpression, TemplateLiteral, SpreadElement, NewExpression, ThisExpression, SequenceExpression, TaggedTemplate, ClassExpression, YieldExpression, AwaitExpression.
  • Deyim: BlockStatement, IfStatement, ForStatement, ForInStatement, ForOfStatement, WhileStatement, DoWhileStatement, SwitchStatement, ReturnStatement, ThrowStatement, TryStatement, BreakStatement, ContinueStatement, ExpressionStatement.
  • Bildirim: VariableDeclaration, FunctionDeclaration, ClassDeclaration, ImportDeclaration.
  • Desen (parçalama): ArrayPattern, ObjectPattern, RestElement, AssignmentPattern.

Otomatik noktalı virgül ekleme, belirtime uygun olarak lexer'da değil ayrıştırıcıda uygulanır.

Yorumlayıcı

src/Runtime/Interpreter.php, AST gezginidir. Her düğümü ziyaret edip bir JsValue (veya kontrol akışını değiştiren deyimler için bir Completion) döndürür.

Önemli yardımcı sınıflar:

  • Environment (src/Runtime/Environment.php) — sözcüksel kapsam zinciri. Her işlev çağrısı, sözcüksel üst öğesine işaret eden yeni bir ortam oluşturur. var, işlev kapsamına taşınır; let / const blok kapsamlıdır ve TDZ'ye tabidir.
  • CallStack (src/Runtime/CallStack.php) — derinlik sınırı olan açık bir yığın. İşlev ve yöntem çağrıları çerçeve ekler; istisnalar bu çerçeveleri kaldırır.
  • Completion (src/Runtime/Completion.php) — normal, return, throw, break, continue değerlerinden oluşan ayırt etiketli birleşim; isteğe bağlı bir değer ve etiket içerir.
  • Reference (src/Runtime/Reference.php) — atamalarda ve delete işlemlerinde sol taraf değerlendirmesi için belirtimde tanımlanan Reference türü.

Değerler

JavaScript değerleri, src/Value/ altında PHP nesneleridir. Her biri JsValue arayüzünü uygular ve kendi tür dönüştürme yöntemlerini (toNumber(), toString(), toBoolean()) içerir.

Sınıf JS türü
JsUndefined undefined (tekil örnek)
JsNull null (tekil örnek)
JsBoolean true / false
JsNumber IEEE 754 double; NaN, ±Infinity, ±0 değerlerini korur
JsString UTF-16 dize semantiği
JsObject Özellik haritası ve prototip zinciri olan temel nesne
JsArray Uzunluk takibiyle JsObject öğesini genişletir
JsFunction Yakalanan Environment değerini içeren closure
JsSymbol Symbol ilkel değeri
JsBigInt bcmath ile keyfi hassasiyet
JsProxy 13 tuzağın tümü, geri alınabilir
JsPromise Eşzamanlı yürütücü + mikro görev kuyruğu
JsGenerator Çift kipli: Bytcode VM § Çerçeve anlık görüntüsü üreticileri bölümüne bakın) ile açıklanan çerçeve anlık görüntüsü (bayt koduna derlenmiş gövdeler); yield*, try-with-yield ve asenkron üreticiler için PHP Fiber geri dönüşü
JsMap, JsSet, JsWeakMap, JsWeakSet, JsWeakRef, JsFinalizationRegistry koleksiyonlar
JsArrayBuffer, JsSharedArrayBuffer, JsDataView, JsTypedArray ikili veriler

Sayı işleme, geçmişteki hataların en büyük tek kaynağıdır: NaN !== NaN doğru olmalı, -0 === 0 doğru olmalı; ToNumber sınır durumları bit düzeyinde özen gerektirir. Spec/TypeConversion sınıfı belirtimdeki algoritmaları kelimesi kelimesine uygular ve kapsamlı biçimde test edilmiştir.

Yerleşik kitaplık

src/BuiltIn/ tüm standart kitaplık nesnelerini sağlar: Array, String, Object, Math, JSON, Date, RegExp, Map, Set, Promise, Proxy, Reflect, Symbol, BigInt, TypedArray, Temporal, Intl, console; ayrıca Web Platformu / Fetch paketleri (URL, Headers, Request, Response, Blob, FormData, tam Streams, EventTarget, AbortController/AbortSignal, DOMException, structuredClone, performance, TextEncoder/TextDecoder, atob/btoa), crypto + SubtleCrypto, WebSocket, XMLHttpRequest ve olay döngüsü (setTimeout, setInterval, queueMicrotask, AsyncContext).

Her yerleşik, bir sınıftaki statik install() yöntemidir. Engine oluşturma sırasında bunları bağımlılık sırasına göre çağırır. Her biri prototip zincirini tanımlar, yöntemleri JsFunction örnekleri olarak PHP closure'ları etrafında kurar ve kurucuyu global olarak sunar.

PHP↔JS köprüsü

Sınır ötesindeki değer dönüşümü iki yerde bulunur:

  • Phasis\Interop\PhpToJs::convert() — PHP değerinden JsValue değerine dönüşüm; setGlobal(), call() argümanları ve ana makine işlevlerinin dönüş değerleri için kullanılır. Çağrılabilir bir PHP, gövdesi onu çağıran bir JsFunction haline gelir.
  • PhpToJs::toPhp() — ana makine işlevinin argümanları için JsValue değerinden PHP değerine dönüşüm.
  • Engine::toPhp() (özel) — eval() ve call() sonuçları için JsValue değerinden PHP değerine dönüşüm.

Nesne köprüsü yoktur: çağrılabilir olmayan PHP nesneleri undefined değerine dönüştürülür (sorun #18). src/Bytecode/ içindeki JsToPhp sınıfının birlikte çalışabilirlikle ilgisi yoktur; aşağıda açıklanan dönüştürücüdür. Dönüştürme kuralları Değer dönüştürme bölümünde açıklanmıştır.

Hata işleme

Yakalanmamış bir JS throw, PHP Phasis\Exceptions\JsThrowable haline gelir; altyapının kendisinin oluşturduğu hatalar Phasis\Exceptions\TypeError, RangeError veya ReferenceError olarak görünür ve bunların tümü Phasis\Exceptions\RuntimeError alt sınıfıdır. Altyapı içinde bir JS try / catch, JsThrowable'i, her türlü RuntimeError'yi ve Phasis\Exceptions\SyntaxError'ü yakalar. Ana makine işlevlerinin fırlattıkları dahil diğer PHP istisnalar dönüştürülmez ve doğrudan PHP çağıranına aktarılır (sorun #20).

İki sınır vardır: çağrı yığını üst sınırı (CallStack::maxDepth, 4,096 çerçeve; ayrıca dönüştürülmüş closure'lar için 8,192 çerçeveli bir koruma) ve maxLoopIterations; Engine::setLimit() üzerinden ayarlanır ve yalnızca ağaç gezgini tarafından uygulanır (sorun #19). Her ikisi de Phasis\Exceptions\InternalError fırlatır. Dize uzunluğu, çıktı boyutu veya yürütme süresi sınırı yoktur.

Bayt Kodu VM

Sık çalışan işlevler iki şekilde daha alt düzeye indirilir. src/Bytecode/ içindeki JsToPhp, sayısal veya yerel değişken ağırlıklı gövdeler için PHP closure'ı üretir; bunu PHP izleme JIT'i yerel koda derleyebilir. İşlem hattı new Ctor(args), obj.method(args) ve this.member okumalarını alt düzeye indirir; bu, döngü içindeki standart sınıf yöntemi örüntüsünün VM'yi tamamen atlamasını sağlar. Diğer her şey, VM::execute tarafından tüketilen düz bayt koduna derlenir; özel çağrı yığını, her JS çağrısını tek bir PHP çerçevesinde tutar ve prototip yöntemi okumaları için her PC'de bir satır içi önbellek kullanır. Basit üretici gövdeleri de bayt koduna derlenir; Op::YIELD, PHP Fiber'ını geçmek yerine bir yığın çerçevesi anlık görüntüsü yakalar.

Derleyicinin alt düzeye indirmediği her yapı (e.g. with, bağlama yeniden atayan bir catch içeren try, yield*, asenkron üreticiler) ağaç gezginine geri döner. Mekanizmanın tamamı için Bayt Kodu VM bölümüne bakın.