diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-13 14:52:57 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-13 14:52:57 +0000 |
| commit | a484f314b719aec5ed7bdc6f08403342b2125561 (patch) | |
| tree | 531e331cf823517eae4c350d37bca6a500b2de9f /lib/Parser | |
| parent | 4297086c86f4d11e8a14b76b50705b419d6b7f13 (diff) | |
feat(compiler)!: add try-catch with C++ stack unwinding
Add TRY/CATCH/ENDTRY and anonymous THROW statements. Use LLVM exception
handling and the C++ ABI to propagate exceptions across function calls,
clean up catch state, and handle uncaught exceptions at the program boundary.
Register exception runtime symbols for the statically linked embedded runner.
Verify runtime checks, nested catches, returns, loops, and invalid syntax
with smoke programs; exercise unwinding with MCJIT, lli, and native binaries.
BREAKING CHANGE: Runtime check failures now throw anonymous exceptions and
print only a generic message when uncaught. Native binaries require linking
the C++ runtime.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib/Parser')
| -rw-r--r-- | lib/Parser/Parser.cc | 31 | ||||
| -rw-r--r-- | lib/Parser/ParserFunction.cc | 3 |
2 files changed, 33 insertions, 1 deletions
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc index 098ef82..aeb81fe 100644 --- a/lib/Parser/Parser.cc +++ b/lib/Parser/Parser.cc @@ -276,6 +276,7 @@ void Parser::syncToStatementStart() { case tok_openfile: case tok_readfile: case tok_writefile: case tok_closefile: case tok_type: case tok_define: case tok_endtype: case tok_class: case tok_endclass: + case tok_try: case tok_catch: case tok_endtry: case tok_throw: return; default: getNextToken(); @@ -399,6 +400,23 @@ std::unique_ptr<StmtAST> Parser::ParseDeclare() { } } +std::unique_ptr<StmtAST> Parser::ParseTryStmt() { + getNextToken(); + auto Body = ParseBlock({tok_catch, tok_endtry}); + if (CurTok != tok_catch) { + fprintf(stderr, "error: Expected CATCH in TRY at line %d\n", Lex.getLine()); + return nullptr; + } + getNextToken(); + auto CatchBody = ParseBlock({tok_endtry, tok_catch}); + if (CurTok != tok_endtry) { + fprintf(stderr, "error: Expected ENDTRY after CATCH at line %d\n", Lex.getLine()); + return nullptr; + } + getNextToken(); + return std::make_unique<TryStmtAST>(std::move(Body), std::move(CatchBody)); +} + std::unique_ptr<StmtAST> Parser::ParseIfStmt() { getNextToken(); auto Cond = ParseExpression(); @@ -569,6 +587,19 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { else if (CurTok == tok_if) { return ParseIfStmt(); } + else if (CurTok == tok_try) { + return ParseTryStmt(); + } + else if (CurTok == tok_throw) { + getNextToken(); + return std::make_unique<ThrowStmtAST>(); + } + else if (CurTok == tok_catch || CurTok == tok_endtry) { + fprintf(stderr, "error: Unexpected %s without matching TRY at line %d\n", + CurTok == tok_catch ? "CATCH" : "ENDTRY", Lex.getLine()); + getNextToken(); + return nullptr; + } else if (CurTok == tok_while) { return ParseWhileStmt(); } diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc index f4e39de..25375f2 100644 --- a/lib/Parser/ParserFunction.cc +++ b/lib/Parser/ParserFunction.cc @@ -224,7 +224,8 @@ std::unique_ptr<StmtAST> Parser::ParseReturnStmt() { // A bare RETURN is recognized right before any block terminator. if (CurTok != tok_endif && CurTok != tok_else && CurTok != tok_endfunction && CurTok != tok_endprocedure && CurTok != tok_endwhile && CurTok != tok_until && - CurTok != tok_next && CurTok != tok_eof) { + CurTok != tok_next && CurTok != tok_catch && CurTok != tok_endtry && + CurTok != tok_eof) { Expr = ParseExpression(); if (!Expr) return nullptr; } |
