Skip to content

Commit 5bbbf69

Browse files
gh-52: TRY catches ParseError.
1 parent 1ebb84e commit 5bbbf69

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

src/parser.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,21 @@
44
#include <string.h>
55
#include <stdlib.h>
66

7+
#ifdef _MSC_VER
8+
#define strdup _strdup
9+
#endif
10+
711
static void report_error(Parser* parser, const char* message) {
812
if (parser->panic_mode) return;
913
parser->panic_mode = true;
1014
parser->had_error = true;
15+
/* Record last error for possible conversion into a runtime THROW
16+
so TRY/CATCH can handle parse-time errors that occur inside
17+
parsed blocks. Also emit the usual diagnostic to stderr. */
18+
if (parser->error_msg) { free(parser->error_msg); parser->error_msg = NULL; }
19+
parser->error_msg = strdup(message);
20+
parser->error_line = parser->current_token.line;
21+
parser->error_col = parser->current_token.column;
1122
fprintf(stderr, "ParseError at %d:%d: %s\n",
1223
parser->current_token.line, parser->current_token.column, message);
1324
}
@@ -16,6 +27,9 @@ void parser_init(Parser* parser, Lexer* lexer) {
1627
parser->lexer = lexer;
1728
parser->panic_mode = false;
1829
parser->had_error = false;
30+
parser->error_msg = NULL;
31+
parser->error_line = 0;
32+
parser->error_col = 0;
1933
parser->current_token = lexer_next_token(parser->lexer);
2034
parser->next_token = lexer_next_token(parser->lexer);
2135
}
@@ -784,9 +798,28 @@ Stmt* parser_parse(Parser* parser) {
784798
continue;
785799
}
786800

801+
/* If a parse error was recorded, synthesize a runtime THROW call
802+
statement so that runtime TRY/CATCH can observe the parse error
803+
as a catchable runtime exception. Then clear the parser error
804+
state so callers (e.g. RUN/IMPORT) don't treat it as a fatal
805+
top-level parse failure. */
806+
if (parser->error_msg) {
807+
char* msg_dup = strdup(parser->error_msg);
808+
Expr* callee = expr_ident(strdup("THROW"), parser->error_line, parser->error_col);
809+
Expr* call = expr_call(callee, parser->error_line, parser->error_col);
810+
Expr* arg = expr_str(msg_dup, parser->error_line, parser->error_col);
811+
expr_list_add(&call->as.call.args, arg);
812+
Stmt* err_stmt = stmt_expr(call, parser->error_line, parser->error_col);
813+
stmt_list_add(&program->as.block, err_stmt);
814+
free(parser->error_msg);
815+
parser->error_msg = NULL;
816+
parser->had_error = false;
817+
parser->panic_mode = false;
818+
}
819+
787820
/* Synchronize after an error: advance to next newline or EOF so the
788821
parser makes progress instead of repeatedly returning NULL and
789-
hanging. Clear panic mode to allow further error reports. */
822+
hanging. */
790823
while (parser->current_token.type != TOKEN_EOF && parser->current_token.type != TOKEN_NEWLINE) {
791824
advance(parser);
792825
}

src/parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ typedef struct {
1212
Token next_token;
1313
bool panic_mode;
1414
bool had_error;
15+
char* error_msg;
16+
int error_line;
17+
int error_col;
1518
} Parser;
1619

1720
void parser_init(Parser* parser, Lexer* lexer);

tests/test2.pre

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ DEL(i0)
1414
DEL(i1)
1515
DEL(i5)
1616
DEL(i_neg)
17+
INT: err = 0
18+
TRY{
19+
nonex.foo = 1 ! should raise an error
20+
err = 1
21+
} CATCH {}
22+
ASSERT(NOT(err))
1723
PRINT("Literals: PASS\n")
1824

1925
! Floating-point binary fixed-point forms

0 commit comments

Comments
 (0)