From e2c65706e61be09ddb7eeb28cd1957acd4317bcf Mon Sep 17 00:00:00 2001 From: _ov4 Date: Fri, 16 Oct 2026 10:09:47 +0000 Subject: feat(constants): implement literal constants with lexical scope Co-Authored-By: Claude Fable 5.1 --- lib/CodeGen/ConstantGen.cc | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 lib/CodeGen/ConstantGen.cc (limited to 'lib/CodeGen/ConstantGen.cc') 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> &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(Val); + if (!Type || !Literal) { + reportError("CONSTANT initializer must be a literal"); + return; + } + Symbols[Name] = {nullptr, Type->Name, false, Literal, ConstantScopes.back().ID}; +} -- cgit v1.3.1-4-g156e