1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 .hl.num { color:#d75f00; } .hl.esc { color:#0184bc; } .hl.sng { color:#50a14f; } .hl.pps { color:#0184bc; } .hl.slc { color:#a0a1a7; font-style:italic; } .hl.com { color:#a0a1a7; font-style:italic; } .hl.ppc { color:#986801; } .hl.opt { color:#383a42; } .hl.ipl { color:#d75f00; } .hl.lin { color:#696c77; user-select: none;-webkit-user-select: none; } .hl.hvr { cursor:help; } .hl.erm { color:#ff0000; font-weight:bold; border:solid 1px red; margin-left: 3em; } .hl.err { color:#ff0000; font-weight:bold; } .hl.kwa { color:#a626a4; font-weight:bold; } .hl.kwb { color:#4078f2; font-weight:bold; } .hl.kwc { color:#ca1243; font-weight:bold; } .hl.kwd { color:#c18401; font-weight:bold; } .hl.kwe { color:#986801; font-weight:bold; } .hl.kwf { color:#d75f00; font-weight:bold; } @media (prefers-color-scheme: dark) { .hl.num { color:#d19a66; } .hl.esc { color:#56b6c2; } .hl.sng { color:#98c379; } .hl.pps { color:#56b6c2; } .hl.slc { color:#545862; font-style:italic; } .hl.com { color:#545862; font-style:italic; } .hl.ppc { color:#be5046; } .hl.opt { color:#abb2bf; } .hl.ipl { color:#d19a66; } .hl.lin { color:#565c64; user-select: none;-webkit-user-select: none; } .hl.hvr { cursor:help; } .hl.erm { color:#ff0000; font-weight:bold; border:solid 1px red; margin-left: 3em; } .hl.err { color:#ff0000; font-weight:bold; } .hl.kwa { color:#c678dd; font-weight:bold; } .hl.kwb { color:#61afef; font-weight:bold; } .hl.kwc { color:#e06c75; font-weight:bold; } .hl.kwd { color:#e5c07b; font-weight:bold; } .hl.kwe { color:#be5046; font-weight:bold; } .hl.kwf { color:#d19a66; font-weight:bold; } } #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 (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}; }