aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CodeGen.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-07-26 17:36:41 +0000
committer_ov4 <ov4@ov4.org>2026-07-26 17:36:41 +0000
commitd65c296a0ad8d335aa076aab48a8b198fa934a2d (patch)
tree80592a0faec64482a7a81d6af4836e52b4fd33ce /lib/CodeGen/CodeGen.cc
parentf19f1c956780f41f1440b372187770ce0be8efed (diff)
feat: records with designator lvalues, and pointer types (CIE 4.1/4.2)
- New CodeGen::emitLValue resolves any designator — variable, checked array element, record field chain (CreateStructGEP via the record payload), pointer deref (with the null-pointer [Fatal] check) — to an address + type name; loadFromLValue centralizes the rvalue read and the STRING null->"" guard, so zero-initialized STRING fields read as "". - Designator assignment stores through emitLValue + emitCoercedExpr; whole-record copies (r2 <- r1, array elements, BYVAL args, RETURN) are aggregate loads/stores with name-checked admission. - getExprTypeInfo walks designator chains statically (field types from the record payload, deref to the pointee), so records/pointers type correctly in every expression context. - Address-of ^x admits into a pointer target only when the designator's type name equals the declared pointee exactly (nominal, strict: the guide's own ^INTEGER-at-a-Season example is a compile error by design); ^arr[i] and ^rec.field work through the same lvalue path. - Verified: the guide's §4.2 StudentRecord example (minus DATE), nested records, arrays of records with Form[i].YearGroup writes, record BYREF/BYVAL params, NodePtr = ^Node forward reference with writes through n1.Next^.Data, unset-pointer deref dying with [Fatal]. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/CodeGen.cc')
-rw-r--r--lib/CodeGen/CodeGen.cc60
1 files changed, 53 insertions, 7 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index ae8efa2..62a6f1e 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -186,6 +186,41 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const {
return Info ? resolveType(Info->TypeName) : nullptr;
}
+ if (auto *D = dynamic_cast<DesignatorExprAST*>(Expr)) {
+ const SymbolInfo *Info = getSymbolInfo(D->getBaseName());
+ if (!Info) return nullptr;
+ std::string TypeName = Info->TypeName;
+ size_t Start = 0;
+ if (Info->IsArray) {
+ // SymbolInfo already holds the ELEMENT type name for arrays.
+ if (D->getAccesses().empty() || D->getAccesses()[0].Kind != AccessKind::Index)
+ return nullptr;
+ Start = 1;
+ }
+ for (size_t I = Start; I < D->getAccesses().size(); ++I) {
+ const TypeInfo *Cur = resolveType(TypeName);
+ if (!Cur) return nullptr;
+ const DesignatorAccess &A = D->getAccesses()[I];
+ if (A.Kind == AccessKind::Field) {
+ const RecordPayload *RP = Cur->asRecord();
+ const RecordFieldInfo *FI = RP ? RP->findField(A.FieldName) : nullptr;
+ if (!FI) return nullptr;
+ TypeName = FI->TypeName;
+ } else if (A.Kind == AccessKind::Deref) {
+ const PointerPayload *PP = Cur->asPointer();
+ if (!PP) return nullptr;
+ TypeName = PP->PointeeTypeName;
+ } else {
+ return nullptr; // indexing a non-array
+ }
+ }
+ return resolveType(TypeName);
+ }
+
+ // ^x has no pseudocode type of its own; only the pointer admission in
+ // emitCoercedExpr may consume it.
+ if (dynamic_cast<AddrOfExprAST*>(Expr)) return nullptr;
+
if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
if (Unary->getOp() == tok_not) {
return resolveType("BOOLEAN");
@@ -683,10 +718,18 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
return FuncGen->emitCallExpr(Call, Args);
}
- // TYPE-system stubs: parsed but not yet wired (phases C/D/E of the TYPE work).
- if (dynamic_cast<DesignatorExprAST*>(Expr) || dynamic_cast<AddrOfExprAST*>(Expr)) {
- reportError("Record field / pointer expressions are not implemented yet");
- return nullptr;
+ if (auto *D = dynamic_cast<DesignatorExprAST*>(Expr)) {
+ LValueInfo LV;
+ if (!emitLValue(D, LV)) return nullptr;
+ return loadFromLValue(LV);
+ }
+
+ // ^x produces a raw address; it is only admissible where a pointer type
+ // is expected, which emitCoercedExpr enforces by pointee name.
+ if (auto *Addr = dynamic_cast<AddrOfExprAST*>(Expr)) {
+ LValueInfo LV;
+ if (!emitLValue(Addr->getTarget(), LV)) return nullptr;
+ return LV.Addr;
}
return nullptr;
@@ -1115,9 +1158,12 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
dynamic_cast<RecordTypeDeclAST*>(Stmt)) {
return;
}
- // TYPE-system stub: wired in the record/lvalue phase.
- if (dynamic_cast<DesignatorAssignStmtAST*>(Stmt)) {
- reportError("Assignment to record fields / pointer targets is not implemented yet");
+ if (auto *DA = dynamic_cast<DesignatorAssignStmtAST*>(Stmt)) {
+ LValueInfo LV;
+ if (!emitLValue(DA->getTarget(), LV)) return;
+ Value *Val = emitCoercedExpr(DA->getExpr(), resolveType(LV.TypeName));
+ if (!Val) return;
+ Builder->CreateStore(Val, LV.Addr);
return;
}
}