ox

The Ox programming language, compiler and tools (WIP)
Log | Files | Refs | README | LICENSE

commit 2fba18d005233ab3a053baf6a8da086a27c40f87
parent ecc6a44d87f87542ed5b3da1fb88fad2e32132b6
Author: citbl <citbl@citbl.org>
Date:   Thu, 23 Oct 2025 21:18:09 +1000

if condition handling

Diffstat:
Aex-cond-adv1.ox | 17+++++++++++++++++
Aex-cond-simple1.ox | 8++++++++
Aex-cond-simple2.ox | 10++++++++++
Mex1.ox | 4++--
Dex3.ox | 15---------------
Dex4.ox | 7-------
Dex5.ox | 9---------
Mex8.ox | 2+-
Mmakefile | 7++++++-
Msrc/gen.h | 1-
Msrc/gen/gen.c | 92++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/parser/parser.c | 2+-
12 files changed, 94 insertions(+), 80 deletions(-)

diff --git a/ex-cond-adv1.ox b/ex-cond-adv1.ox @@ -0,0 +1,17 @@ +// conditional to be handled + +int main() { + print("did it work?"); + string password = "123"; + if (password == "1234") { + print("it worked!"); + return 0; + } else { + if(password == "123") { + print("the else worked!"); + return 1; + } else { + print("booboo"); + } + } +} diff --git a/ex-cond-simple1.ox b/ex-cond-simple1.ox @@ -0,0 +1,8 @@ +void main() { + int a = 1; + if (a == 1) { + print("yes is expected"); + } else { + print("no"); + } +} diff --git a/ex-cond-simple2.ox b/ex-cond-simple2.ox @@ -0,0 +1,10 @@ +// more conditional test, else case should be taken + +void main() { + int a = 1; + if (a == 2) { + print("no"); + } else { + print("yes"); + } +} diff --git a/ex1.ox b/ex1.ox @@ -1,6 +1,6 @@ // Hello world and comment -void main(int param1) { - print("hello world\n"); +void main(int var) { + print("hello world"); //print(param1); } diff --git a/ex3.ox b/ex3.ox @@ -1,15 +0,0 @@ -// conditional to be handled - -void main() { - print("did it work?"); - string password = "123"; - if (password == "1234") { - print("it worked!"); - } else { - if(password == "123") { - print("the else worked!"); - } else { - print("booboo"); - } - } -} diff --git a/ex4.ox b/ex4.ox @@ -1,7 +0,0 @@ -void main() { - if (a == true) { - print("yes is expected"); - } else { - print("no"); - } -} diff --git a/ex5.ox b/ex5.ox @@ -1,9 +0,0 @@ -// more conditional test, else case should be taken - -void main() { - if (a == false) { - print("yes"); - } else { - print("no"); - } -} diff --git a/ex8.ox b/ex8.ox @@ -2,7 +2,7 @@ void main() { int a = 10; - if(true == true) { + if(1 == 1) { if(a == 11) { print("this is wrong"); } else { diff --git a/makefile b/makefile @@ -27,6 +27,11 @@ debug: default: cc ${STD} -g -Wall -Wextra -Wno-unused-parameter -Wno-unused-function -fsanitize=address,undefined -o ${BIN} ${SRC} ${LIB} # -Wpedantic -Wshadow -Wconversion +fast: + cc ${STD} -O3 -ffast-math -DNDEBUG -march=native -mtune=native -flto -fomit-frame-pointer -fno-plt -fno-semantic-interposition -pipe \ + -fno-trapping-math -Wl,-O3 ${LDFLAGS} -o ${BIN} ${SRC} ${LIB} + strip ${BIN} + clean: rm -rf ${BIN} ${BIN}.* err.log @@ -36,7 +41,7 @@ release: clean check: clean cc ${STD} -g -Wall -Wextra -fsanitize=address -fsanitize=undefined -o ${BIN} ${SRC} ${LIB} -test: clean default +test: clean fast @for f in ex*.ox; do \ ./${BIN} --quiet $$f > /dev/null 2>err.log || { echo "FAIL: $$f"; cat err.log; exit 1; }; \ echo $$f; \ diff --git a/src/gen.h b/src/gen.h @@ -16,7 +16,6 @@ typedef struct { // gcc_jit_type *type_kind; need type too? Scope* scope; const char* src; - bool block_terminated; } Gen; Gen gen_init(Scope*, const char*, Node*, bool); diff --git a/src/gen/gen.c b/src/gen/gen.c @@ -299,28 +299,23 @@ add_symbol(Gen* gen, Symbol* sym) gen->scope->symbols[gen->scope->len++] = sym; } -static void -end_jump_if_needed(Gen* gen, gcc_jit_location* loc, gcc_jit_block* target) -{ - if (!gen->block_terminated && gen->curr_block) { - gcc_jit_block_end_with_jump(gen->curr_block, loc, target); - gen->block_terminated = true; - } -} - -static void build_block(Gen* gen, Node* body); +static bool build_block(Gen* gen, Node* body); static int block_counter = 0; -static void +static bool build_statement(Gen* gen, Node* node) { + gcc_jit_location* loc = loc_from_node(gen, node); switch (node->type) { case NODE_BLOCK: break; - case NODE_RETURN: - break; // TODO return from function probably only handled at the end of the gen + case NODE_RETURN: { + gcc_jit_rvalue* rv = handle_expr(gen, node->data.ret.expr); + gcc_jit_block_end_with_return(gen->curr_block, loc, rv); + gen->curr_block = NULL; // important + return true; // we end the block here + } case NODE_VAR_DECL: { - gcc_jit_location* loc = loc_from_node(gen, node); const char* var_name = span_str(gen->src, node->data.var_decl.name, (char[IDENTSZ]) { 0 }); gcc_jit_type* declared_type = ox_type_to_c_type(gen, node->data.var_decl.type); @@ -348,7 +343,6 @@ build_statement(Gen* gen, Node* node) break; } case NODE_VAR_ASSIGN: { - gcc_jit_location* loc = loc_from_node(gen, node); gcc_jit_rvalue* rvalue = handle_expr(gen, node->data.var_assign.rhs); // find the var_decl (d.lvalue) from the symbols table's symbol. for (size_t i = 0; i < gen->scope->len; i++) { @@ -372,8 +366,6 @@ build_statement(Gen* gen, Node* node) break; } case NODE_IF: { - gcc_jit_location* loc = loc_from_node(gen, node); - // build the condition OpType op = node->data.if_statement.cond->data.binary_expr.op; @@ -398,7 +390,6 @@ build_statement(Gen* gen, Node* node) gcc_jit_rvalue* lhs_val = handle_expr(gen, lhs); gcc_jit_rvalue* rhs_val = handle_expr(gen, rhs); - gcc_jit_rvalue* cond = gcc_jit_context_new_comparison(gen->ctx, loc, cmp, lhs_val, rhs_val); // create the BLOCKS @@ -411,47 +402,62 @@ build_statement(Gen* gen, Node* node) snprintf(label_end, 64, "if.end%d", block_counter); // blocks - gcc_jit_block* then_block = gcc_jit_function_new_block(gen->curr_func, label_then); - gcc_jit_block* merge_block = gcc_jit_function_new_block(gen->curr_func, label_else); - gcc_jit_block* else_block = else_body ? gcc_jit_function_new_block(gen->curr_func, label_else) : NULL; - - // rig the jumps - - gcc_jit_block_end_with_conditional(gen->curr_block, loc, cond, then_block, else_body ? else_block : merge_block); + gcc_jit_block* then_bb = gcc_jit_function_new_block(gen->curr_func, label_then); + gcc_jit_block* else_bb = else_body ? gcc_jit_function_new_block(gen->curr_func, label_else) : NULL; + gcc_jit_block* merge_bb = NULL; + + if (!else_bb) { + // no else: need merge now for the false edge + merge_bb = gcc_jit_function_new_block(gen->curr_func, label_end); + gcc_jit_block_end_with_conditional(gen->curr_block, loc, cond, then_bb, merge_bb); + } else { + // with else: branch to then/else; decide on merge later + gcc_jit_block_end_with_conditional(gen->curr_block, loc, cond, then_bb, else_bb); + } - // build THEN + // THEN + gen->curr_block = then_bb; + bool then_ended = build_block(gen, then_body); + gcc_jit_block* then_open = gen->curr_block; // last open block in THEN (may differ from then_bb) + + // ELSE + bool else_ended = false; + gcc_jit_block* else_open = NULL; + if (else_bb) { + gen->curr_block = else_bb; + else_ended = build_block(gen, else_body); + else_open = gen->curr_block; // last open block in ELSE + } - gen->curr_block = then_block; - gen->block_terminated = false; - build_block(gen, then_body); - end_jump_if_needed(gen, loc, merge_block); + // If both branches ended, no merge needed, we notify we have ended as well + if (else_bb && then_ended && else_ended) return true; - // build ELSE block (optional) - if (else_block != NULL) { - gen->curr_block = else_block; - gen->block_terminated = false; - build_block(gen, else_body); - end_jump_if_needed(gen, loc, merge_block); - } + // Ensure we have a merge if any branch continues. + if (!merge_bb) merge_bb = gcc_jit_function_new_block(gen->curr_func, label_end); - // continue after if, note that the original block is terminated. - gen->curr_block = merge_block; - gen->block_terminated = false; + if (!then_ended) gcc_jit_block_end_with_jump(then_open, loc, merge_bb); + if (else_bb && !else_ended) gcc_jit_block_end_with_jump(else_open, loc, merge_bb); - break; + gen->curr_block = merge_bb; + return false; } default: printf("build_statement unhandled, %s\n", node_type_str(node->type)); break; } + return false; } -static void +// build_block: returns true if block ended with a terminator +static bool build_block(Gen* gen, Node* body) { for (size_t i = 0; i < body->data.block.len; i++) { - build_statement(gen, body->data.block.stmts[i]); + if (gen->curr_block == NULL) return true; + bool ended = build_statement(gen, body->data.block.stmts[i]); + if (ended) return true; } + return false; } static void diff --git a/src/parser/parser.c b/src/parser/parser.c @@ -165,7 +165,7 @@ parse_equality(Parser* par) Node* rhs = parse_relational(par); node = make_binary_node(OP_INEQUALITY, node, rhs); } else { - perror("unhandled parse_equality token"); + // do not error out for other things like `=`, `&`, etc. let it pass. break; } }