aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-13 13:40:57 +0000
committer_ov4 <ov4@ov4.org>2026-10-13 13:40:57 +0000
commitf5a2541ed3faf9a942b867e2d54577352153afce (patch)
treed5f737fdb8d77dc67d46cc12f8603c7df6a168c7 /lib
parent5b08d59dba28b99cf991c02e837297fbfdb190c9 (diff)
Refactor record fields to preserve visibility and share parsing
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/Designator.cc5
-rw-r--r--lib/CodeGen/TypeSystem.cc8
-rw-r--r--lib/Parser/ParserType.cc61
3 files changed, 40 insertions, 34 deletions
diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc
index ad0cc49..640ca0b 100644
--- a/lib/CodeGen/Designator.cc
+++ b/lib/CodeGen/Designator.cc
@@ -58,10 +58,7 @@ void CodeGen::runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statem
} else if (auto *P = dynamic_cast<PointerTypeDeclAST*>(S.get())) {
Ok = Types->definePointer(P->getName(), P->getPointeeTypeName(), Err);
} else if (auto *R = dynamic_cast<RecordTypeDeclAST*>(S.get())) {
- std::vector<std::pair<std::string, std::string>> Fields;
- for (const RecordFieldDecl &F : R->getFields())
- Fields.emplace_back(F.Name, F.TypeName);
- Ok = Types->defineRecord(R->getName(), Fields, Err);
+ Ok = Types->defineRecord(R->getName(), R->getFields(), Err);
}
if (!Ok) reportError("%s", Err.c_str());
}
diff --git a/lib/CodeGen/TypeSystem.cc b/lib/CodeGen/TypeSystem.cc
index c170be8..f693ba1 100644
--- a/lib/CodeGen/TypeSystem.cc
+++ b/lib/CodeGen/TypeSystem.cc
@@ -1,4 +1,5 @@
#include "cps/TypeSystem.h"
+#include "cps/TypeAST.h"
#include "llvm/IR/Constants.h"
#include <utility>
@@ -185,7 +186,7 @@ bool TypeSystem::defineEnum(const std::string &Name,
}
bool TypeSystem::defineRecord(const std::string &Name,
- const std::vector<std::pair<std::string, std::string>> &Fields,
+ const std::vector<RecordFieldDecl> &Fields,
std::string &Err) {
auto It = Types.find(Name);
if (It == Types.end() || It->second.Kind != TypeKind::Record) {
@@ -195,7 +196,9 @@ bool TypeSystem::defineRecord(const std::string &Name,
std::vector<Type*> FieldTypes;
RecordPayload Payload;
- for (const auto &[FieldName, FieldTypeName] : Fields) {
+ for (const RecordFieldDecl &Field : Fields) {
+ const std::string &FieldName = Field.Name;
+ const std::string &FieldTypeName = Field.TypeName;
if (Payload.findField(FieldName)) {
Err = "Duplicate field '" + FieldName + "' in record " + Name;
return false;
@@ -222,6 +225,7 @@ bool TypeSystem::defineRecord(const std::string &Name,
RecordFieldInfo FI;
FI.TypeName = FieldInfo->Name;
FI.Index = static_cast<unsigned>(FieldTypes.size());
+ FI.IsPublic = Field.IsPublic;
Payload.Fields.emplace_back(FieldName, FI);
FieldTypes.push_back(FieldInfo->LLVMType);
}
diff --git a/lib/Parser/ParserType.cc b/lib/Parser/ParserType.cc
index 8be7e46..ae671d5 100644
--- a/lib/Parser/ParserType.cc
+++ b/lib/Parser/ParserType.cc
@@ -66,30 +66,9 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() {
return nullptr;
}
} else {
- // Record body: DECLARE-only lines, so nothing here can leak into the
- // statement chain. One bad field yields one diagnostic; parsing then
- // resumes at the next field or ENDTYPE.
- std::vector<RecordFieldDecl> Fields;
- bool HadFieldError = false;
- while (CurTok == tok_declare) {
- if (!ParseRecordField(Fields)) {
- HadFieldError = true;
- while (CurTok != tok_declare && CurTok != tok_endtype && CurTok != tok_eof)
- getNextToken();
- }
- }
- if (CurTok != tok_endtype) {
- fprintf(stderr, "error: Expected DECLARE or ENDTYPE in TYPE %s at line %d\n",
- Name.c_str(), Lex.getLine());
- return nullptr; // token left for the outer recovery
- }
- getNextToken(); // eat ENDTYPE
- if (Fields.empty()) {
- fprintf(stderr, "error: Record TYPE %s has no fields at line %d\n", Name.c_str(), Line);
- return nullptr;
- }
- if (HadFieldError) return nullptr;
- Decl = std::make_unique<RecordTypeDeclAST>(Name, std::move(Fields));
+ auto Fields = ParseRecordBody(Name, Line, tok_endtype);
+ if (!Fields) return nullptr;
+ Decl = std::make_unique<RecordTypeDeclAST>(Name, std::move(*Fields));
}
if (!AtTopLevel) {
@@ -99,9 +78,35 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() {
return Decl;
}
-// DECLARE <field> : <type> — one record field. Array fields are deferred.
-bool Parser::ParseRecordField(std::vector<RecordFieldDecl> &Out) {
- getNextToken(); // eat DECLARE
+// Shared record body and field parsing. Fields are data, never statements.
+std::optional<std::vector<RecordFieldDecl>> Parser::ParseRecordBody(
+ const std::string &Name, int Line, int EndToken) {
+ std::vector<RecordFieldDecl> Fields;
+ bool HadFieldError = false;
+ while (CurTok == tok_declare) {
+ if (!ParseRecordField(Fields, true)) {
+ HadFieldError = true;
+ while (CurTok != tok_declare && CurTok != EndToken && CurTok != tok_eof)
+ getNextToken();
+ }
+ }
+ if (CurTok != EndToken) {
+ fprintf(stderr, "error: Expected DECLARE or ENDTYPE in TYPE %s at line %d\n",
+ Name.c_str(), Lex.getLine());
+ return std::nullopt;
+ }
+ getNextToken(); // eat body terminator
+ if (Fields.empty()) {
+ fprintf(stderr, "error: Record TYPE %s has no fields at line %d\n", Name.c_str(), Line);
+ return std::nullopt;
+ }
+ if (HadFieldError) return std::nullopt;
+ return Fields;
+}
+
+// <field introducer> <field> : <type>. Array fields are deferred.
+bool Parser::ParseRecordField(std::vector<RecordFieldDecl> &Out, bool IsPublic) {
+ getNextToken(); // eat field introducer
if (CurTok != tok_identifier) {
fprintf(stderr, "error: Expected field name after DECLARE at line %d\n", Lex.getLine());
return false;
@@ -125,6 +130,6 @@ bool Parser::ParseRecordField(std::vector<RecordFieldDecl> &Out) {
std::string TypeName = ParseTypeName(false);
if (TypeName.empty()) return false;
- Out.push_back({FieldName, TypeName});
+ Out.push_back({FieldName, TypeName, IsPublic});
return true;
}