aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/ConstantGen.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-16 10:09:47 +0000
committer_ov4 <ov4@ov4.org>2026-10-16 10:09:47 +0000
commite2c65706e61be09ddb7eeb28cd1957acd4317bcf (patch)
tree15447a03d67d395a722c5be3f0b05bc9f197197a /lib/CodeGen/ConstantGen.cc
parent45c9d37eb27d204a6202b33cb37e890af0171357 (diff)
feat(constants): implement literal constants with lexical scope
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/ConstantGen.cc')
-rw-r--r--lib/CodeGen/ConstantGen.cc59
1 files changed, 59 insertions, 0 deletions
diff --git a/lib/CodeGen/ConstantGen.cc b/lib/CodeGen/ConstantGen.cc
new file mode 100644
index 0000000..e9f81ae
--- /dev/null
+++ b/lib/CodeGen/ConstantGen.cc
@@ -0,0 +1,59 @@
+#include "cps/CodeGen.h"
+
+using namespace llvm;
+using namespace cps;
+
+// Only bindings introduced by constants or hiding constants are restored.
+// Ordinary variables keep the compiler's existing function-wide visibility.
+void CodeGen::emitScopedBlock(const std::vector<std::unique_ptr<StmtAST>> &Body) {
+ ConstantScopes.push_back({NextScopeID++, {}});
+ for (const auto &S : Body) emitStmt(S.get());
+ for (const auto &[Name, Previous] : ConstantScopes.back().Saved) {
+ if (Previous) Symbols[Name] = *Previous;
+ else Symbols.erase(Name);
+ }
+ ConstantScopes.pop_back();
+}
+
+bool CodeGen::prepareSymbolDeclaration(const std::string &Name, bool IsConstant) {
+ auto &Scope = ConstantScopes.back();
+ auto It = Symbols.find(Name);
+ if (It != Symbols.end()) {
+ if ((IsConstant || It->second.ConstantValue) && It->second.ScopeID == Scope.ID) {
+ reportError("Declaration of %s conflicts with an existing declaration in this scope", Name.c_str());
+ return false;
+ }
+ if (IsConstant || It->second.ConstantValue) Scope.Saved.emplace(Name, It->second);
+ } else if (IsConstant) {
+ Scope.Saved.emplace(Name, std::nullopt);
+ }
+ return true;
+}
+
+bool CodeGen::requireWritable(const SymbolInfo &Info, const std::string &Name) {
+ if (!Info.ConstantValue) return true;
+ reportError("Constant %s is not a writable location", Name.c_str());
+ return false;
+}
+
+void CodeGen::emitConstantStmt(ConstantStmtAST *Stmt) {
+ const std::string &Name = Stmt->getName();
+ if (Types->lookupEnumConstant(Name) || Types->resolve(Name)) {
+ reportError("Constant %s conflicts with an enum value or type name", Name.c_str());
+ return;
+ }
+ if (ConstantScopes.back().ID == 0 &&
+ (FuncGen->getSignature(Name) || isBuiltinName(Name))) {
+ reportError("Constant %s conflicts with a function name", Name.c_str());
+ return;
+ }
+ if (!prepareSymbolDeclaration(Name, true)) return;
+ const TypeInfo *Type = getExprTypeInfo(Stmt->getValue());
+ Value *Val = emitExpr(Stmt->getValue());
+ auto *Literal = dyn_cast_or_null<Constant>(Val);
+ if (!Type || !Literal) {
+ reportError("CONSTANT initializer must be a literal");
+ return;
+ }
+ Symbols[Name] = {nullptr, Type->Name, false, Literal, ConstantScopes.back().ID};
+}