1
0
Fork 0
forked from fun/fun

Added try/catch/finally to the parser. (0.18.0)

This commit is contained in:
Johannes Findeisen 2025-10-03 23:25:55 +02:00
commit cefa1bf7e0
4 changed files with 137 additions and 1 deletions

View file

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project(fun VERSION 0.17.10 LANGUAGES C)
project(fun VERSION 0.18.0 LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

24
examples/try_catch_finally.fun Executable file
View file

@ -0,0 +1,24 @@
/*
* This file is part of the Fun programming language.
* https://hanez.org/project/fun/
*
* Copyright 2025 Johannes Findeisen <you@hanez.org>
* Licensed under the terms of the Apache-2.0 license.
* https://opensource.org/license/apache-2-0
*
* Added: 2025-10-03
*/
// Demonstration of try/catch/finally syntax support
// Note: current runtime does not yet implement exceptions; catch blocks are not executed.
print("before try")
try
print("inside try body")
catch err
// This will not run yet (no exception raised, and runtime doesn't support throwing)
print("caught error: ")
print(err)
finally
print("finally always runs (syntactically)")
print("after try")

View file

@ -0,0 +1,29 @@
/*
* This file is part of the Fun programming language.
* https://hanez.org/project/fun/
*
* Copyright 2025 Johannes Findeisen <you@hanez.org>
* Licensed under the terms of the Apache-2.0 license.
* https://opensource.org/license/apache-2-0
*
* Added: 2025-10-03
*/
// Example: try/catch/finally with an intentional runtime error
// Note: The current runtime does not implement exceptions yet, so the catch
// block will not execute today. This example is prepared for when exceptions
// are supported. It also demonstrates the location of the error inside try.
print("before try")
try
print("inside try: about to divide by zero")
number x = 1 / 0 // deliberate runtime error
print("this will not be reached due to the error above")
catch err
// Intended behavior (once exceptions are wired up): this block runs
// and 'err' contains an error object/stack trace
print("caught error: ")
print(err)
finally
print("finally runs regardless (syntactically, even without exceptions)")
print("after try")

View file

@ -3626,6 +3626,89 @@ static void parse_block(Bytecode *bc, const char *src, size_t len, size_t *pos,
continue;
}
/* try/catch/finally (syntax support; runtime exceptions not yet implemented) */
if (starts_with(src, len, *pos, "try")) {
/* consume 'try' */
*pos += 3;
/* end of header line */
skip_to_eol(src, len, pos);
/* parse try body at increased indent (if any) */
int try_body_indent = 0;
size_t look_try = *pos;
if (read_line_start(src, len, &look_try, &try_body_indent) && try_body_indent > current_indent) {
parse_block(bc, src, len, pos, try_body_indent);
} else {
/* empty try body allowed */
}
/* Optional: catch and/or finally clauses at same indentation */
int seen_catch = 0;
int seen_finally = 0;
for (;;) {
size_t look = *pos;
int look_indent = 0;
if (!read_line_start(src, len, &look, &look_indent)) break; /* EOF */
if (look_indent != current_indent) break; /* different indentation -> stop */
if (!seen_catch && starts_with(src, len, look, "catch")) {
/* consume 'catch' */
*pos = look + 5;
/* optional variable name */
skip_spaces(src, len, pos);
char *ex_name = NULL;
size_t tmp = *pos;
if (read_identifier_into(src, len, &tmp, &ex_name)) {
*pos = tmp;
free(ex_name);
}
/* end of header line */
skip_to_eol(src, len, pos);
/* We currently don't have runtime exceptions: emit an unconditional jump over the catch body (so it's parsed but never executed) */
int j_over = bytecode_add_instruction(bc, OP_JUMP, 0);
/* parse catch body at increased indent (if any) */
int catch_indent = 0;
size_t look_catch = *pos;
if (read_line_start(src, len, &look_catch, &catch_indent) && catch_indent > current_indent) {
parse_block(bc, src, len, pos, catch_indent);
} else {
/* empty catch body allowed */
}
/* patch jump to here (after catch body) */
bytecode_set_operand(bc, j_over, bc->instr_count);
seen_catch = 1;
continue;
}
if (!seen_finally && starts_with(src, len, look, "finally")) {
/* consume 'finally' */
*pos = look + 7;
/* end of header line */
skip_to_eol(src, len, pos);
/* parse finally body at increased indent (if any) */
int finally_indent = 0;
size_t look_fin = *pos;
if (read_line_start(src, len, &look_fin, &finally_indent) && finally_indent > current_indent) {
parse_block(bc, src, len, pos, finally_indent);
} else {
/* empty finally body allowed */
}
seen_finally = 1;
continue;
}
/* no recognized clause at this indentation */
break;
}
continue;
}
/* otherwise: simple statement on this line */
parse_simple_statement(bc, src, len, pos);
}