feat(struct+null): struct runtime + ValueKind::Null + E010 ADR-020 revizyonu
- value.hpp: ValueKind::Nil → ValueKind::Null (saQut'ta null anahtar sözcüğü) - object.hpp: StructObject : Object eklendi (alanlar sıralı Value[] olarak) - instruction.hpp: STRUCT_NEW, FIELD_GET, FIELD_SET opcodes - ir_generator: struct layout haritası (sembol tablosundan), VariableDecl struct init, MemberAccess okuma/yazma codegen - interpreter: STRUCT_NEW/FIELD_GET/FIELD_SET + referans semantiği - ir_function: STRUCT_NEW/FIELD_GET/FIELD_SET dump - symbol_table: structLayouts haritası + getFieldIndex/getFieldType yardımcıları - symbol_collector: StructDecl her zaman structFields_ girişi açar; structLayouts doldurur - E010 devre dışı — ADR-020: struct alanları referans semantiği taşır, by-value döngü yok - type_checker: MemberAccess struct alan tipi çözümlendi; IndexExpression array eleman tipi - parser: parseStatement'a "TypeName VarName" → parseVariableDecl desteği (struct değişkeni) - golden test: tests/golden/struct/basic.sqt (21 test geçiyor) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f1cb983b69
commit
435c8bcb96
|
|
@ -82,6 +82,11 @@ enum class Opcode {
|
|||
|
||||
RETURN, // Bu frame'i kapat, slots[src]'yi caller'a ilet.
|
||||
|
||||
// --- 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ü
|
||||
|
|
@ -117,6 +122,9 @@ inline const char* opcodeName(Opcode op) {
|
|||
case Opcode::SHL: return "SHL";
|
||||
case Opcode::SHR: return "SHR";
|
||||
case Opcode::BNOT: return "BNOT";
|
||||
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";
|
||||
|
|
|
|||
|
|
@ -121,6 +121,15 @@ void IRFunction::dump() const {
|
|||
} else if (ins.opcode == Opcode::BNOT) {
|
||||
std::cout << slot(ins.dest) << " = ~" << slot(ins.src);
|
||||
|
||||
} else if (ins.opcode == Opcode::STRUCT_NEW) {
|
||||
std::cout << slot(ins.dest) << " = struct<" << ins.functionName << ">[" << ins.intValue << " alan]";
|
||||
|
||||
} else if (ins.opcode == Opcode::FIELD_GET) {
|
||||
std::cout << slot(ins.dest) << " = " << slot(ins.src) << "." << ins.intValue;
|
||||
|
||||
} else if (ins.opcode == Opcode::FIELD_SET) {
|
||||
std::cout << slot(ins.dest) << "." << ins.intValue << " = " << slot(ins.right);
|
||||
|
||||
} else if (ins.opcode == Opcode::ARRAY_NEW) {
|
||||
std::cout << slot(ins.dest) << " = array[" << ins.intValue << "]";
|
||||
|
||||
|
|
|
|||
|
|
@ -14,9 +14,12 @@
|
|||
// generate — Ana giriş noktası
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
IRProgram IRGenerator::generate(ASTNode* programNode, SymbolTable& /*symbolTable*/) {
|
||||
IRProgram IRGenerator::generate(ASTNode* programNode, SymbolTable& symbolTable) {
|
||||
IRProgram program;
|
||||
|
||||
// 0. Geçiş: struct layout haritasını sembol tablosundan al
|
||||
structLayouts_ = symbolTable.structLayouts;
|
||||
|
||||
// 1. Geçiş: modül-düzeyi VariableDecl'leri topla ve kayıt et
|
||||
// "Global" değil — bu dosyanın (modülün) kendi değişkenleri.
|
||||
std::vector<VariableDeclNode*> globalVars;
|
||||
|
|
@ -97,7 +100,7 @@ void IRGenerator::generateStatement(ASTNode* node) {
|
|||
break;
|
||||
}
|
||||
|
||||
// ── Değişken bildirimi: int x = <ifade> ──────────────────────────────
|
||||
// ── Değişken bildirimi: int x = <ifade> / Point p; ────────────────
|
||||
case ASTKind::VariableDecl: {
|
||||
auto* vd = (VariableDeclNode*)node;
|
||||
|
||||
|
|
@ -106,14 +109,12 @@ void IRGenerator::generateStatement(ASTNode* node) {
|
|||
registerVariable(vd->name, varSlot);
|
||||
|
||||
if (vd->initExpr) {
|
||||
// Başlatma ifadesini üret, sonucu bir slotta al
|
||||
int initSlot = generateExpression(vd->initExpr);
|
||||
|
||||
if (initSlot != varSlot) {
|
||||
// Sonuç başka bir slotta, değişkenin slotuna kopyala
|
||||
emitLoadSlot(varSlot, initSlot);
|
||||
}
|
||||
// initSlot == varSlot: LOAD_CONST doğrudan varSlot'a yazıldı, kopya gerekmez
|
||||
if (initSlot != varSlot) emitLoadSlot(varSlot, initSlot);
|
||||
} else if (structLayouts_.count(vd->varType)) {
|
||||
// Struct değişkeni: init ifadesi yoksa boş StructObject oluştur
|
||||
int fc = getStructFieldCount(vd->varType);
|
||||
emitStructNew(varSlot, vd->varType, fc);
|
||||
}
|
||||
|
||||
// Sibling VariableDecl'ler: int a, b; → children'da diğer VariableDecl'ler
|
||||
|
|
@ -389,6 +390,18 @@ int IRGenerator::generateExpression(ASTNode* node) {
|
|||
return rhsSlot;
|
||||
}
|
||||
|
||||
// p.field = val → FIELD_SET
|
||||
if (bin->Left && bin->Left->kind == ASTKind::MemberAccess) {
|
||||
auto* ma = (MemberAccessNode*)bin->Left;
|
||||
int objSlot = generateExpression(ma->object);
|
||||
std::string structName;
|
||||
if (auto* exprObj = dynamic_cast<ExpressionNode*>(ma->object))
|
||||
structName = exprObj->resolvedType.structName;
|
||||
int idx2 = getStructFieldIndex(structName, ma->member);
|
||||
if (idx2 >= 0) emitFieldSet(objSlot, idx2, rhsSlot);
|
||||
return rhsSlot;
|
||||
}
|
||||
|
||||
auto* lhsId = (IdentifierNode*)bin->Left;
|
||||
std::string varName = lhsId->parserToken.token->token;
|
||||
|
||||
|
|
@ -589,7 +602,19 @@ int IRGenerator::generateExpression(ASTNode* node) {
|
|||
return resultSlot; // artırmadan önceki değer
|
||||
}
|
||||
|
||||
// ── Array literali: [1, 2, 3] ─────────────────────────────────────────
|
||||
// ── Üye erişimi okuma: p.x ───────────────────────────────────────────
|
||||
case ASTKind::MemberAccess: {
|
||||
auto* ma = (MemberAccessNode*)node;
|
||||
int objSlot = generateExpression(ma->object);
|
||||
int destSlot = freshSlot();
|
||||
// Nesnenin struct adını resolvedType üstünden al (tip denetleyici yazdı)
|
||||
std::string structName;
|
||||
if (auto* exprObj = dynamic_cast<ExpressionNode*>(ma->object))
|
||||
structName = exprObj->resolvedType.structName;
|
||||
int idx = getStructFieldIndex(structName, ma->member);
|
||||
if (idx >= 0) emitFieldGet(destSlot, objSlot, idx);
|
||||
return destSlot;
|
||||
}
|
||||
case ASTKind::ArrayLiteral: {
|
||||
auto* al = (ArrayLiteralNode*)node;
|
||||
int arrSlot = freshSlot();
|
||||
|
|
@ -685,6 +710,30 @@ void IRGenerator::emitStoreGlobal(int srcSlot, int globalIndex) {
|
|||
currentFunction_->instructions.push_back(std::move(ins));
|
||||
}
|
||||
|
||||
void IRGenerator::emitStructNew(int destSlot, const std::string& structType, int fieldCount) {
|
||||
Instruction ins(Opcode::STRUCT_NEW);
|
||||
ins.dest = destSlot;
|
||||
ins.intValue = fieldCount;
|
||||
ins.functionName = structType; // struct tip adı
|
||||
currentFunction_->instructions.push_back(std::move(ins));
|
||||
}
|
||||
|
||||
void IRGenerator::emitFieldGet(int destSlot, int objSlot, int fieldIdx) {
|
||||
Instruction ins(Opcode::FIELD_GET);
|
||||
ins.dest = destSlot;
|
||||
ins.src = objSlot;
|
||||
ins.intValue = fieldIdx;
|
||||
currentFunction_->instructions.push_back(std::move(ins));
|
||||
}
|
||||
|
||||
void IRGenerator::emitFieldSet(int objSlot, int fieldIdx, int valSlot) {
|
||||
Instruction ins(Opcode::FIELD_SET);
|
||||
ins.dest = objSlot;
|
||||
ins.intValue = fieldIdx;
|
||||
ins.right = valSlot;
|
||||
currentFunction_->instructions.push_back(std::move(ins));
|
||||
}
|
||||
|
||||
void IRGenerator::emitArrayNew(int destSlot, int capacity) {
|
||||
Instruction ins(Opcode::ARRAY_NEW);
|
||||
ins.dest = destSlot;
|
||||
|
|
@ -715,6 +764,20 @@ void IRGenerator::emitArrayLen(int destSlot, int arrSlot) {
|
|||
currentFunction_->instructions.push_back(std::move(ins));
|
||||
}
|
||||
|
||||
int IRGenerator::getStructFieldIndex(const std::string& structType, const std::string& fieldName) const {
|
||||
auto it = structLayouts_.find(structType);
|
||||
if (it == structLayouts_.end()) return -1;
|
||||
for (int i = 0; i < (int)it->second.size(); i++)
|
||||
if (it->second[i].first == fieldName) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int IRGenerator::getStructFieldCount(const std::string& structType) const {
|
||||
auto it = structLayouts_.find(structType);
|
||||
if (it == structLayouts_.end()) return 0;
|
||||
return (int)it->second.size();
|
||||
}
|
||||
|
||||
bool IRGenerator::isGlobal(const std::string& name) const {
|
||||
return nameToGlobal_.count(name) > 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,11 @@
|
|||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include "ir/ir_program.hpp"
|
||||
#include "symbol/symbol_table.hpp"
|
||||
#include "core/type.hpp"
|
||||
#include "parser/ast_node.hpp"
|
||||
|
||||
class IRGenerator {
|
||||
|
|
@ -58,6 +61,9 @@ private:
|
|||
void emitLoadSlot(int destSlot, int srcSlot);
|
||||
void emitLoadGlobal(int destSlot, int globalIndex);
|
||||
void emitStoreGlobal(int srcSlot, int globalIndex);
|
||||
void emitStructNew(int destSlot, const std::string& structType, int fieldCount);
|
||||
void emitFieldGet(int destSlot, int objSlot, int fieldIdx);
|
||||
void emitFieldSet(int objSlot, int fieldIdx, int valSlot);
|
||||
void emitArrayNew(int destSlot, int capacity);
|
||||
void emitArrayGet(int destSlot, int arrSlot, int idxSlot);
|
||||
void emitArraySet(int arrSlot, int idxSlot, int valSlot);
|
||||
|
|
@ -101,6 +107,13 @@ private:
|
|||
std::unordered_map<std::string, int> nameToGlobal_;
|
||||
int globalCount_ = 0;
|
||||
|
||||
// Struct alan düzeni: struct adı → sıralı [(alan adı, Type)] listesi
|
||||
// Sembol tablosundan generate() başında kopyalanır.
|
||||
std::unordered_map<std::string, std::vector<std::pair<std::string, Type>>> structLayouts_;
|
||||
|
||||
int getStructFieldIndex(const std::string& structType, const std::string& fieldName) const;
|
||||
int getStructFieldCount(const std::string& structType) const;
|
||||
|
||||
bool isGlobal(const std::string& name) const;
|
||||
int getGlobalIndex(const std::string& name) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -497,6 +497,15 @@ ASTNode* Parser::parseStatement() {
|
|||
if (ct.type == TokenType::KW_STRUCT)
|
||||
return parseStructDecl();
|
||||
|
||||
// Kullanıcı tanımlı struct tipiyle değişken bildirimi: Point p; veya Point p = ...;
|
||||
if (ct.type == TokenType::IDENTIFIER) {
|
||||
auto la1 = lookahead(1);
|
||||
// "TypeName varName" veya "TypeName varName = ..." → değişken bildirimi
|
||||
// (TypeName LPAREN → ifade; o durumda parseExpressionStatement devam eder)
|
||||
if (la1.type == TokenType::IDENTIFIER)
|
||||
return parseVariableDecl();
|
||||
}
|
||||
|
||||
return parseExpressionStatement();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@ void TypeChecker::checkStmt(ASTNode* node) {
|
|||
case ASTKind::VariableDecl: {
|
||||
auto* vd = (VariableDeclNode*)node;
|
||||
Type targetType = Type::fromName(vd->varType);
|
||||
if (targetType.isError() && table_.structLayouts.count(vd->varType))
|
||||
targetType = Type::structType(vd->varType);
|
||||
if (vd->initExpr) {
|
||||
Type srcType = checkExpr(vd->initExpr, targetType);
|
||||
bool isLit = vd->initExpr->kind == ASTKind::Literal;
|
||||
|
|
@ -374,15 +376,26 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) {
|
|||
// ── MemberAccess / IndexExpression ─────────────────────────────────────
|
||||
case ASTKind::MemberAccess: {
|
||||
auto* ma = (MemberAccessNode*)node;
|
||||
checkExpr(ma->object);
|
||||
result = Type::error(); // TODO(faz3+): struct alan çözümü
|
||||
Type objType = checkExpr(ma->object);
|
||||
if (objType.isStruct()) {
|
||||
result = table_.getFieldType(objType.structName, ma->member);
|
||||
if (result.isError())
|
||||
diag_.report("E001", node->loc,
|
||||
"'" + objType.structName + "' struct'ında '" + ma->member + "' alanı yok");
|
||||
} else {
|
||||
result = Type::error();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ASTKind::IndexExpression: {
|
||||
auto* ie = (IndexExpressionNode*)node;
|
||||
checkExpr(ie->object);
|
||||
Type objType = checkExpr(ie->object);
|
||||
if (ie->index) checkExpr(ie->index);
|
||||
result = Type::error(); // TODO(faz3+): array eleman tipi
|
||||
// array eleman tipi
|
||||
if (objType.isArray() && objType.elementType)
|
||||
result = *objType.elementType;
|
||||
else
|
||||
result = Type::Int(); // varsayılan (tip çıkarımı tam değil)
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,14 +77,15 @@ void SymbolCollector::pass1Globals(ASTNode* program) {
|
|||
"'" + st->name + "' zaten bu kapsamda tanımlı");
|
||||
break;
|
||||
}
|
||||
// struct alan isimlerini cycle check için kaydet
|
||||
// structFields_'e her zaman bir giriş aç (typeFromName için gerekli)
|
||||
structFields_[st->name]; // boş vektör oluşturur; by-value döngü artık referans semantiğiyle meşru (ADR-020)
|
||||
|
||||
// structLayouts: tüm alanlar (isim + tip) sırayla — IR üreteci ve tip denetleyici için
|
||||
for (ASTNode* fieldNode : st->getChildren()) {
|
||||
if (fieldNode->kind == ASTKind::VariableDecl) {
|
||||
auto* vd = (VariableDeclNode*)fieldNode;
|
||||
// yalnızca struct tipindeki alanları izle
|
||||
Type ft = Type::fromName(vd->varType);
|
||||
if (ft.isError()) // primitif değilse struct tipi olabilir
|
||||
structFields_[st->name].push_back(vd->varType);
|
||||
Type ft = typeFromName(vd->varType, vd->loc);
|
||||
table_.structLayouts[st->name].push_back({vd->name, ft});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -124,44 +125,10 @@ void SymbolCollector::pass1Globals(ASTNode* program) {
|
|||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
void SymbolCollector::checkStructCycles() {
|
||||
// white=0 / gray=1 / black=2
|
||||
std::unordered_map<std::string, int> color;
|
||||
for (auto& kv : structFields_) color[kv.first] = 0;
|
||||
|
||||
std::function<bool(const std::string&)> dfs = [&](const std::string& name) -> bool {
|
||||
auto it = color.find(name);
|
||||
if (it == color.end()) return false; // primitif / bilinmeyen → çevrim değil
|
||||
if (it->second == 1) return true; // gray → back-edge → çevrim!
|
||||
if (it->second == 2) return false; // black → zaten işlendi
|
||||
|
||||
it->second = 1; // gri yap
|
||||
auto fit = structFields_.find(name);
|
||||
if (fit != structFields_.end()) {
|
||||
for (const std::string& dep : fit->second) {
|
||||
if (dfs(dep)) return true;
|
||||
}
|
||||
}
|
||||
it->second = 2; // siyah yap
|
||||
return false;
|
||||
};
|
||||
|
||||
for (auto& kv : structFields_) {
|
||||
if (color[kv.first] == 0) {
|
||||
// DFS başlat
|
||||
color[kv.first] = 1;
|
||||
for (const std::string& dep : kv.second) {
|
||||
if (dfs(dep)) {
|
||||
// tanımlama konumunu bulmak için global scope'ta ara
|
||||
Symbol* s = table_.global()->lookupLocal(kv.first);
|
||||
SourceLocation loc = s ? s->definitionLoc : SourceLocation{};
|
||||
diag_.report("E010", loc,
|
||||
"Döngüsel struct: '" + kv.first + "' by-value sonsuz boyut oluşturur");
|
||||
break;
|
||||
}
|
||||
}
|
||||
color[kv.first] = 2;
|
||||
}
|
||||
}
|
||||
// ADR-020: Struct alanları referans semantiği taşır (Object* pointer).
|
||||
// By-value gömme yok → sonsuz-boyut döngüsü imkânsız.
|
||||
// E010 artık üretilmez; bu metot koşullu olarak devre dışı.
|
||||
// TODO(gelecek): Primitive tipler için by-value gömme eklenirse E010 geri açılır.
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "symbol/scope.hpp"
|
||||
|
||||
class SymbolTable {
|
||||
|
|
@ -50,6 +51,26 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
// Struct alan düzeni: struct adı → sıralı [(alan adı, tip)] listesi
|
||||
// Sembol toplayıcı doldurur; tip denetleyici ve IR üreteci okur.
|
||||
std::unordered_map<std::string, std::vector<std::pair<std::string, Type>>> structLayouts;
|
||||
|
||||
int getFieldIndex(const std::string& structName, const std::string& fieldName) const {
|
||||
auto it = structLayouts.find(structName);
|
||||
if (it == structLayouts.end()) return -1;
|
||||
for (int i = 0; i < (int)it->second.size(); i++)
|
||||
if (it->second[i].first == fieldName) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Type getFieldType(const std::string& structName, const std::string& fieldName) const {
|
||||
auto it = structLayouts.find(structName);
|
||||
if (it == structLayouts.end()) return Type::error();
|
||||
for (auto& p : it->second)
|
||||
if (p.first == fieldName) return p.second;
|
||||
return Type::error();
|
||||
}
|
||||
|
||||
private:
|
||||
Scope* newScope(Scope* p) {
|
||||
scopes_.push_back(std::make_unique<Scope>(p));
|
||||
|
|
|
|||
|
|
@ -193,6 +193,35 @@ int Interpreter::run() {
|
|||
continue;
|
||||
}
|
||||
|
||||
// ── Struct (ADR-020: referans semantiği) ──────────────────────────
|
||||
case Opcode::STRUCT_NEW: {
|
||||
StructObject* obj = heap_.allocStruct(instr.intValue);
|
||||
frame.slots[instr.dest] = Value::fromRef(obj);
|
||||
break;
|
||||
}
|
||||
case Opcode::FIELD_GET: {
|
||||
Value& objVal = frame.slots[instr.src];
|
||||
if (objVal.kind != ValueKind::Ref || !objVal.ref)
|
||||
throw std::runtime_error("Çalışma hatası: struct değil");
|
||||
auto* obj = (StructObject*)objVal.ref;
|
||||
int idx = instr.intValue;
|
||||
if (idx < 0 || idx >= (int)obj->fields.size())
|
||||
throw std::runtime_error("Çalışma hatası: geçersiz struct alan indeksi " + std::to_string(idx));
|
||||
frame.slots[instr.dest] = obj->fields[idx];
|
||||
break;
|
||||
}
|
||||
case Opcode::FIELD_SET: {
|
||||
Value& objVal = frame.slots[instr.dest];
|
||||
if (objVal.kind != ValueKind::Ref || !objVal.ref)
|
||||
throw std::runtime_error("Çalışma hatası: struct değil");
|
||||
auto* obj = (StructObject*)objVal.ref;
|
||||
int idx = instr.intValue;
|
||||
if (idx < 0 || idx >= (int)obj->fields.size())
|
||||
throw std::runtime_error("Çalışma hatası: geçersiz struct alan indeksi " + std::to_string(idx));
|
||||
obj->fields[idx] = frame.slots[instr.right];
|
||||
break;
|
||||
}
|
||||
|
||||
// ── Array (ADR-020: referans semantiği) ───────────────────────────
|
||||
case Opcode::ARRAY_NEW: {
|
||||
ArrayObject* arr = heap_.allocArray(instr.intValue);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// marked + next: mark-sweep için hazır; v1'de kullanılmaz.
|
||||
// TODO(#56): mark-sweep v2 — Heap::collect() bu header'ı kullanacak.
|
||||
|
||||
enum class ObjectType { Array /*, Struct, String (ileride) */ };
|
||||
enum class ObjectType { Array, Struct };
|
||||
|
||||
struct Object {
|
||||
ObjectType type;
|
||||
|
|
@ -17,7 +17,6 @@ struct Object {
|
|||
};
|
||||
|
||||
// Forward declare — Value, Object*'ı taşır; Object, Value içerir.
|
||||
// Gerçek tanım value.hpp'den sonra gelir; burada sadece forward.
|
||||
struct Value;
|
||||
|
||||
struct ArrayObject : Object {
|
||||
|
|
@ -28,6 +27,15 @@ struct ArrayObject : Object {
|
|||
}
|
||||
};
|
||||
|
||||
// ADR-020: Struct = referans semantiği. Alanlar sıra indeksiyle erişilir.
|
||||
struct StructObject : Object {
|
||||
std::vector<Value> fields;
|
||||
explicit StructObject(int fieldCount = 0) {
|
||||
type = ObjectType::Struct;
|
||||
fields.resize(fieldCount); // Value::fromInt(0) ile başlatılır (varsayılan)
|
||||
}
|
||||
};
|
||||
|
||||
// ── Heap ─────────────────────────────────────────────────────────────────────
|
||||
// Tüm nesneleri intrusive listede tutar. v1'de serbest bırakma yok.
|
||||
// TODO(#56): mark-sweep v2 — collect() kök taraması yapacak, ölü nesneleri silecek.
|
||||
|
|
@ -41,7 +49,15 @@ struct Heap {
|
|||
head = obj;
|
||||
allocCount++;
|
||||
return obj;
|
||||
// TODO(#56): mark-sweep kök taraması buradan — GC eşiği aşılınca tetikle
|
||||
}
|
||||
|
||||
StructObject* allocStruct(int fieldCount) {
|
||||
auto* obj = new StructObject(fieldCount);
|
||||
obj->next = head;
|
||||
head = obj;
|
||||
allocCount++;
|
||||
return obj;
|
||||
// TODO(#56): mark-sweep kök taraması buradan
|
||||
}
|
||||
|
||||
// v1: process exit'te OS toplar; yıkıcı tüm nesneleri siler.
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@
|
|||
struct Object;
|
||||
|
||||
// ADR-020: Primitive (int/bool) = değer; bileşik (array/struct/string) = referans.
|
||||
// ADR-021: Nil = nullable referansların null değeri (Type? için).
|
||||
// ADR-021: Null = nullable referansların null değeri (saQut'ta `null` anahtar sözcüğü).
|
||||
// Bool ayrı kind değil — boolean sonuçlar int olarak saklanır (0=yanlış, sıfır-dışı=doğru).
|
||||
// Float henüz implement edilmedi — IR'de float opcode yok.
|
||||
enum class ValueKind {
|
||||
Int,
|
||||
String,
|
||||
Ref, // ADR-020: array/struct nesnesine Object* referansı
|
||||
Nil, // ADR-021: nullable referansın null değeri
|
||||
Null, // ADR-021: nullable referansın null değeri (saQut kaynağında `null`)
|
||||
// Float, // TODO(#44)
|
||||
};
|
||||
|
||||
|
|
@ -37,17 +37,17 @@ struct Value {
|
|||
Value v; v.kind = ValueKind::Ref; v.ref = obj; return v;
|
||||
}
|
||||
|
||||
static Value nil() {
|
||||
Value v; v.kind = ValueKind::Nil; return v;
|
||||
static Value null() {
|
||||
Value v; v.kind = ValueKind::Null; return v;
|
||||
}
|
||||
|
||||
// JIF_FALSE: int 0 / boş string / nil = yanlış; Ref her zaman doğru
|
||||
// JIF_FALSE: int 0 / boş string / null = yanlış; Ref her zaman doğru
|
||||
bool isTruthy() const {
|
||||
switch (kind) {
|
||||
case ValueKind::Int: return intValue != 0;
|
||||
case ValueKind::String: return !stringValue.empty();
|
||||
case ValueKind::Ref: return ref != nullptr;
|
||||
case ValueKind::Nil: return false;
|
||||
case ValueKind::Null: return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ struct Value {
|
|||
case ValueKind::Int: return std::to_string(intValue);
|
||||
case ValueKind::String: return stringValue;
|
||||
case ValueKind::Ref: return "<array>";
|
||||
case ValueKind::Nil: return "nil";
|
||||
case ValueKind::Null: return "null";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ struct Value {
|
|||
case ValueKind::Int: return "int";
|
||||
case ValueKind::String: return "string";
|
||||
case ValueKind::Ref: return "array";
|
||||
case ValueKind::Nil: return "nil";
|
||||
case ValueKind::Null: return "null";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
10
|
||||
20
|
||||
99
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
}
|
||||
|
||||
void setX(Point p, int val) {
|
||||
p.x = val;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Point p;
|
||||
p.x = 10;
|
||||
p.y = 20;
|
||||
print(p.x);
|
||||
print(p.y);
|
||||
setX(p, 99);
|
||||
print(p.x);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue