ox

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

commit 61c13e81caf86e7a92f5bbd3eb7819ec4a565566
parent 52d5fb89bc8d20bdc529ed2c8cd34f19bc11e95d
Author: citbl <citbl@citbl.org>
Date:   Mon, 27 Oct 2025 21:05:11 +1000

wip for loop, array subscript done

Diffstat:
M.clang-format | 2+-
M.zed/debug.json | 4++--
AREADME | 17+++++++++++++++++
DREADME.md | 3---
MTODO | 1+
Aex-decl-no-init.ox | 3+++
Mex-for-simple1.ox | 4++--
Aex-subscript-simple.ox | 6++++++
Msrc/gen.h | 7+++++++
Msrc/gen/gen.c | 439++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/parser.h | 1+
Msrc/parser/parser.c | 6+++---
Msrc/parser/stmt.c | 1+
13 files changed, 400 insertions(+), 94 deletions(-)

diff --git a/.clang-format b/.clang-format @@ -19,7 +19,7 @@ AlignConsecutiveMacros: false SortIncludes: false IndentCaseLabels: false -ColumnLimit: 150 +ColumnLimit: 100 PenaltyBreakBeforeFirstCallParameter: 1 AlignAfterOpenBracket: DontAlign BinPackArguments: false diff --git a/.zed/debug.json b/.zed/debug.json @@ -6,12 +6,12 @@ { "label": "Debug native binary", "build": { - "command": "make", + "command": "make check", "args": ["debug"], "cwd": "$ZED_WORKTREE_ROOT" }, "program": "$ZED_WORKTREE_ROOT/oxc", - "args": ["$ZED_WORKTREE_ROOT/ex123.ox"], + "args": ["$ZED_WORKTREE_ROOT/ex-subscript-simple.ox"], "request": "launch", "adapter": "CodeLLDB" } diff --git a/README b/README @@ -0,0 +1,17 @@ + _,.---._ ,-.--, + ,-.' , - `..--.-. /=/, .' + /==/_, , - \==\ -\/=/- / +|==| .=. \==\ `-' ,/ +|==|_ : ;=: - ||==|, - | +|==| , '=' /==/ , \ + \==\ - ,_ /==/, .--, - \ + '.='. - .'\==\- \/=/ , / + `--`--'' `--`-' `--` + + ,,,,,,,,,,,,,,,,,,,,,,,,,,,, + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Ox Programming language + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ``````````````````````````` + + WIP diff --git a/README.md b/README.md @@ -1,3 +0,0 @@ -### Ox Programming language - -WIP diff --git a/TODO b/TODO @@ -16,3 +16,4 @@ [x] redo arguments as list and not linked list, handle in parse and in gen (2 places in gen?) [x] get rid of count_args and search for 'argc' +[ ] printing -5 crashes, I think parsing is wrong for `-`, sees as value 5 diff --git a/ex-decl-no-init.ox b/ex-decl-no-init.ox @@ -0,0 +1,3 @@ +void main() { + int i; +} diff --git a/ex-for-simple1.ox b/ex-for-simple1.ox @@ -1,6 +1,6 @@ void main() { - int i; - for(i = 0; i < 5; i++) { + int i = 0; + for(i = 0; i < 5; i = i + 1) { print("bozo!"); } } diff --git a/ex-subscript-simple.ox b/ex-subscript-simple.ox @@ -0,0 +1,6 @@ +void main() { + int i = 0; + print(i); + i++; + print(i); +} diff --git a/src/gen.h b/src/gen.h @@ -5,6 +5,12 @@ #include "types.h" +typedef struct LoopContext { + gcc_jit_block* break_target; + gcc_jit_block* continue_target; + struct LoopContext* prev; +} LoopContext; + typedef struct { gcc_jit_context* ctx; gcc_jit_function* prev_func; @@ -15,6 +21,7 @@ typedef struct { gcc_jit_block* curr_block; // gcc_jit_type *type_kind; need type too? Scope* scope; + LoopContext* loop; const char* src; } Gen; diff --git a/src/gen/gen.c b/src/gen/gen.c @@ -24,6 +24,37 @@ loc_from_node(Gen* gen, Node* node) return gcc_jit_context_new_location(gen->ctx, node->filename, node->line, node->col); } +static void +push_loop(Gen* gen, gcc_jit_block* brk, gcc_jit_block* cont) +{ + LoopContext* lctx = (LoopContext*)malloc(sizeof(LoopContext)); + if (lctx == NULL) { panic("push_loop: could not alloc"); } + lctx->break_target = brk; + lctx->continue_target = cont; + lctx->prev = gen->loop; + gen->loop = lctx; +} + +static void +pop_loop(Gen* gen) +{ + LoopContext* lctx = gen->loop; + gen->loop = lctx->prev; + free(lctx); +} + +static inline gcc_jit_block* +current_break(Gen* gen) +{ + return gen->loop ? gen->loop->break_target : NULL; +} + +static inline gcc_jit_block* +current_continue(Gen* gen) +{ + return gen->loop ? gen->loop->continue_target : NULL; +} + Gen gen_init(Scope* scope, const char* src, Node* node, bool quiet) { @@ -36,14 +67,17 @@ gen_init(Scope* scope, const char* src, Node* node, bool quiet) if (!ctx) { panic("could not acquire gcc jit context"); } // needs loc* to work - // gcc_jit_context_set_bool_option(ctx, GCC_JIT_BOOL_OPTION_DEBUGINFO, 1); - // high level + // gcc_jit_context_set_bool_option(ctx, GCC_JIT_BOOL_OPTION_DEBUGINFO, + // 1); high level gcc_jit_context_set_bool_option(ctx, GCC_JIT_BOOL_OPTION_DEBUGINFO, 1); - if (quiet == false) { gcc_jit_context_set_bool_option(ctx, GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1); } + if (quiet == false) { + gcc_jit_context_set_bool_option(ctx, GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1); + } - // gcc_jit_context_set_bool_option(ctx, GCC_JIT_BOOL_OPTION_DUMP_SUMMARY, 1); + // gcc_jit_context_set_bool_option(ctx, + // GCC_JIT_BOOL_OPTION_DUMP_SUMMARY, 1); gcc_jit_context_set_str_option(ctx, GCC_JIT_STR_OPTION_PROGNAME, "ox"); // keep FP @@ -63,7 +97,8 @@ gen_init(Scope* scope, const char* src, Node* node, bool quiet) gcc_jit_location* loc = gcc_jit_context_new_location(ctx, node->filename, 0, 0); gcc_jit_param* pm_puts[] = { gcc_jit_context_new_param(ctx, loc, type_cstr, "s") }; - gcc_jit_function* fn_puts = gcc_jit_context_new_function(ctx, loc, GCC_JIT_FUNCTION_IMPORTED, type_int, "puts", 1, pm_puts, 0); + gcc_jit_function* fn_puts = gcc_jit_context_new_function( + ctx, loc, GCC_JIT_FUNCTION_IMPORTED, type_int, "puts", 1, pm_puts, 0); gcc_jit_param* pm_printf[] = { gcc_jit_context_new_param(ctx, loc, type_cstr, "fmt") }; gcc_jit_function* fn_printf = gcc_jit_context_new_function(ctx, @@ -88,25 +123,78 @@ gen_init(Scope* scope, const char* src, Node* node, bool quiet) }; } -static gcc_jit_rvalue* -handle_ident_call(Gen* gen, Node* node) +static Symbol* +find_symbol(Gen* gen, Span name) { - // Look up the symbol in the current scope // TODO look up in parent scope with utility function and recursion + const char* ident_name = span_str(gen->src, name, (char[IDENTSZ]) { 0 }); + // Look up the symbol in the current scope // TODO look up in parent + // scope with utility function and recursion for (size_t i = 0; i < gen->scope->len; i++) { Symbol* sym = gen->scope->symbols[i]; const char* sym_name = span_str(gen->src, sym->name, (char[IDENTSZ]) { 0 }); // printf("symbol %s\n", sym_name); - - const char* ident_name = span_str(gen->src, node->data.ident.name, (char[IDENTSZ]) { 0 }); // printf("ident %s\n", ident_name); - if (strncmp(sym_name, ident_name, strlen(sym_name)) == 0) { - printf("found %s\n", sym_name); - return gcc_jit_lvalue_as_rvalue(sym->d.lvalue); + printf("found symbol %s\n", sym_name); + return sym; } } + printf("find_symbol: not found: %s!\n", ident_name); + return NULL; +} - softpanic("undefined variable: %s\n", span_str(gen->src, node->data.ident.name, (char[IDENTSZ]) { 0 })); +static gcc_jit_rvalue* +handle_ident_call(Gen* gen, Node* node) +{ + // Look up the symbol in the current scope // TODO look up in parent + // scope with utility function and recursion + Symbol* sym = find_symbol(gen, node->data.ident.name); + + if (sym == NULL) { + softpanic("handle_ident_call: undefined variable: %s\n", + span_str(gen->src, node->data.ident.name, (char[IDENTSZ]) { 0 })); + } + return gcc_jit_lvalue_as_rvalue(sym->d.lvalue); +} + +static gcc_jit_rvalue* +handle_unary_expr(Gen* gen, Node* node) +{ + gcc_jit_context* ctx = gen->ctx; + gcc_jit_block* bb = gen->curr_block; + + Node* opnd = node->data.unary_expr.operand; + Symbol* sym = find_symbol(gen, opnd->data.ident.name); + if (sym == NULL) { + softpanic("handle_unary_expr: undefined variable: %s\n", + span_str(gen->src, opnd->data.ident.name, (char[IDENTSZ]) { 0 })); + } + + // gcc_jit_lvalue* lv = gcc_jit_rvalue_dereference(, NULL); + gcc_jit_lvalue* lv = sym->d.lvalue; + gcc_jit_rvalue* orig = gcc_jit_lvalue_as_rvalue(sym->d.lvalue); + gcc_jit_type* ty = gcc_jit_rvalue_get_type(orig); + gcc_jit_rvalue* one = gcc_jit_context_one(ctx, ty); + + gcc_jit_rvalue* inc + = gcc_jit_context_new_binary_op(ctx, NULL, GCC_JIT_BINARY_OP_PLUS, ty, orig, one); + switch (node->data.unary_expr.op) { + case OPER_POSTINC: { // i++ + gcc_jit_block_add_assignment(bb, NULL, lv, inc); + return orig; // return value before incr as ++ is postfix + + if (lv == NULL) { + printf("handle_unary_expr: no lvalue\n"); + return NULL; + } + printf("wef\n"); + break; + } + default: + printf("handle_unary_expr, unhandled op %d\n", node->data.unary_expr.op); + return NULL; + break; + } return NULL; } @@ -126,13 +214,15 @@ emit_literal_string(Gen* gen, Node* node) static gcc_jit_rvalue* emit_literal_int(Gen* gen, Node* node) { - return gcc_jit_context_new_rvalue_from_int(gen->ctx, type_int, (int)node->data.number.value); + return gcc_jit_context_new_rvalue_from_int( + gen->ctx, type_int, (int)node->data.number.value); } static gcc_jit_rvalue* emit_literal_float(Gen* gen, Node* node) { - return gcc_jit_context_new_rvalue_from_double(gen->ctx, type_double, node->data.number.value); + return gcc_jit_context_new_rvalue_from_double( + gen->ctx, type_double, node->data.number.value); } static void @@ -143,46 +233,113 @@ build_program(Gen* gen, Node* node) gen_next(gen, node->data.program.decl[i]); } } +static inline int +is_intlike(gcc_jit_context* ctx, gcc_jit_type* t) +{ + return t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_INT) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_SHORT) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_SHORT) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_LONG) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_LONG_LONG) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG_LONG) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT64_T) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT32_T) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_CHAR) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_CHAR); +} +static inline int +is_cstr(gcc_jit_context* ctx, gcc_jit_type* t) +{ + return t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_CONST_CHAR_PTR); +} static gcc_jit_rvalue* lower_builtin_print(Gen* gen, Node* node) { size_t argc = node->data.call_expr.len; + for (size_t i = 0; i < argc; i++) { + Node* arg = node->data.call_expr.args[i]; + } + // 1-arg, treat as puts(arg) if (argc == 1) { - gcc_jit_rvalue* arg = handle_expr(gen, node->data.call_expr.args[0]); // TODO [0] when many + gcc_jit_rvalue* arg = handle_expr(gen, node->data.call_expr.args[0]); + gcc_jit_type* t = gcc_jit_rvalue_get_type(arg); + gcc_jit_location* loc = loc_from_node(gen, node->data.call_expr.args[0]); + // print a string + if (is_cstr(gen->ctx, t)) { + gcc_jit_rvalue* args[] = { arg }; + return gcc_jit_context_new_call(gen->ctx, loc, gen->puts_fn, 1, args); + } + // print a integer + else if (is_intlike(gen->ctx, t)) { + // cast to int for a clean %d + gcc_jit_type* t_int = gcc_jit_context_get_type(gen->ctx, GCC_JIT_TYPE_INT64_T); + gcc_jit_rvalue* fmt = gcc_jit_context_new_string_literal(gen->ctx, "%d\n"); + gcc_jit_rvalue* ival = arg;//(t == t_int) + //? arg + //: gcc_jit_context_new_cast(gen->ctx, NULL, arg, t_int); + gcc_jit_rvalue* args[] = { fmt, ival }; + return gcc_jit_context_new_call(gen->ctx, loc, gen->printf_fn, 2, args); + } // cast common cases to const char* - // if (gcc_jit_rvalue_get_type(arg) != type_cstr) arg = gcc_jit_context_new_cast(gen->ctx, loc_from_node(gen, node), arg, type_cstr); - gcc_jit_rvalue* args[] = { arg }; - return gcc_jit_context_new_call(gen->ctx, loc_from_node(gen, node), gen->puts_fn, 1, args); + // if (gcc_jit_rvalue_get_type(arg) != type_cstr) arg = + // gcc_jit_context_new_cast(gen->ctx, loc_from_node(gen, node), + // arg, type_cstr); + + // gcc_jit_rvalue* args[] = { arg }; + // return gcc_jit_context_new_call( + // gen->ctx, loc_from_node(gen, node), gen->puts_fn, 1, args); + + // gcc_jit_type* type_of_args = gcc_jit_rvalue_get_type(arg); + // switch (type_of_args) { + // case GCC_JIT_TYPE_CONST_CHAR_PTR: + + // break; + // default: + // printf("lower_builtin_print: unhandled type passed %s\n", type_of_args); + // break; + // } } + return NULL; + // softpanic("we don't currently handle formatted strings to print"); - // n>=1, treat as printf(fmt, ...) // Part of TODO about args as list and not + // n>=1, treat as printf(fmt, ...) // Part of TODO about args as list + // and not // - // through each args, form the ("formatted %s string %d etc.", str, intv) for clib's printf + // through each args, form the ("formatted %s string %d etc.", str, + // intv) for clib's printf - // TODO we're talking about formatting here, which we plan on doing as a string - // interpolation, something along the lines of {{variable}} without defining its type would - // involve lookup split of the string and then formatting + // TODO we're talking about formatting here, which we plan on doing as a + // string interpolation, something along the lines of {{variable}} + // without defining its type would involve lookup split of the string + // and then formatting - // we need to discuss and decide what we'd do when the user inevitably would print out a ref - // to a struct. Do we say [[struct]] or do we have some automatic unwrap and display of - // struct data... probably, yes. + // we need to discuss and decide what we'd do when the user inevitably + // would print out a ref to a struct. Do we say [[struct]] or do we have + // some automatic unwrap and display of struct data... probably, yes. gcc_jit_rvalue** args = (gcc_jit_rvalue**)calloc(MAXARGS, sizeof(gcc_jit_rvalue*)); - if (argc > MAXARGS) { softpanic("we do not currently support more than 16 args to a print call"); } + if (argc > MAXARGS) { + softpanic("we do not currently support more than 16 args to a " + "print call"); + } for (size_t i = 0; i < argc; i++) { gcc_jit_rvalue* arg = handle_expr(gen, node->data.call_expr.args[i]); if (i == 0) { if (gcc_jit_rvalue_get_type(arg) != type_cstr) { - // note this is probably not going to work as limited cast supported - // and string isn't one of them - arg = gcc_jit_context_new_cast(gen->ctx, loc_from_node(gen, node), arg, type_cstr); + // note this is probably not going to work as + // limited cast supported and string isn't one + // of them + arg = gcc_jit_context_new_cast( + gen->ctx, loc_from_node(gen, node), arg, type_cstr); } } else { // @@ -190,15 +347,19 @@ lower_builtin_print(Gen* gen, Node* node) // gcc_jit_type* ty = gcc_jit_rvalue_get_type(arg); if (ty == type_int) { - arg = gcc_jit_context_new_cast(gen->ctx, loc_from_node(gen, node), arg, type_cstr); + arg = gcc_jit_context_new_cast( + gen->ctx, loc_from_node(gen, node), arg, type_cstr); } else if (ty == type_double) { - // variadics already promote float→double; double is + // variadics already promote float→double; + // double is } else if (ty == type_cstr) { // leave as const char* } else { // fallback: pass pointer as void* - arg = gcc_jit_context_new_cast( - gen->ctx, loc_from_node(gen, node), arg, gcc_jit_context_get_type(gen->ctx, GCC_JIT_TYPE_VOID_PTR)); + arg = gcc_jit_context_new_cast(gen->ctx, + loc_from_node(gen, node), + arg, + gcc_jit_context_get_type(gen->ctx, GCC_JIT_TYPE_VOID_PTR)); } } // TODO auto grow @@ -253,10 +414,13 @@ handle_expr(Gen* gen, Node* node) case NODE_CALL_EXPR: return handle_func_call(gen, node); break; - case NODE_IDENT: { + case NODE_IDENT: return handle_ident_call(gen, node); break; - } + case NODE_UNARY_EXPR: // ++ etc. + return handle_unary_expr(gen, node); + break; + // case NODE_IDENT: { // return NULL; // fixme // break; @@ -293,7 +457,8 @@ add_symbol(Gen* gen, Symbol* sym) { if (gen->scope->len == gen->scope->cap) { gen->scope->cap *= 2; - gen->scope->symbols = (Symbol**)realloc(gen->scope->symbols, sizeof(Symbol*) * gen->scope->cap); + gen->scope->symbols + = (Symbol**)realloc(gen->scope->symbols, sizeof(Symbol*) * gen->scope->cap); } gen->scope->symbols[gen->scope->len++] = sym; @@ -302,6 +467,8 @@ add_symbol(Gen* gen, Symbol* sym) static bool build_block(Gen*, Node*); static bool build_statement(Gen*, Node*); +static gcc_jit_rvalue* build_bool_value(Gen*, Node*); + static int block_counter = 0, loop_counter = 0; static bool @@ -311,47 +478,71 @@ build_for_statement(Gen* gen, Node* node) entry → (init) → [head: cond?] ──T──> (body) ──continue──> (step) ──┐ └──F───────────────────> (end) → next ^ - └── back to [head] + └── back to + [head] */ - // gcc_jit_location* loc = loc_from_node(gen, node); + gcc_jit_location* loc = loc_from_node(gen, node); - // Node* init = node->data.for_statement.init; - // Node* cond = node->data.for_statement.cond; - // Node* step = node->data.for_statement.increment; - // Node* body = node->data.for_statement.body; + Node* init = node->data.for_statement.init; + Node* cond = node->data.for_statement.cond; + Node* step = node->data.for_statement.increment; + Node* body = node->data.for_statement.body; - // loop_counter++; + loop_counter++; - // char label_cond[64], label_body[64], label_step[64], label_end[64]; - // snprintf(label_cond, 64, "for.cond%d", loop_counter); - // snprintf(label_body, 64, "for.body%d", loop_counter); - // snprintf(label_step, 64, "for.step%d", loop_counter); - // snprintf(label_end, 64, "for.end%d", loop_counter); + char label_cond[64], label_body[64], label_step[64], label_end[64]; + snprintf(label_cond, 64, "for.cond%d", loop_counter); + snprintf(label_body, 64, "for.body%d", loop_counter); + snprintf(label_step, 64, "for.step%d", loop_counter); + snprintf(label_end, 64, "for.end%d", loop_counter); - // gcc_jit_block* cond_block = gcc_jit_function_new_block(gen->curr_func, label_cond); - // gcc_jit_block* body_block = gcc_jit_function_new_block(gen->curr_func, label_body); - // gcc_jit_block* step_block = gcc_jit_function_new_block(gen->curr_func, label_step); - // gcc_jit_block* end_block = gcc_jit_function_new_block(gen->curr_func, label_end); + gcc_jit_block* cond_block = gcc_jit_function_new_block(gen->curr_func, label_cond); + gcc_jit_block* body_block = gcc_jit_function_new_block(gen->curr_func, label_body); + gcc_jit_block* step_block = gcc_jit_function_new_block(gen->curr_func, label_step); + gcc_jit_block* end_block = gcc_jit_function_new_block(gen->curr_func, label_end); - // // header, e.g. for(int = 0 <- - // if (init) { build_statement(gen, init); } + // gcc_jit_block* saved_break = gen->loop->break_target; + // gcc_jit_block* saved_cont = gen->loop->continue_target; + // gen->loop->break_target = end_block; + // gen->loop->continue_target = step_block; - // // jump to cond e.g. ; i < 5 <- - // gcc_jit_block_end_with_jump(gen->curr_block, loc, cond_block); + // header, e.g. for(int = 0 <- + if (init) { build_statement(gen, init); } - // // cond: evaluate - // gen->curr_block = cond_block; - // gcc_jit_rvalue* cnd = NULL; + // jump to cond e.g. ; i < 5 <- + gcc_jit_block_end_with_jump(gen->curr_block, loc, cond_block); - // if (cond != NULL) { - // // cnd = build_bool_rvalue(gen, cond); - // // TODO our parsing needs to handle the int i = 0; - // // need to handle binary_expr like if - // // or check if it's already a bool - // // or check if it's numbers(?) - // } + // cond: evaluate + gen->curr_block = cond_block; + gcc_jit_rvalue* cnd = NULL; + + if (cond != NULL) { + cnd = build_bool_value(gen, cond); + gcc_jit_block_end_with_conditional(cond_block, loc, cnd, body_block, end_block); + } else { + gcc_jit_block_end_with_jump(cond_block, loc, body_block); // presume for(;;) + } + + push_loop(gen, /*break to*/ end_block, /*continue to*/ step_block); + + // build for body + + gen->curr_block = body_block; + bool for_body_ended = build_block(gen, body); + if (!for_body_ended) { gcc_jit_block_end_with_jump(gen->curr_block, loc, step_block); } + + pop_loop(gen); + + // step incr etc. + gen->curr_block = step_block; + if (step) { build_statement(gen, step); } + gcc_jit_block_end_with_jump(step_block, loc, end_block); + + // resume after loop + + gen->curr_block = end_block; return false; } @@ -403,7 +594,8 @@ build_if_statement(Gen* gen, Node* node) // blocks 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* else_bb + = else_body ? gcc_jit_function_new_block(gen->curr_func, label_else) : NULL; gcc_jit_block* merge_bb = NULL; if (!else_bb) { @@ -418,7 +610,8 @@ build_if_statement(Gen* gen, Node* node) // 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) + gcc_jit_block* then_open = gen->curr_block; // last open block in THEN + // (may differ from then_bb) // ELSE bool else_ended = false; @@ -429,7 +622,8 @@ build_if_statement(Gen* gen, Node* node) else_open = gen->curr_block; // last open block in ELSE } - // If both branches ended, no merge needed, we notify we have ended as well + // If both branches ended, no merge needed, we notify we have ended as + // well if (else_bb && then_ended && else_ended) return true; // Ensure we have a merge if any branch continues. @@ -450,14 +644,21 @@ build_var_decl_statement(Gen* gen, Node* node) gcc_jit_type* declared_type = ox_type_to_c_type(gen, node->data.var_decl.type); gcc_jit_lvalue* var_decl = NULL; - gcc_jit_rvalue* rvalue = handle_expr(gen, node->data.var_decl.init); + + gcc_jit_rvalue* rvalue = NULL; + Node* init = node->data.var_decl.init; + if (init != NULL) { rvalue = handle_expr(gen, init); } if (gen->curr_func == NULL && gen->curr_block == NULL) { - var_decl = gcc_jit_context_new_global(gen->ctx, loc, GCC_JIT_GLOBAL_INTERNAL, declared_type, strdup(var_name)); - gcc_jit_global_set_initializer_rvalue(var_decl, rvalue); + // global var + var_decl = gcc_jit_context_new_global( + gen->ctx, loc, GCC_JIT_GLOBAL_INTERNAL, declared_type, strdup(var_name)); + if (rvalue) gcc_jit_global_set_initializer_rvalue(var_decl, rvalue); } else { - var_decl = gcc_jit_function_new_local(gen->curr_func, loc, declared_type, strdup(var_name)); - gcc_jit_block_add_assignment(gen->curr_block, loc, var_decl, rvalue); + // local var + var_decl = gcc_jit_function_new_local( + gen->curr_func, loc, declared_type, strdup(var_name)); + if (rvalue) gcc_jit_block_add_assignment(gen->curr_block, loc, var_decl, rvalue); } if (node->data.var_decl.init == NULL) { panic("could not instanciate gcc jit new local"); } @@ -486,6 +687,20 @@ build_statement(Gen* gen, Node* node) gen->curr_block = NULL; // important return true; // we end the block here } + case NODE_BREAK: { + gcc_jit_block* t = current_break(gen); + if (!t) return true; // break outside the loop + gcc_jit_block_end_with_jump(gen->curr_block, loc, t); + gen->curr_block = NULL; + return true; + } + case NODE_CONTINUE: { + gcc_jit_block* t = current_continue(gen); + if (!t) return true; // continue outside of a loop + gcc_jit_block_end_with_jump(gen->curr_block, loc, t); + gen->curr_block = NULL; + return true; + } case NODE_VAR_DECL: { return build_var_decl_statement(gen, node); } @@ -494,19 +709,33 @@ build_statement(Gen* gen, Node* node) // find the var_decl (d.lvalue) from the symbols table's symbol. for (size_t i = 0; i < gen->scope->len; i++) { Symbol* sym = gen->scope->symbols[i]; - if (span_ident_same(sym->name, node->data.var_assign.lhs->data.ident.name, gen->src)) { + if (span_ident_same(sym->name, + node->data.var_assign.lhs->data.ident.name, + gen->src)) { // we found the symbol we are assigning to gcc_jit_lvalue* lvalue = sym->d.lvalue; // check the type of lvalue matches the rvalue gcc_jit_type* ltype = sym->ctype; gcc_jit_type* rtype = gcc_jit_rvalue_get_type(rvalue); - if (rtype != ltype) { panic_at(node, "right hand side of assigment doesn't match the type of the left hand side"); } - if (lvalue) gcc_jit_block_add_assignment(gen->curr_block, loc, lvalue, rvalue); + if (rtype != ltype) { + panic_at(node, + "right hand side of assigment " + "doesn't match the " + "type of the left hand side"); + } + if (lvalue) + gcc_jit_block_add_assignment( + gen->curr_block, loc, lvalue, rvalue); } } break; } + case NODE_BINARY_EXPR: { + printf("TODO NODE_BINARY_EXPR\nTODO NODE_BINARY_EXPR\nTODO " + "NODE_BINARY_EXPR\nTODO\n"); + } + case NODE_EXPR_STATEMENT: { gcc_jit_rvalue* rv = handle_expr(gen, node->data.expr_statement.expr); if (rv) gcc_jit_block_add_eval(gen->curr_block, loc_from_node(gen, node), rv); @@ -523,6 +752,46 @@ build_statement(Gen* gen, Node* node) return false; } +static gcc_jit_rvalue* +build_bool_value(Gen* gen, Node* node) +{ + gcc_jit_location* loc = loc_from_node(gen, node); + + switch (node->type) { + case NODE_BINARY_EXPR: { + gcc_jit_rvalue* lvalue = handle_expr(gen, node->data.binary_expr.lhs); + gcc_jit_rvalue* rvalue = handle_expr(gen, node->data.binary_expr.rhs); + enum gcc_jit_comparison op; + switch (node->data.binary_expr.op) { + case OP_LT: + op = GCC_JIT_COMPARISON_LT; + break; + case OP_GT: + op = GCC_JIT_COMPARISON_GT; + break; + case OP_LT_EQ: + op = GCC_JIT_COMPARISON_LE; + break; + case OP_GT_EQ: + op = GCC_JIT_COMPARISON_GE; + break; + default: + printf("build_bool_rvalue nodebinary op unhandled, " + "%s\n", + node_type_str(node->type)); + return NULL; + } + return gcc_jit_context_new_comparison(gen->ctx, loc, op, lvalue, rvalue); + break; + } + default: + printf("build_bool_rvalue unhandled, %s\n", node_type_str(node->type)); + break; + } + + return NULL; +} + // build_block: returns true if block ended with a terminator static bool build_block(Gen* gen, Node* body) @@ -538,7 +807,8 @@ build_block(Gen* gen, Node* body) static void build_func_decl(Gen* gen, Node* node) { - const char* func_name = span_str(gen->src, node->data.function_decl.name, (char[IDENTSZ]) { 0 }); + const char* func_name + = span_str(gen->src, node->data.function_decl.name, (char[IDENTSZ]) { 0 }); Node* return_type = node->data.function_decl.return_type; gcc_jit_type* ret_type = ox_type_to_c_type(gen, return_type); @@ -563,12 +833,15 @@ build_func_decl(Gen* gen, Node* node) build_block(gen, node->data.function_decl.body); if (gen->curr_block && ret_type == type_int) { // TODO handle more return types - gcc_jit_rvalue* ret_value = gcc_jit_context_new_rvalue_from_int(gen->ctx, type_int, 0); + gcc_jit_rvalue* ret_value + = gcc_jit_context_new_rvalue_from_int(gen->ctx, type_int, 0); gcc_jit_block_end_with_return(gen->curr_block, loc, ret_value); } else if (gen->curr_block && ret_type == type_void) { gcc_jit_block_end_with_void_return(gen->curr_block, loc); } else { - printf("build_func_decl unhandled return type in func: %s - defaulting to void\n", func_name); + printf("build_func_decl unhandled return type in func: %s - " + "defaulting to void\n", + func_name); gcc_jit_block_end_with_void_return(gen->curr_block, loc); } diff --git a/src/parser.h b/src/parser.h @@ -29,6 +29,7 @@ Node* parse_unary(Parser*); Node* parse_term(Parser*); Node* parse_expression(Parser*); Node* parse_expression_statement(Parser*); +Node* parse_assignment_expr(Parser*); Node* parse_statement(Parser*); Node* parse_block(Parser*); Node* parse_declaration_statement(Parser*); diff --git a/src/parser/parser.c b/src/parser/parser.c @@ -115,13 +115,13 @@ parse_relational(Parser* par) for (;;) { if (match(par, TOKEN_LT)) { Node* rhs = parse_additive(par); - node = make_binary_node('<', node, rhs); + node = make_binary_node(OP_LT, node, rhs); } else if (match(par, TOKEN_LT_EQ)) { Node* rhs = parse_additive(par); node = make_binary_node(OP_LT_EQ, node, rhs); } else if (match(par, TOKEN_GT)) { Node* rhs = parse_additive(par); - node = make_binary_node('>', node, rhs); + node = make_binary_node(OP_GT, node, rhs); } else if (match(par, TOKEN_GT_EQ)) { Node* rhs = parse_additive(par); node = make_binary_node(OP_GT_EQ, node, rhs); @@ -172,7 +172,7 @@ parse_equality(Parser* par) return node; } -static Node* +Node* parse_assignment_expr(Parser* par) { Node* left = parse_equality(par); diff --git a/src/parser/stmt.c b/src/parser/stmt.c @@ -61,6 +61,7 @@ parse_for(Parser* par) if (tok2.type == TOKEN_IDENT) { init = parse_declaration_statement(par); } else { + // TODO check: init = parse_assignment_expr(par); init = parse_expression_statement(par); } } else