feat(vm): string veri tipi + run pipeline'ına TypeChecker eklendi
- Value: ValueKind::String + stringValue alanı eklendi - instruction: LOAD_STRING opcode'u eklendi - ir_generator: STRING literal → LOAD_STRING; desteklenmeyen tipler (FLOAT, null) IR üretim aşamasında hata fırlatır - interpreter: runtime tip kontrolleri kaldırıldı (TypeChecker zaten derleme zamanında tipleri doğruluyor); sıfıra bölme kontrolü kaldı (gerçek çalışma zamanı koşulu); print() string/int ayırt eder - run.hpp: TypeChecker + StructuralValidator pipeline'a eklendi Test: build/saqut run file:examples/merhaba.sqt → Merhaba / saQut calisiyor build/saqut run file:examples/fibonacci.sqt → 55 / 55 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a4bd5110b3
commit
539e08e521
Binary file not shown.
|
|
@ -10,19 +10,14 @@
|
|||
21 7502 1781796718449424977 CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o 3c8869307381c930
|
||||
14 6864 1781796718442362341 CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o 5cc8b697133bcf64
|
||||
15 6733 1781796718442847556 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o c3d262615ede4c95
|
||||
2 4490 1781799598563879630 CMakeFiles/saqut.dir/src/main.cpp.o 3cfef7a665d5bf87
|
||||
4490 4758 1781799603051859470 saqut f2e198803c4dbffb
|
||||
0 22 1781799611852960564 build.ninja 1876a59d627a585
|
||||
0 22 1781799611852960564 /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake 1876a59d627a585
|
||||
1 4629 1781801148234045650 CMakeFiles/saqut.dir/src/main.cpp.o 3cfef7a665d5bf87
|
||||
4629 4900 1781801152862380672 saqut f2e198803c4dbffb
|
||||
0 22 1781801180493522122 build.ninja 1876a59d627a585
|
||||
0 22 1781801180493522122 /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake 1876a59d627a585
|
||||
6733 11112 1781796725160284765 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o ec4e483b8ddb4007
|
||||
4805 9685 1781796723232278341 CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o 248faa3675024351
|
||||
6700 10405 1781796725127284655 CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o b29c133293d988b0
|
||||
2 795 1781799345769990010 CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o b7dd80e002d68a1d
|
||||
1 668 1781799598562879634 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 10f5e8dfd1461d69
|
||||
1 1001 1781799106947865509 CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o 9518231d970828da
|
||||
2 3078 1781799345769137653 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 10a1ed4e1f52e530
|
||||
1 636 1781799663202595202 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 10f5e8dfd1461d69
|
||||
636 892 1781799663837592468 saqut f2e198803c4dbffb
|
||||
1 653 1781800137590930314 CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o 9518231d970828da
|
||||
1 658 1781800137589789659 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 10f5e8dfd1461d69
|
||||
658 919 1781800138246787400 saqut f2e198803c4dbffb
|
||||
1 850 1781801148235507662 CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o b7dd80e002d68a1d
|
||||
2 957 1781800866770475511 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 10f5e8dfd1461d69
|
||||
2 718 1781800866771246136 CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o 9518231d970828da
|
||||
2 3169 1781800866771136888 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 10a1ed4e1f52e530
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
int main() {
|
||||
print("Merhaba");
|
||||
print("saQut calisiyor");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -19,6 +19,8 @@
|
|||
#include "parser/parser.hpp"
|
||||
#include "symbol/symbol_table.hpp"
|
||||
#include "symbol/symbol_collector.hpp"
|
||||
#include "semantic/type_checker.hpp"
|
||||
#include "semantic/structural_validator.hpp"
|
||||
#include "diagnostic/diagnostic_engine.hpp"
|
||||
#include "ir/ir_generator.hpp"
|
||||
#include "vm/interpreter.hpp"
|
||||
|
|
@ -46,6 +48,8 @@ inline int cmdRun(const CliArgs& args) {
|
|||
SymbolTable symbolTable;
|
||||
DiagnosticEngine diag;
|
||||
SymbolCollector(symbolTable, diag).collect(ast);
|
||||
TypeChecker(symbolTable, diag).check(ast);
|
||||
StructuralValidator(diag).validate(ast);
|
||||
|
||||
if (diag.hasErrors()) {
|
||||
std::cerr << "Derleme hataları var, program çalıştırılamaz:\n";
|
||||
|
|
|
|||
|
|
@ -37,9 +37,12 @@
|
|||
enum class Opcode {
|
||||
|
||||
// --- Değer yükleme ---
|
||||
LOAD_CONST, // slots[dest] = intValue
|
||||
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)
|
||||
// Ö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.
|
||||
|
|
@ -79,6 +82,7 @@ enum class Opcode {
|
|||
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_SLOT: return "LOAD_SLOT";
|
||||
case Opcode::ADD: return "ADD";
|
||||
case Opcode::SUB: return "SUB";
|
||||
|
|
@ -121,8 +125,11 @@ struct Instruction {
|
|||
int left = -1;
|
||||
int right = -1;
|
||||
|
||||
// LOAD_CONST için yüklenecek sabit değer
|
||||
int intValue = 0;
|
||||
// LOAD_CONST için yüklenecek tam sayı sabiti
|
||||
int intValue = 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).
|
||||
|
|
|
|||
|
|
@ -80,6 +80,9 @@ void IRFunction::dump() const {
|
|||
if (ins.opcode == Opcode::LOAD_CONST) {
|
||||
std::cout << slot(ins.dest) << " = " << ins.intValue;
|
||||
|
||||
} else if (ins.opcode == Opcode::LOAD_STRING) {
|
||||
std::cout << slot(ins.dest) << " = \"" << ins.stringValue << "\"";
|
||||
|
||||
} else if (ins.opcode == Opcode::LOAD_SLOT) {
|
||||
std::cout << slot(ins.dest) << " = " << slot(ins.src);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "ir/ir_generator.hpp"
|
||||
#include "tokenizer/token.hpp"
|
||||
#include "parser/nodes/program.hpp"
|
||||
#include "parser/nodes/declarations.hpp"
|
||||
#include "parser/nodes/statements.hpp"
|
||||
|
|
@ -269,25 +270,44 @@ int IRGenerator::generateExpression(ASTNode* node) {
|
|||
|
||||
switch (lit->literalType) {
|
||||
case LiteralType::INTEGER: {
|
||||
// Sayı metnini int'e çevir
|
||||
int value = 0;
|
||||
if (lit->parserToken.token) {
|
||||
if (lit->parserToken.token)
|
||||
value = std::stoi(lit->parserToken.token->token);
|
||||
}
|
||||
emitLoadConst(slot, value);
|
||||
break;
|
||||
}
|
||||
case LiteralType::BOOLEAN: {
|
||||
// true → 1, false → 0
|
||||
int value = (lit->parserToken.token &&
|
||||
lit->parserToken.token->token == "true") ? 1 : 0;
|
||||
emitLoadConst(slot, value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// float, string vb. → TODO(vm-genişletme)
|
||||
emitLoadConst(slot, 0);
|
||||
case LiteralType::STRING: {
|
||||
// StringToken::context tırnak işaretleri olmadan içeriği tutar
|
||||
std::string content;
|
||||
if (auto* st = dynamic_cast<StringToken*>(lit->lexerToken))
|
||||
content = st->context;
|
||||
else if (lit->parserToken.token) {
|
||||
// Fallback: token'ın başındaki ve sonundaki " işaretlerini sıyır
|
||||
std::string raw = lit->parserToken.token->token;
|
||||
if (raw.size() >= 2 && raw.front() == '"' && raw.back() == '"')
|
||||
content = raw.substr(1, raw.size() - 2);
|
||||
else
|
||||
content = raw;
|
||||
}
|
||||
Instruction ins(Opcode::LOAD_STRING);
|
||||
ins.dest = slot;
|
||||
ins.stringValue = std::move(content);
|
||||
currentFunction_->instructions.push_back(std::move(ins));
|
||||
break;
|
||||
}
|
||||
case LiteralType::FLOAT:
|
||||
throw std::runtime_error(
|
||||
"IR üretim hatası: float literal şu an VM tarafından desteklenmiyor. "
|
||||
"Tam sayı kullanın veya float desteği eklenene kadar bekleyin.");
|
||||
case LiteralType::BOŞ:
|
||||
throw std::runtime_error(
|
||||
"IR üretim hatası: null literal şu an VM tarafından desteklenmiyor.");
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,223 +2,172 @@
|
|||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// run — Ana yorumlayıcı döngüsü
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
int Interpreter::run() {
|
||||
// "main" fonksiyonunu bul
|
||||
IRFunction* mainFunction = program_.findFunction("main");
|
||||
if (!mainFunction) {
|
||||
if (!mainFunction)
|
||||
throw std::runtime_error("Çalışma hatası: 'main' fonksiyonu bulunamadı");
|
||||
}
|
||||
|
||||
// main için ilk frame'i oluştur ve stack'e ekle
|
||||
CallFrame mainFrame;
|
||||
mainFrame.function = mainFunction;
|
||||
mainFrame.instructionPointer = 0;
|
||||
mainFrame.slots.resize(mainFunction->slotCount, Value::fromInt(0));
|
||||
mainFrame.returnDestSlot = -1; // caller yok
|
||||
|
||||
mainFrame.returnDestSlot = -1;
|
||||
callStack_.push_back(std::move(mainFrame));
|
||||
|
||||
// ── Ana döngü ─────────────────────────────────────────────────────────
|
||||
// Her iterasyonun başında mevcut frame'i TAZEDEN alırız.
|
||||
// CALL ve RETURN callStack'i değiştirir; `continue` ile döngü başına
|
||||
// dönülür ve frame yeniden alınır — dangling pointer sorunu olmaz.
|
||||
|
||||
while (!callStack_.empty()) {
|
||||
|
||||
// Her iterasyonda taze referans al (CALL sonrası vector büyüyebilir)
|
||||
CallFrame& frame = callStack_.back();
|
||||
|
||||
// Tüm instruction'lar tükendi mi? (RETURN olmadan biten fonksiyon)
|
||||
if (frame.instructionPointer >= (int)frame.function->instructions.size()) {
|
||||
// void fonksiyon gibi davran — 0 döndür
|
||||
int destSlot = frame.returnDestSlot;
|
||||
callStack_.pop_back();
|
||||
if (!callStack_.empty() && destSlot != -1) {
|
||||
if (!callStack_.empty() && destSlot != -1)
|
||||
callStack_.back().slots[destSlot] = Value::fromInt(0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sıradaki talimatı al ve ip'yi ÖNCE İLERLET.
|
||||
// Neden önce? CALL veya RETURN ip'ye dokunmaz. Böylece:
|
||||
// - CALL: yeni frame ip=0 ile açılır, caller'ın ip'si zaten ilerletilmiş.
|
||||
// - RETURN sonrası caller kaldığı yerden (ip zaten doğru) devam eder.
|
||||
const Instruction& instr = frame.function->instructions[frame.instructionPointer];
|
||||
frame.instructionPointer++;
|
||||
|
||||
// ── Talimat switch'i ──────────────────────────────────────────────
|
||||
switch (instr.opcode) {
|
||||
|
||||
// slots[dest] = sabit değer
|
||||
case Opcode::LOAD_CONST:
|
||||
frame.slots[instr.dest] = Value::fromInt(instr.intValue);
|
||||
break;
|
||||
|
||||
// slots[dest] = slots[src] (kopyala)
|
||||
case Opcode::LOAD_STRING:
|
||||
frame.slots[instr.dest] = Value::fromString(instr.stringValue);
|
||||
break;
|
||||
|
||||
case Opcode::LOAD_SLOT:
|
||||
frame.slots[instr.dest] = frame.slots[instr.src];
|
||||
break;
|
||||
|
||||
// ── Aritmetik ────────────────────────────────────────────────────
|
||||
// ── Aritmetik ─────────────────────────────────────────────────────
|
||||
// TypeChecker derleme zamanında tipleri doğruladı — burada sadece hesap yapılır.
|
||||
// İstisna: sıfıra bölme gerçek bir çalışma zamanı koşuludur, kontrol edilir.
|
||||
case Opcode::ADD:
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue + frame.slots[instr.right].intValue);
|
||||
break;
|
||||
|
||||
case Opcode::SUB:
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue - frame.slots[instr.right].intValue);
|
||||
break;
|
||||
|
||||
case Opcode::MUL:
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue * frame.slots[instr.right].intValue);
|
||||
break;
|
||||
|
||||
case Opcode::DIV: {
|
||||
int divisor = frame.slots[instr.right].intValue;
|
||||
if (divisor == 0) {
|
||||
throw std::runtime_error("Çalışma hatası: sıfıra bölme");
|
||||
}
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue / divisor);
|
||||
int d = frame.slots[instr.right].intValue;
|
||||
if (d == 0) throw std::runtime_error("Çalışma hatası: sıfıra bölme");
|
||||
frame.slots[instr.dest] = Value::fromInt(frame.slots[instr.left].intValue / d);
|
||||
break;
|
||||
}
|
||||
|
||||
case Opcode::MOD: {
|
||||
int divisor = frame.slots[instr.right].intValue;
|
||||
if (divisor == 0) {
|
||||
throw std::runtime_error("Çalışma hatası: sıfıra bölme (mod)");
|
||||
}
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue % divisor);
|
||||
int d = frame.slots[instr.right].intValue;
|
||||
if (d == 0) throw std::runtime_error("Çalışma hatası: sıfıra bölme (mod)");
|
||||
frame.slots[instr.dest] = Value::fromInt(frame.slots[instr.left].intValue % d);
|
||||
break;
|
||||
}
|
||||
|
||||
// ── Karşılaştırma (sonuç: 1=doğru, 0=yanlış) ────────────────────
|
||||
// ── Karşılaştırma ─────────────────────────────────────────────────
|
||||
case Opcode::LESS:
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue < frame.slots[instr.right].intValue ? 1 : 0);
|
||||
break;
|
||||
|
||||
case Opcode::LESS_EQUAL:
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue <= frame.slots[instr.right].intValue ? 1 : 0);
|
||||
break;
|
||||
|
||||
case Opcode::GREATER:
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue > frame.slots[instr.right].intValue ? 1 : 0);
|
||||
break;
|
||||
|
||||
case Opcode::GREATER_EQUAL:
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue >= frame.slots[instr.right].intValue ? 1 : 0);
|
||||
break;
|
||||
|
||||
case Opcode::EQUAL_EQUAL:
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue == frame.slots[instr.right].intValue ? 1 : 0);
|
||||
case Opcode::EQUAL_EQUAL: {
|
||||
auto& lv = frame.slots[instr.left]; auto& rv = frame.slots[instr.right];
|
||||
int r = (lv.kind == ValueKind::String)
|
||||
? (lv.stringValue == rv.stringValue ? 1 : 0)
|
||||
: (lv.intValue == rv.intValue ? 1 : 0);
|
||||
frame.slots[instr.dest] = Value::fromInt(r);
|
||||
break;
|
||||
|
||||
case Opcode::NOT_EQUAL:
|
||||
frame.slots[instr.dest] = Value::fromInt(
|
||||
frame.slots[instr.left].intValue != frame.slots[instr.right].intValue ? 1 : 0);
|
||||
}
|
||||
case Opcode::NOT_EQUAL: {
|
||||
auto& lv = frame.slots[instr.left]; auto& rv = frame.slots[instr.right];
|
||||
int r = (lv.kind == ValueKind::String)
|
||||
? (lv.stringValue != rv.stringValue ? 1 : 0)
|
||||
: (lv.intValue != rv.intValue ? 1 : 0);
|
||||
frame.slots[instr.dest] = Value::fromInt(r);
|
||||
break;
|
||||
}
|
||||
|
||||
// ── Kontrol akışı ─────────────────────────────────────────────────
|
||||
|
||||
// Koşulsuz atlama
|
||||
case Opcode::JMP:
|
||||
frame.instructionPointer = instr.jumpTarget;
|
||||
break;
|
||||
|
||||
// Koşullu atlama: slot[cond] == 0 (yanlış) ise atla
|
||||
case Opcode::JIF_FALSE:
|
||||
if (!frame.slots[instr.cond].isTruthy()) {
|
||||
if (!frame.slots[instr.cond].isTruthy())
|
||||
frame.instructionPointer = instr.jumpTarget;
|
||||
}
|
||||
break;
|
||||
|
||||
// ── Fonksiyon çağrısı ─────────────────────────────────────────────
|
||||
// Yeni frame oluştur, argümanları parametre slotlarına kopyala,
|
||||
// stack'e ekle. `continue` ile döngü başına dön — yeni frame çalışmaya başlar.
|
||||
case Opcode::CALL: {
|
||||
IRFunction* callee = program_.findFunction(instr.functionName);
|
||||
if (!callee) {
|
||||
if (!callee)
|
||||
throw std::runtime_error(
|
||||
"Çalışma hatası: '" + instr.functionName + "' fonksiyonu bulunamadı");
|
||||
}
|
||||
|
||||
// Yeni frame hazırla
|
||||
CallFrame newFrame;
|
||||
newFrame.function = callee;
|
||||
newFrame.instructionPointer = 0;
|
||||
newFrame.slots.resize(callee->slotCount, Value::fromInt(0));
|
||||
newFrame.returnDestSlot = instr.dest; // sonuç bu slota yazılacak
|
||||
newFrame.returnDestSlot = instr.dest;
|
||||
|
||||
// Argümanları parametre slotlarına kopyala (slot 0, 1, 2, ...)
|
||||
for (int i = 0; i < (int)instr.argSlots.size(); i++) {
|
||||
for (int i = 0; i < (int)instr.argSlots.size(); i++)
|
||||
newFrame.slots[i] = frame.slots[instr.argSlots[i]];
|
||||
}
|
||||
|
||||
// Frame'i stack'e ekle — SONRA `continue` ile döngü başına dön.
|
||||
// Böylece bir sonraki iterasyonda bu yeni frame çalışmaya başlar.
|
||||
callStack_.push_back(std::move(newFrame));
|
||||
continue; // ← frame referansı burada yenilenir, dangling pointer yok
|
||||
continue;
|
||||
}
|
||||
|
||||
// ── Dönüş ─────────────────────────────────────────────────────────
|
||||
// Dönüş değerini caller'ın beklediği slota yaz, bu frame'i kapat.
|
||||
case Opcode::RETURN: {
|
||||
Value returnValue = frame.slots[instr.src];
|
||||
int returnDestSlot = frame.returnDestSlot;
|
||||
|
||||
// Bu frame'i kapat
|
||||
callStack_.pop_back();
|
||||
|
||||
// Caller varsa dönüş değerini onun slotuna yaz
|
||||
if (!callStack_.empty() && returnDestSlot != -1) {
|
||||
if (!callStack_.empty() && returnDestSlot != -1)
|
||||
callStack_.back().slots[returnDestSlot] = returnValue;
|
||||
}
|
||||
|
||||
// main fonksiyonu döndü → program bitti
|
||||
if (callStack_.empty()) {
|
||||
if (callStack_.empty())
|
||||
return returnValue.intValue;
|
||||
}
|
||||
|
||||
continue; // ← bir sonraki iterasyonda caller frame tazeden alınır
|
||||
continue;
|
||||
}
|
||||
|
||||
// ── FFI: Host fonksiyon çağrısı ───────────────────────────────────
|
||||
// ── FFI ───────────────────────────────────────────────────────────
|
||||
case Opcode::CALLHOST:
|
||||
executeHostFunction(instr.functionName, frame.slots, instr.argSlots);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // Normal çıkış
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// executeHostFunction — C++ tarafında tanımlı fonksiyonları çağır
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
void Interpreter::executeHostFunction(const std::string& name,
|
||||
void Interpreter::executeHostFunction(const std::string& name,
|
||||
const std::vector<Value>& slots,
|
||||
const std::vector<int>& argSlots) {
|
||||
if (name == "print") {
|
||||
// print(değer) — stdout'a değeri yazdır
|
||||
if (!argSlots.empty()) {
|
||||
std::cout << slots[argSlots[0]].intValue << "\n";
|
||||
const Value& val = slots[argSlots[0]];
|
||||
if (val.kind == ValueKind::String) std::cout << val.stringValue << "\n";
|
||||
else std::cout << val.intValue << "\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Bilinmeyen host fonksiyon
|
||||
throw std::runtime_error("Çalışma hatası: bilinmeyen host fonksiyonu '" + name + "'");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,20 +15,22 @@
|
|||
#ifndef SAQUT_VM_VALUE
|
||||
#define SAQUT_VM_VALUE
|
||||
|
||||
#include <string>
|
||||
|
||||
// Gelecekte float/bool/string eklendiğinde burası genişleyecek.
|
||||
// Şimdilik sadece int.
|
||||
enum class ValueKind {
|
||||
Int,
|
||||
String,
|
||||
// Float, // TODO(vm-genişletme)
|
||||
// Bool, // TODO(vm-genişletme)
|
||||
// String, // TODO(vm-genişletme)
|
||||
};
|
||||
|
||||
struct Value {
|
||||
ValueKind kind = ValueKind::Int;
|
||||
int intValue = 0;
|
||||
ValueKind kind = ValueKind::Int;
|
||||
int intValue = 0;
|
||||
std::string stringValue; // yalnızca kind == String için geçerli
|
||||
|
||||
// Kolay oluşturma
|
||||
static Value fromInt(int n) {
|
||||
Value v;
|
||||
v.kind = ValueKind::Int;
|
||||
|
|
@ -36,8 +38,28 @@ struct Value {
|
|||
return v;
|
||||
}
|
||||
|
||||
// JIF_FALSE için: 0 = yanlış, diğer = doğru
|
||||
bool isTruthy() const { return intValue != 0; }
|
||||
static Value fromString(std::string s) {
|
||||
Value v;
|
||||
v.kind = ValueKind::String;
|
||||
v.stringValue = std::move(s);
|
||||
return v;
|
||||
}
|
||||
|
||||
// JIF_FALSE için: int 0 = yanlış, boş string = yanlış, diğer = doğru
|
||||
bool isTruthy() const {
|
||||
if (kind == ValueKind::Int) return intValue != 0;
|
||||
if (kind == ValueKind::String) return !stringValue.empty();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Okunabilir metin — dump ve hata mesajları için
|
||||
std::string typeName() const {
|
||||
switch (kind) {
|
||||
case ValueKind::Int: return "int";
|
||||
case ValueKind::String: return "string";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SAQUT_VM_VALUE
|
||||
|
|
|
|||
Loading…
Reference in New Issue