aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/cps/AST.h12
-rw-r--r--include/cps/CodeGen.h3
-rw-r--r--include/cps/ExceptionHandler.h48
-rw-r--r--include/cps/FileHandler.h7
-rw-r--r--include/cps/FunctionGen.h6
-rw-r--r--include/cps/Lexer.h7
-rw-r--r--include/cps/Parser.h1
-rw-r--r--include/cps/RuntimeCheck.h28
8 files changed, 86 insertions, 26 deletions
diff --git a/include/cps/AST.h b/include/cps/AST.h
index d98613d..e3c6bc5 100644
--- a/include/cps/AST.h
+++ b/include/cps/AST.h
@@ -93,6 +93,18 @@ public:
virtual ~StmtAST() = default;
};
+class TryStmtAST : public StmtAST {
+ std::vector<std::unique_ptr<StmtAST>> Body, CatchBody;
+public:
+ TryStmtAST(std::vector<std::unique_ptr<StmtAST>> Body,
+ std::vector<std::unique_ptr<StmtAST>> CatchBody)
+ : Body(std::move(Body)), CatchBody(std::move(CatchBody)) {}
+ const std::vector<std::unique_ptr<StmtAST>> &getBody() const { return Body; }
+ const std::vector<std::unique_ptr<StmtAST>> &getCatchBody() const { return CatchBody; }
+};
+
+class ThrowStmtAST : public StmtAST {};
+
class DeclareStmtAST : public StmtAST {
std::string Name;
std::string Type;
diff --git a/include/cps/CodeGen.h b/include/cps/CodeGen.h
index 2c837fd..acd6cb2 100644
--- a/include/cps/CodeGen.h
+++ b/include/cps/CodeGen.h
@@ -19,6 +19,7 @@ namespace cps {
class ArrayHandler;
class FileHandler;
+class ExceptionHandler;
class CodeGen {
std::unique_ptr<llvm::LLVMContext> TheContext;
@@ -28,6 +29,7 @@ class CodeGen {
std::unique_ptr<TypeSystem> Types;
std::unique_ptr<ArrayHandler> Arrays;
+ std::unique_ptr<ExceptionHandler> Exceptions;
std::unique_ptr<RuntimeCheck> RuntimeChecker;
std::unique_ptr<FunctionGen> FuncGen;
@@ -87,6 +89,7 @@ class CodeGen {
void emitOutputValue(llvm::Value *Val, const TypeInfo *TypeInfo, bool AppendNewline = true);
void emitIfStmt(IfStmtAST *Stmt);
+ void emitTryStmt(TryStmtAST *Stmt);
void emitWhileStmt(WhileStmtAST *Stmt);
void emitRepeatStmt(RepeatStmtAST *Stmt);
void emitForStmt(ForStmtAST *Stmt);
diff --git a/include/cps/ExceptionHandler.h b/include/cps/ExceptionHandler.h
new file mode 100644
index 0000000..5c846ae
--- /dev/null
+++ b/include/cps/ExceptionHandler.h
@@ -0,0 +1,48 @@
+#pragma once
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
+#include <map>
+#include <vector>
+
+namespace cps {
+
+// C++ ABI exception emission. State is keyed by function because file helper
+// bodies and user functions are emitted using the same builder as their caller.
+class ExceptionHandler {
+ struct Handler {
+ llvm::BasicBlock *Target;
+ llvm::AllocaInst *Exception;
+ unsigned CatchDepth;
+ };
+ struct FunctionState {
+ std::vector<Handler> Handlers;
+ unsigned CatchDepth = 0;
+ };
+
+ llvm::LLVMContext &Context;
+ llvm::IRBuilder<> &Builder;
+ llvm::Module &Module;
+ std::map<llvm::Function *, FunctionState> States;
+ llvm::FunctionCallee Allocate, Throw, BeginCatch, EndCatch, Personality;
+ llvm::GlobalVariable *IntTypeInfo = nullptr;
+
+ void ensureRuntime();
+ llvm::BasicBlock *emitUnwindDestination();
+
+public:
+ ExceptionHandler(llvm::LLVMContext &C, llvm::IRBuilder<> &B, llvm::Module &M)
+ : Context(C), Builder(B), Module(M) {}
+
+ void prepareFunction(llvm::Function *F);
+ void pushHandler(llvm::BasicBlock *Target);
+ llvm::AllocaInst *popHandler();
+ void beginCatch(llvm::AllocaInst *Exception);
+ void endCatch();
+ void emitReturnCleanup();
+
+ llvm::Value *emitCall(llvm::FunctionCallee Callee, llvm::ArrayRef<llvm::Value *> Args,
+ const llvm::Twine &Name = "");
+ void emitThrow();
+};
+
+} // namespace cps
diff --git a/include/cps/FileHandler.h b/include/cps/FileHandler.h
index 3898a57..8b8ddf4 100644
--- a/include/cps/FileHandler.h
+++ b/include/cps/FileHandler.h
@@ -7,6 +7,7 @@
namespace cps {
class RuntimeCheck;
+class ExceptionHandler;
// Emits the text-file runtime: a fixed-size open-file table plus internal
// __cps_file_* helper functions, synthesized once on first use so programs
@@ -20,6 +21,7 @@ class FileHandler {
llvm::IRBuilder<> &Builder;
llvm::Module &Module;
RuntimeCheck &Checker;
+ ExceptionHandler &Exceptions;
static constexpr uint64_t TableSize = 16;
bool RuntimeEmitted = false;
@@ -35,9 +37,6 @@ class FileHandler {
llvm::GlobalVariable *FileModes = nullptr; // [TableSize x i8] 0 = free slot, else FileMode
llvm::Value *ModeReadStr = nullptr, *ModeWriteStr = nullptr, *ModeAppendStr = nullptr;
- llvm::Value *ErrOpenFail = nullptr, *ErrAlreadyOpen = nullptr, *ErrTableFull = nullptr,
- *ErrNotOpen = nullptr, *ErrNotRead = nullptr, *ErrNotWrite = nullptr,
- *ErrPastEof = nullptr;
// synthesized helpers (internal linkage; pseudocode identifiers cannot
// start with '_', so these names are un-collidable)
@@ -60,7 +59,7 @@ class FileHandler {
public:
FileHandler(llvm::LLVMContext &Ctx, llvm::IRBuilder<> &B, llvm::Module &M,
- RuntimeCheck &RC);
+ RuntimeCheck &RC, ExceptionHandler &EH);
// NameStr/DataStr are already-coerced STRING ptrs; Line is the statement's
// source line for runtime diagnostics. All methods null-check and bail;
diff --git a/include/cps/FunctionGen.h b/include/cps/FunctionGen.h
index d914162..a7cead5 100644
--- a/include/cps/FunctionGen.h
+++ b/include/cps/FunctionGen.h
@@ -12,6 +12,8 @@
namespace cps {
+class ExceptionHandler;
+
// Array-parameter ABI: each rank-R array parameter is flattened into the
// data pointer followed by kBoundArgsPerDim i64 bounds per dimension.
inline constexpr unsigned kBoundArgsPerDim = 2; // lower, upper
@@ -51,6 +53,7 @@ private:
llvm::Module &Module;
llvm::IRBuilder<> &Builder;
TypeSystem &Types;
+ ExceptionHandler &Exceptions;
std::map<std::string, SymbolInfo> &Symbols;
bool &HadError;
@@ -65,9 +68,10 @@ public:
llvm::Module &M,
llvm::IRBuilder<> &B,
TypeSystem &TS,
+ ExceptionHandler &EH,
std::map<std::string, SymbolInfo> &Sym,
bool &HadErrorFlag)
- : Context(C), Module(M), Builder(B), Types(TS), Symbols(Sym), HadError(HadErrorFlag) {}
+ : Context(C), Module(M), Builder(B), Types(TS), Exceptions(EH), Symbols(Sym), HadError(HadErrorFlag) {}
llvm::Type *getLLVMType(const std::string &TypeName);
diff --git a/include/cps/Lexer.h b/include/cps/Lexer.h
index 3652df0..2876a58 100644
--- a/include/cps/Lexer.h
+++ b/include/cps/Lexer.h
@@ -88,7 +88,12 @@ enum Token {
tok_class = -604,
tok_endclass = -605,
tok_public = -606,
- tok_private = -607
+ tok_private = -607,
+
+ tok_try = -700,
+ tok_catch = -701,
+ tok_endtry = -702,
+ tok_throw = -703
};
class Lexer {
diff --git a/include/cps/Parser.h b/include/cps/Parser.h
index 7344015..49a9791 100644
--- a/include/cps/Parser.h
+++ b/include/cps/Parser.h
@@ -40,6 +40,7 @@ class Parser {
std::optional<std::vector<std::unique_ptr<ExprAST>>> ParseExprList(char CloseDelim, bool AllowEmpty);
void syncToStatementStart();
std::unique_ptr<StmtAST> ParseIfStmt();
+ std::unique_ptr<StmtAST> ParseTryStmt();
std::unique_ptr<StmtAST> ParseWhileStmt();
std::unique_ptr<StmtAST> ParseRepeatStmt();
std::unique_ptr<StmtAST> ParseForStmt();
diff --git a/include/cps/RuntimeCheck.h b/include/cps/RuntimeCheck.h
index 51a07aa..d9a69b6 100644
--- a/include/cps/RuntimeCheck.h
+++ b/include/cps/RuntimeCheck.h
@@ -7,24 +7,18 @@
namespace cps {
+class ExceptionHandler;
+
class RuntimeCheck {
- llvm::Module &TheModule;
llvm::LLVMContext &TheContext;
llvm::IRBuilder<> &Builder;
-
- llvm::FunctionCallee PrintfFunc;
- llvm::FunctionCallee ExitFunc;
- llvm::Value *DivZeroMsg;
- llvm::Value *OutOfBoundsMsg;
- llvm::Value *EnumRangeMsg;
- llvm::Value *NullDerefMsg;
- llvm::Value *ArrayArgBoundsMsg;
-
- void setupExternalFunctions();
- void emitErrorAndExit(llvm::Value *Condition, llvm::Value *Msg, int Line);
+ ExceptionHandler &Exceptions;
public:
- RuntimeCheck(llvm::Module &M, llvm::LLVMContext &C, llvm::IRBuilder<> &B);
+ RuntimeCheck(llvm::LLVMContext &C, llvm::IRBuilder<> &B, ExceptionHandler &EH);
+
+ // Split the block, throwing an anonymous exception when Condition is true.
+ void emitCheck(llvm::Value *Condition);
void emitDivZeroCheck(llvm::Value *Divisor, int Line);
void emitIndexCheck(llvm::Value *Index, llvm::Value *Lower, llvm::Value *Upper, int Line);
@@ -33,7 +27,7 @@ public:
void emitEnumRangeCheck(llvm::Value *Ordinal, uint64_t ValueCount,
const std::string &TypeName, int Line);
- // Dereferencing an unset (null) pointer dies instead of segfaulting.
+ // Dereferencing an unset (null) pointer throws instead of segfaulting.
void emitNullDerefCheck(llvm::Value *Ptr, int Line);
// A bounded array parameter is a contract: the argument's runtime bounds
@@ -41,12 +35,6 @@ public:
void emitArrayArgBoundsCheck(llvm::Value *ActualLower, llvm::Value *ActualUpper,
int64_t DeclaredLower, int64_t DeclaredUpper, int Line);
- // Runtime-computed variant: FmtArgs are the printf varargs after Msg
- // (e.g. {i32 line, ptr filename}). Needed when the failure site is inside
- // a synthesized helper function, where the line number is an argument
- // rather than a compile-time constant.
- void emitErrorAndExit(llvm::Value *Condition, llvm::Value *Msg,
- llvm::ArrayRef<llvm::Value *> FmtArgs);
};
}