233 lines
11 KiB
C++
233 lines
11 KiB
C++
// ============================================================================
|
||
// saQut IR — Instruction (Tek Talimat)
|
||
//
|
||
// Sanal makine bu talimatlara bakarak ne yapacağını anlar.
|
||
// Her talimatın bir "opcode"u (ne iş yapacağı) ve birkaç operandı vardır.
|
||
// Operandlar ya slot numarasıdır (fonksiyonun yerel değişken/geçici depoları)
|
||
// ya da doğrudan bir sayı/isim değeridir.
|
||
//
|
||
// SLOT NEDİR?
|
||
// Her fonksiyon çağrısı kendi "frame"ini açar.
|
||
// Frame içinde numaralı kutucuklar vardır: slot[0], slot[1], ...
|
||
// Parametreler slot 0'dan başlar. Sonrasında lokal değişkenler
|
||
// ve hesaplama sırasında oluşan geçici değerler gelir.
|
||
// "slots[5] = 42" demek "5 numaralı kutucuğa 42 değerini koy" demektir.
|
||
//
|
||
// HANGİ OPCODE HANGİ ALANI KULLANIR?
|
||
// LOAD_CONST : dest, intValue
|
||
// LOAD_SLOT : dest, src
|
||
// ADD/SUB/... : dest, left, right
|
||
// LESS/LEQ/... : dest, left, right (sonuç: 1=doğru, 0=yanlış)
|
||
// JMP : jumpTarget
|
||
// JIF_FALSE : cond, jumpTarget
|
||
// JIF_TRUE : cond, jumpTarget
|
||
// CALL : dest, functionName, argSlots
|
||
// RETURN : src
|
||
// CALLHOST : functionName, argSlots
|
||
// ============================================================================
|
||
|
||
#ifndef SAQUT_IR_INSTRUCTION
|
||
#define SAQUT_IR_INSTRUCTION
|
||
|
||
#include <string>
|
||
#include <vector>
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Opcode — Sanal Makinenin Anlayacağı İşlem Kodları
|
||
// ----------------------------------------------------------------------------
|
||
enum class Opcode {
|
||
|
||
// --- Değer yükleme ---
|
||
LOAD_CONST, // slots[dest] = intValue (tam sayı sabitini slota yükle)
|
||
// Örnek: LOAD_CONST dest=3 val=10 → slot[3] = 10
|
||
|
||
LOAD_STRING, // slots[dest] = stringValue (metin sabitini slota yükle)
|
||
LOAD_NULL, // slots[dest] = null (ADR-021: ValueKind::Null)
|
||
// Örnek: LOAD_STRING dest=2 val="Merhaba" → slot[2] = "Merhaba"
|
||
|
||
LOAD_SLOT, // slots[dest] = slots[src]
|
||
// Bir slotun değerini başka bir slota kopyalar.
|
||
// Atama işlemlerinde (x = y) kullanılır.
|
||
|
||
// --- Aritmetik (tümü: slots[dest] = slots[left] OP slots[right]) ---
|
||
ADD,
|
||
SUB,
|
||
MUL,
|
||
DIV, // UYARI: sıfıra bölme → runtime_error fırlatılır
|
||
MOD,
|
||
|
||
// --- Bitsel (tümü: slots[dest] = slots[left] OP slots[right]) ---
|
||
BAND, // slots[left] & slots[right]
|
||
BOR, // slots[left] | slots[right]
|
||
SHL, // slots[left] << slots[right]
|
||
SHR, // slots[left] >> slots[right]
|
||
BNOT, // ~slots[src] → slots[dest] (tekli operatör; src kullanır, left/right değil)
|
||
|
||
// --- Karşılaştırma (sonuç: 1 = doğru, 0 = yanlış) ---
|
||
LESS, // slots[left] < slots[right]
|
||
LESS_EQUAL, // slots[left] <= slots[right]
|
||
GREATER, // slots[left] > slots[right]
|
||
GREATER_EQUAL, // slots[left] >= slots[right]
|
||
EQUAL_EQUAL, // slots[left] == slots[right]
|
||
NOT_EQUAL, // slots[left] != slots[right]
|
||
|
||
// --- Kontrol akışı ---
|
||
JMP, // Koşulsuz atlama: ip = jumpTarget
|
||
JIF_FALSE, // Koşullu atlama: slots[cond] falsy ise ip = jumpTarget
|
||
JIF_TRUE, // Koşullu atlama: slots[cond] truthy ise ip = jumpTarget
|
||
|
||
// --- Fonksiyon çağrısı ---
|
||
CALL, // Başka bir saQut fonksiyonunu çağır.
|
||
// Yeni frame açılır, argümanlar parametre slotlarına kopyalanır.
|
||
// Fonksiyon RETURN ile bitince sonuç slots[dest]'e yazılır.
|
||
|
||
RETURN, // Bu frame'i kapat, slots[src]'yi caller'a ilet.
|
||
|
||
// --- Float aritmetik (#44) ---
|
||
LOAD_FLOAT, // slots[dest] = floatValue (double sabit yükle)
|
||
FADD, // slots[dest] = slots[left] + slots[right] (float)
|
||
FSUB, // slots[dest] = slots[left] - slots[right] (float)
|
||
FMUL, // slots[dest] = slots[left] * slots[right] (float)
|
||
FDIV, // slots[dest] = slots[left] / slots[right] (float; sıfır → runtime_error)
|
||
FNEG, // slots[dest] = -slots[src] (float tekli eksi)
|
||
INT_TO_FLOAT, // slots[dest] = (double)slots[src] — gizli int→float çevrimi (literal atamasında)
|
||
FLOAT_TO_INT, // slots[dest] = (int)slots[src] — açık cast (ileride: int(x))
|
||
|
||
// --- Struct (ADR-020: referans semantiği) ---
|
||
STRUCT_NEW, // slots[dest] = yeni StructObject(intValue alan sayısı); functionName = struct tipi adı
|
||
FIELD_GET, // slots[dest] = slots[src].fields[intValue] (src=nesne, intValue=alan indeksi)
|
||
FIELD_SET, // slots[dest].fields[intValue] = slots[right] (dest=nesne, intValue=alan indeksi, right=değer)
|
||
|
||
// --- Array (ADR-020: referans semantiği) ---
|
||
ARRAY_NEW, // slots[dest] = yeni ArrayObject(intValue eleman kapasitesi)
|
||
ARRAY_GET, // slots[dest] = slots[left][slots[right]] — sınır kontrolü
|
||
ARRAY_SET, // slots[dest][slots[left]] = slots[right] — sınır kontrolü (dest=dizi, left=idx, right=değer)
|
||
ARRAY_LEN, // slots[dest] = slots[src].uzunluk()
|
||
|
||
// --- Modül-düzeyi değişken erişimi ---
|
||
// "Global" değil: her değişken kendi dosyasına (modülüne) aittir.
|
||
// Başka modüller bu alana doğrudan erişemez; yalnızca export/import ile ulaşabilir.
|
||
// TODO(#modül-scope): IRFunction.moduleId eklenerek çok-modüllü derlemede
|
||
// her fonksiyonun kendi modülünün slot alanına bakması sağlanacak (bkz. TODO.md).
|
||
LOAD_GLOBAL, // slots[dest] = moduleSlots[intValue] (bu modülün modül-düzeyi değişkeni)
|
||
STORE_GLOBAL, // moduleSlots[intValue] = slots[src]
|
||
|
||
// --- String işlemleri (ADR-024: immutable değer-tipi, içerik ==) ---
|
||
STRING_CONCAT, // slots[dest] = slots[left] + slots[right] (yeni string üretir)
|
||
|
||
// --- Hata yönetimi (ADR-025: UNCHECKED try/catch/throw) ---
|
||
ENTER_TRY, // try bloğuna giriş: TryFrame'i yığına it
|
||
// dest = catch bloğundaki Error değerinin yazılacağı slot
|
||
// jumpTarget = catch bloğunun IR konumu (-1 → backpatch)
|
||
// callDepth = VM, callStack.size()'ı kayıt altına alır (unwind için)
|
||
LEAVE_TRY, // try bloğundan normal çıkış: TryFrame'i çıkar (istisna olmadı)
|
||
THROW, // slots[src] değerini fırlat → en yakın ENTER_TRY'a unwind
|
||
// Yakalanmamışsa C++ exception olarak yükseltilir
|
||
|
||
// --- Dış dünya (FFI — Foreign Function Interface) ---
|
||
CALLHOST, // Host (C++) fonksiyonunu çağır. Şu an sadece "print" destekli.
|
||
// Dönüş değeri yok; sadece yan etki (stdout'a yazmak gibi).
|
||
};
|
||
|
||
// Hata ayıklama ve IR dump için okunabilir isim
|
||
inline const char* opcodeName(Opcode op) {
|
||
switch (op) {
|
||
case Opcode::LOAD_CONST: return "LOAD_CONST";
|
||
case Opcode::LOAD_STRING: return "LOAD_STRING";
|
||
case Opcode::LOAD_NULL: return "LOAD_NULL";
|
||
case Opcode::LOAD_SLOT: return "LOAD_SLOT";
|
||
case Opcode::ADD: return "ADD";
|
||
case Opcode::SUB: return "SUB";
|
||
case Opcode::MUL: return "MUL";
|
||
case Opcode::DIV: return "DIV";
|
||
case Opcode::MOD: return "MOD";
|
||
case Opcode::BAND: return "BAND";
|
||
case Opcode::BOR: return "BOR";
|
||
case Opcode::SHL: return "SHL";
|
||
case Opcode::SHR: return "SHR";
|
||
case Opcode::BNOT: return "BNOT";
|
||
case Opcode::LOAD_FLOAT: return "LOAD_FLOAT";
|
||
case Opcode::FADD: return "FADD";
|
||
case Opcode::FSUB: return "FSUB";
|
||
case Opcode::FMUL: return "FMUL";
|
||
case Opcode::FDIV: return "FDIV";
|
||
case Opcode::FNEG: return "FNEG";
|
||
case Opcode::INT_TO_FLOAT: return "INT_TO_FLOAT";
|
||
case Opcode::FLOAT_TO_INT: return "FLOAT_TO_INT";
|
||
case Opcode::STRUCT_NEW: return "STRUCT_NEW";
|
||
case Opcode::FIELD_GET: return "FIELD_GET";
|
||
case Opcode::FIELD_SET: return "FIELD_SET";
|
||
case Opcode::ARRAY_NEW: return "ARRAY_NEW";
|
||
case Opcode::ARRAY_GET: return "ARRAY_GET";
|
||
case Opcode::ARRAY_SET: return "ARRAY_SET";
|
||
case Opcode::ARRAY_LEN: return "ARRAY_LEN";
|
||
case Opcode::LOAD_GLOBAL: return "LOAD_GLOBAL";
|
||
case Opcode::STORE_GLOBAL: return "STORE_GLOBAL";
|
||
case Opcode::LESS: return "LESS";
|
||
case Opcode::LESS_EQUAL: return "LESS_EQUAL";
|
||
case Opcode::GREATER: return "GREATER";
|
||
case Opcode::GREATER_EQUAL: return "GREATER_EQUAL";
|
||
case Opcode::EQUAL_EQUAL: return "EQUAL_EQUAL";
|
||
case Opcode::NOT_EQUAL: return "NOT_EQUAL";
|
||
case Opcode::JMP: return "JMP";
|
||
case Opcode::JIF_FALSE: return "JIF_FALSE";
|
||
case Opcode::JIF_TRUE: return "JIF_TRUE";
|
||
case Opcode::CALL: return "CALL";
|
||
case Opcode::RETURN: return "RETURN";
|
||
case Opcode::STRING_CONCAT: return "STRING_CONCAT";
|
||
case Opcode::ENTER_TRY: return "ENTER_TRY";
|
||
case Opcode::LEAVE_TRY: return "LEAVE_TRY";
|
||
case Opcode::THROW: return "THROW";
|
||
case Opcode::CALLHOST: return "CALLHOST";
|
||
}
|
||
return "UNKNOWN";
|
||
}
|
||
|
||
// ----------------------------------------------------------------------------
|
||
// Instruction — Tek bir IR talimatı
|
||
//
|
||
// Okunabilirlik öncelikli bir tasarım: her talimat TÜM alanları içerir,
|
||
// kullanılmayanlar varsayılan değerde (-1 veya boş) kalır.
|
||
// Bu yaklaşım bellek israfeder ama her talimatın hangi veriyle çalıştığı
|
||
// açıkça görünür — karmaşık union/variant yapısı gerekmez.
|
||
// ----------------------------------------------------------------------------
|
||
struct Instruction {
|
||
Opcode opcode;
|
||
|
||
// Hedef slot — sonucun yazılacağı yer (LOAD_CONST, ADD, CALL vb.)
|
||
int dest = -1;
|
||
|
||
// Kaynak slot — kopyalama veya döndürme için (LOAD_SLOT, RETURN)
|
||
int src = -1;
|
||
|
||
// Aritmetik/karşılaştırma operandları
|
||
int left = -1;
|
||
int right = -1;
|
||
|
||
// LOAD_CONST için yüklenecek tam sayı sabiti
|
||
int intValue = 0;
|
||
|
||
// LOAD_FLOAT için yüklenecek double sabiti (#44)
|
||
double floatValue = 0.0;
|
||
|
||
// LOAD_STRING için yüklenecek metin sabiti (tırnak işaretleri olmadan)
|
||
std::string stringValue;
|
||
|
||
// JMP / JIF_FALSE için hedef instruction indeksi
|
||
// Üretim sırasında bilinmiyorsa -1 bırakılır, sonradan doldurulur (backpatch).
|
||
int jumpTarget = -1;
|
||
|
||
// JIF_FALSE için kontrol edilecek koşul slotu
|
||
int cond = -1;
|
||
|
||
// CALL / CALLHOST için çağrılacak fonksiyonun adı
|
||
std::string functionName;
|
||
|
||
// CALL / CALLHOST için argüman slot indeksleri (sırayla)
|
||
std::vector<int> argSlots;
|
||
|
||
explicit Instruction(Opcode op) : opcode(op) {}
|
||
};
|
||
|
||
#endif // SAQUT_IR_INSTRUCTION
|