Added try/catch/finally to the parser. (0.18.0)
This commit is contained in:
parent
7842b1b909
commit
cefa1bf7e0
4 changed files with 137 additions and 1 deletions
|
|
@ -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
24
examples/try_catch_finally.fun
Executable 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")
|
||||
29
examples/try_catch_with_error.fun
Executable file
29
examples/try_catch_with_error.fun
Executable 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")
|
||||
83
src/parser.c
83
src/parser.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue