ox

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

commit 499b2ff90e63d0b9214b4dc23eb32667ab412165
parent 61c13e81caf86e7a92f5bbd3eb7819ec4a565566
Author: citbl <citbl@citbl.org>
Date:   Mon, 27 Oct 2025 21:33:04 +1000

janky as for loop initial impl

Diffstat:
M.zed/debug.json | 2+-
Mex-for-simple1.ox | 2+-
Msrc/gen/gen.c | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
3 files changed, 139 insertions(+), 49 deletions(-)

diff --git a/.zed/debug.json b/.zed/debug.json @@ -11,7 +11,7 @@ "cwd": "$ZED_WORKTREE_ROOT" }, "program": "$ZED_WORKTREE_ROOT/oxc", - "args": ["$ZED_WORKTREE_ROOT/ex-subscript-simple.ox"], + "args": ["$ZED_WORKTREE_ROOT/ex-for-simple1.ox"], "request": "launch", "adapter": "CodeLLDB" } diff --git a/ex-for-simple1.ox b/ex-for-simple1.ox @@ -1,6 +1,6 @@ void main() { int i = 0; - for(i = 0; i < 5; i = i + 1) { + for(i = 0; i < 5; i++) { print("bozo!"); } } diff --git a/src/gen/gen.c b/src/gen/gen.c @@ -157,6 +157,123 @@ handle_ident_call(Gen* gen, Node* node) return gcc_jit_lvalue_as_rvalue(sym->d.lvalue); } +static gcc_jit_rvalue* handle_expr(Gen*, Node*); + +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_floatlike(gcc_jit_context* ctx, gcc_jit_type* t) +{ + return t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_FLOAT) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_DOUBLE) + || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_LONG_DOUBLE); +} + +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* +handle_binary_expr(Gen* gen, Node* node) +{ + OpType op = node->data.binary_expr.op; + Node* lhs = node->data.binary_expr.lhs; + Node* rhs = node->data.binary_expr.rhs; + + gcc_jit_context* ctx = gen->ctx; + gcc_jit_location* loc = loc_from_node(gen, node); + switch (op) { + case OP_LT: { + gcc_jit_rvalue* L = handle_expr(gen, lhs); + gcc_jit_rvalue* R = handle_expr(gen, rhs); + gcc_jit_type* Lt = gcc_jit_rvalue_get_type(L); + gcc_jit_type* Rt = gcc_jit_rvalue_get_type(R); + + // floats: cast both to double + if (is_floatlike(ctx, Lt) || is_floatlike(ctx, Rt)) { + gcc_jit_type* T = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_DOUBLE); + L = gcc_jit_context_new_cast(ctx, loc, L, T); + R = gcc_jit_context_new_cast(ctx, loc, R, T); + return gcc_jit_context_new_comparison( + ctx, loc, GCC_JIT_COMPARISON_LT, L, R); + } + + // integers: cast both to signed/unsigned long long (cheap, predictable) + if (is_intlike(ctx, Lt) && is_intlike(ctx, Rt)) { + int any_unsigned + = (Lt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_CHAR)) + || (Lt + == gcc_jit_context_get_type( + ctx, GCC_JIT_TYPE_UNSIGNED_SHORT)) + || (Lt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_INT)) + || (Lt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG)) + || (Lt + == gcc_jit_context_get_type( + ctx, GCC_JIT_TYPE_UNSIGNED_LONG_LONG)) + || (Rt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_CHAR)) + || (Rt + == gcc_jit_context_get_type( + ctx, GCC_JIT_TYPE_UNSIGNED_SHORT)) + || (Rt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_INT)) + || (Rt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG)) + || (Rt + == gcc_jit_context_get_type( + ctx, GCC_JIT_TYPE_UNSIGNED_LONG_LONG)); + + gcc_jit_type* T = gcc_jit_context_get_type(ctx, + any_unsigned ? GCC_JIT_TYPE_UNSIGNED_LONG_LONG + : GCC_JIT_TYPE_LONG_LONG); + + L = gcc_jit_context_new_cast(ctx, loc, L, T); + R = gcc_jit_context_new_cast(ctx, loc, R, T); + return gcc_jit_context_new_comparison( + ctx, loc, GCC_JIT_COMPARISON_LT, L, R); + } + + // pointers: either reject or compare addresses (UB in C for unrelated objs). + if ( +#ifdef GCC_JIT_HAVE_gcc_jit_type_is_pointer + gcc_jit_type_is_pointer(Lt) && gcc_jit_type_is_pointer(Rt) +#else + 0 +#endif + ) { + gcc_jit_type* T + = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG_LONG); + L = gcc_jit_context_new_cast(ctx, loc, L, T); + R = gcc_jit_context_new_cast(ctx, loc, R, T); + return gcc_jit_context_new_comparison( + ctx, loc, GCC_JIT_COMPARISON_LT, L, R); + } + + // unsupported types (e.g., strings or structs) + printf("handle_binary_expr OP_LT: unsupported operand types\n"); + return NULL; + } + default: + printf("handle_binary_expr unhandled OpType %d (can be ignored in var assignment (for now))\n", op); + return NULL; + break; + } +} + static gcc_jit_rvalue* handle_unary_expr(Gen* gen, Node* node) { @@ -198,8 +315,6 @@ handle_unary_expr(Gen* gen, Node* node) return NULL; } -static gcc_jit_rvalue* handle_expr(Gen*, Node*); - static gcc_jit_rvalue* emit_literal_string(Gen* gen, Node* node) { @@ -233,28 +348,7 @@ 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) { @@ -277,11 +371,13 @@ lower_builtin_print(Gen* gen, Node* node) // 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_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* 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); } @@ -300,8 +396,8 @@ lower_builtin_print(Gen* gen, Node* node) // break; // default: - // printf("lower_builtin_print: unhandled type passed %s\n", type_of_args); - // break; + // printf("lower_builtin_print: unhandled type passed %s\n", + // type_of_args); break; // } } @@ -420,6 +516,9 @@ handle_expr(Gen* gen, Node* node) case NODE_UNARY_EXPR: // ++ etc. return handle_unary_expr(gen, node); break; + case NODE_BINARY_EXPR: + return handle_binary_expr(gen, node); + break; // case NODE_IDENT: { // return NULL; // fixme @@ -474,14 +573,6 @@ static int block_counter = 0, loop_counter = 0; static bool build_for_statement(Gen* gen, Node* node) { - /* - entry → (init) → [head: cond?] ──T──> (body) ──continue──> (step) ──┐ - └──F───────────────────> (end) → next - ^ - └── back to - [head] - */ - gcc_jit_location* loc = loc_from_node(gen, node); Node* init = node->data.for_statement.init; @@ -538,7 +629,7 @@ build_for_statement(Gen* gen, Node* node) gen->curr_block = step_block; if (step) { build_statement(gen, step); } - gcc_jit_block_end_with_jump(step_block, loc, end_block); + gcc_jit_block_end_with_jump(step_block, loc, cond_block); // resume after loop @@ -549,12 +640,6 @@ build_for_statement(Gen* gen, Node* node) static bool build_if_statement(Gen* gen, Node* node) { - /* - pre → [cond?] ──T──> (then) ─────┐ - └──F──> (else) ─────┐ │ - (merge) → next - */ - gcc_jit_location* loc = loc_from_node(gen, node); // build the condition @@ -732,10 +817,15 @@ build_statement(Gen* gen, Node* node) break; } case NODE_BINARY_EXPR: { - printf("TODO NODE_BINARY_EXPR\nTODO NODE_BINARY_EXPR\nTODO " - "NODE_BINARY_EXPR\nTODO\n"); + printf("TODO NODE_BINARY_EXPR\n \ + TODO NODE_BINARY_EXPR\nTODO \ + NODE_BINARY_EXPR\nTODO\n"); + } + case NODE_UNARY_EXPR: { + gcc_jit_rvalue* rv = handle_unary_expr(gen, node); + if (rv) gcc_jit_block_add_eval(gen->curr_block, loc_from_node(gen, node), rv); + break; } - 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);