ox

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

gen.c (43481B)


      1 #include "../gen.h"
      2 #include "../parser.h"
      3 #include "../utils.h"
      4 #include "../typer.h"
      5 
      6 #include <stdint.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include <assert.h>
     11 #include <sys/param.h>
     12 
     13 static gcc_jit_type* type_boolean;
     14 static gcc_jit_type* type_int;
     15 static gcc_jit_type* type_i8;
     16 static gcc_jit_type* type_i16;
     17 static gcc_jit_type* type_i32;
     18 static gcc_jit_type* type_i64;
     19 static gcc_jit_type* type_i128;
     20 static gcc_jit_type* type_u8;
     21 static gcc_jit_type* type_u16;
     22 static gcc_jit_type* type_u32;
     23 static gcc_jit_type* type_u64;
     24 static gcc_jit_type* type_u128;
     25 static gcc_jit_type* type_f32;
     26 static gcc_jit_type* type_f64;
     27 static gcc_jit_type* type_f128;
     28 static gcc_jit_type* type_uint;
     29 static gcc_jit_type* type_void;
     30 static gcc_jit_type* type_cstr;
     31 static gcc_jit_type* type_char;
     32 static gcc_jit_type* type_voidp;
     33 
     34 static const char* type_func = "function";
     35 static const char* type_var = "variable";
     36 
     37 #define MAXARGS 16
     38 
     39 static gcc_jit_location*
     40 loc_from_node(Gen* gen, Node* node)
     41 {
     42 	if (node->filename == NULL) return NULL;
     43 	return gcc_jit_context_new_location(gen->ctx, node->filename, node->line, node->col);
     44 }
     45 
     46 static void
     47 push_loop(Gen* gen, gcc_jit_block* brk, gcc_jit_block* cont)
     48 {
     49 	LoopContext* lctx = (LoopContext*)malloc(sizeof(LoopContext));
     50 	if (lctx == NULL) { panic("push_loop: could not alloc"); }
     51 	lctx->break_target = brk;
     52 	lctx->continue_target = cont;
     53 	lctx->prev = gen->loop;
     54 	gen->loop = lctx;
     55 }
     56 
     57 static void
     58 pop_loop(Gen* gen)
     59 {
     60 	LoopContext* lctx = gen->loop;
     61 	gen->loop = lctx->prev;
     62 	free(lctx);
     63 }
     64 
     65 static inline gcc_jit_block*
     66 current_break(Gen* gen)
     67 {
     68 	return gen->loop ? gen->loop->break_target : NULL;
     69 }
     70 
     71 static inline gcc_jit_block*
     72 current_continue(Gen* gen)
     73 {
     74 	return gen->loop ? gen->loop->continue_target : NULL;
     75 }
     76 
     77 __attribute__((unused)) static const char*
     78 get_english_type(gcc_jit_type* T)
     79 {
     80 	return gcc_jit_object_get_debug_string(gcc_jit_type_as_object(T));
     81 }
     82 
     83 Gen
     84 gen_init(Scope* scope, const char* src, Node* node, bool quiet)
     85 {
     86 	if (scope == NULL || src == NULL) { panic("gen_init: no Scope or AST provided"); }
     87 
     88 	gcc_jit_context* ctx;
     89 
     90 	ctx = gcc_jit_context_acquire();
     91 
     92 	if (!ctx) { panic("could not acquire gcc jit context"); }
     93 
     94 	// needs loc* to work
     95 	// gcc_jit_context_set_bool_option(ctx, GCC_JIT_BOOL_OPTION_DEBUGINFO,
     96 	// 1); high level
     97 
     98 	gcc_jit_context_set_bool_option(ctx, GCC_JIT_BOOL_OPTION_DEBUGINFO, 1);
     99 
    100 	if (quiet == false) { gcc_jit_context_set_bool_option(ctx, GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1); }
    101 
    102 	// gcc_jit_context_set_bool_option(ctx,
    103 	// GCC_JIT_BOOL_OPTION_DUMP_SUMMARY, 1);
    104 
    105 	gcc_jit_context_set_str_option(ctx, GCC_JIT_STR_OPTION_PROGNAME, "ox");
    106 	// keep FP
    107 	gcc_jit_context_add_driver_option(ctx, "-fno-omit-frame-pointer");
    108 
    109 	gcc_jit_context_set_int_option(ctx,
    110 		GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
    111 		/*0-3 for O3*/ 0);
    112 
    113 	type_boolean = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_BOOL);
    114 
    115 	type_int = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT64_T);
    116 	type_i8 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT8_T);
    117 	type_i16 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT16_T);
    118 	type_i32 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT32_T);
    119 	type_i64 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT64_T);
    120 	type_i128 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT128_T);
    121 
    122 	type_u8 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UINT8_T);
    123 	type_u16 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UINT16_T);
    124 	type_u32 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UINT32_T);
    125 	type_u64 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UINT64_T);
    126 	type_u128 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UINT128_T);
    127 
    128 	type_f32 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_FLOAT);
    129 	type_f64 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_DOUBLE);
    130 	type_f128 = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_LONG_DOUBLE);
    131 
    132 	type_uint = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UINT64_T);
    133 	type_char = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_CHAR);
    134 	type_void = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_VOID);
    135 	type_cstr = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_CONST_CHAR_PTR);
    136 	type_voidp = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_VOID_PTR);
    137 	/* gcc_jit_type_dyncast_function_ptr_type; */
    138 
    139 	gcc_jit_location* loc = gcc_jit_context_new_location(ctx, node->filename, 0, 0);
    140 
    141 	gcc_jit_param* pm_puts[] = { gcc_jit_context_new_param(ctx, loc, type_cstr, "s") };
    142 	gcc_jit_function* fn_puts = gcc_jit_context_new_function(ctx, loc, GCC_JIT_FUNCTION_IMPORTED, type_int, "puts", 1, pm_puts, 0);
    143 
    144 	gcc_jit_param* pm_printf[] = { gcc_jit_context_new_param(ctx, loc, type_cstr, "fmt") };
    145 	gcc_jit_function* fn_printf = gcc_jit_context_new_function(ctx,
    146 		loc,
    147 		GCC_JIT_FUNCTION_IMPORTED,
    148 		type_int,
    149 		"printf",
    150 		1,
    151 		pm_printf,
    152 		/*is_variadic=*/1);
    153 
    154 	return (Gen) {
    155 		.ctx = ctx,
    156 		.scope = scope,
    157 		.prev_func = NULL,
    158 		.curr_func = NULL,
    159 		.prev_block = NULL,
    160 		.curr_block = NULL,
    161 		.puts_fn = fn_puts,
    162 		.printf_fn = fn_printf,
    163 		.src = src,
    164 	};
    165 }
    166 
    167 static void
    168 push_scope(Gen* gen)
    169 {
    170 	printf("push_scope\n");
    171 	Scope* scope = calloc(1, sizeof(Scope));
    172 	*scope = (Scope) { 0 };
    173 	scope->symbols = (Symbol**)calloc(16, sizeof(Symbol*));
    174 	if (scope->symbols == NULL) panic("push_scope: symbols: could not alloc");
    175 	scope->cap = 16;
    176 	scope->len = 0;
    177 
    178 	scope->parent = gen->scope;
    179 	gen->scope = scope;
    180 }
    181 
    182 static void
    183 pop_scope(Gen* gen)
    184 {
    185 	printf("pop_scope\n");
    186 	Scope* s = gen->scope;
    187 	gen->scope = s->parent;
    188 }
    189 
    190 static Symbol*
    191 find_symbol(Gen* gen, Scope* scope, Span name)
    192 {
    193 	const char* ident_name = span_str(gen->src, name, (char[IDENTSZ]) { 0 });
    194 	// Look up the symbol in the current scope // TODO look up in parent
    195 	// scope with utility function and recursion
    196 	for (size_t i = 0; i < scope->len; i++) {
    197 		Symbol* sym = scope->symbols[i];
    198 		const char* sym_name = span_str(gen->src, sym->name, (char[IDENTSZ]) { 0 });
    199 		// printf("symbol %s\n", sym_name);
    200 		// printf("ident %s\n", ident_name);
    201 		if (strcmp(sym_name, ident_name) == 0) {
    202 			printf("found symbol %s\n", sym_name);
    203 			return sym;
    204 		}
    205 	}
    206 	printf("find_symbol: not found locally: %s\n", ident_name);
    207 
    208 	if (scope->parent != NULL) {
    209 		printf("looking up symbol %s in parent\n", ident_name);
    210 		return find_symbol(gen, scope->parent, name);
    211 	}
    212 
    213 	return NULL;
    214 }
    215 
    216 static void
    217 add_symbol(Gen* gen, Symbol* sym)
    218 {
    219 	if (gen->scope->len == gen->scope->cap) {
    220 		gen->scope->cap *= 2;
    221 		gen->scope->symbols = (Symbol**)realloc(gen->scope->symbols, sizeof(Symbol*) * gen->scope->cap);
    222 	}
    223 
    224 	gen->scope->symbols[gen->scope->len++] = sym;
    225 
    226 	printf("add_symbol: we now have %zu symbols: ", gen->scope->len);
    227 	for (size_t i = 0; i < gen->scope->len; i++) {
    228 		Symbol* symy = gen->scope->symbols[i];
    229 		const char* name = span_str(gen->src, symy->name, (char[IDENTSZ]) { 0 });
    230 		printf("%s, ", name);
    231 	}
    232 	printf("\n");
    233 }
    234 
    235 static gcc_jit_rvalue*
    236 handle_ident_call(Gen* gen, Node* node)
    237 {
    238 	// Look up the symbol in the current scope // TODO look up in parent
    239 	// scope with utility function and recursion
    240 	Symbol* sym = find_symbol(gen, gen->scope, node->data.ident.name);
    241 
    242 	if (sym == NULL) {
    243 		panic_at(node,
    244 			"handle_ident_call: undefined variable: %s\n",
    245 			span_str(gen->src, node->data.ident.name, (char[IDENTSZ]) { 0 }));
    246 	}
    247 	return gcc_jit_lvalue_as_rvalue(sym->d.lvalue);
    248 }
    249 
    250 static gcc_jit_rvalue* handle_expr(Gen*, Node*);
    251 
    252 static inline int
    253 is_intlike(gcc_jit_context* ctx, gcc_jit_type* t) // TODO support all new types
    254 {
    255 	return t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT) || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_INT)
    256 		|| t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_SHORT)
    257 		|| t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_SHORT)
    258 		|| t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_LONG)
    259 		|| t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG)
    260 		|| t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_LONG_LONG)
    261 		|| t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG_LONG)
    262 		|| t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT64_T) || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT32_T)
    263 		|| t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_CHAR)
    264 		|| t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_CHAR);
    265 }
    266 
    267 static inline int
    268 is_floatlike(gcc_jit_context* ctx, gcc_jit_type* t)
    269 {
    270 	return t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_FLOAT) || t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_DOUBLE)
    271 		|| t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_LONG_DOUBLE);
    272 }
    273 
    274 static inline int
    275 is_cstr(gcc_jit_context* ctx, gcc_jit_type* t)
    276 {
    277 	return t == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_CONST_CHAR_PTR);
    278 }
    279 
    280 // > < >= <= + - / * %
    281 static gcc_jit_rvalue*
    282 handle_bin_expr(Gen* gen, Node* node, int gcc_jit_op, bool cmp)
    283 {
    284 	Node* lhs = node->data.binary_expr.lhs;
    285 	Node* rhs = node->data.binary_expr.rhs;
    286 	gcc_jit_context* ctx = gen->ctx;
    287 	gcc_jit_location* loc = loc_from_node(gen, node);
    288 
    289 	gcc_jit_rvalue* L = handle_expr(gen, lhs);
    290 	gcc_jit_rvalue* R = handle_expr(gen, rhs);
    291 	gcc_jit_type* Lt = gcc_jit_rvalue_get_type(L);
    292 	gcc_jit_type* Rt = gcc_jit_rvalue_get_type(R);
    293 	gcc_jit_rvalue* result = NULL;
    294 
    295 	// floats: cast both to double
    296 	if (is_floatlike(ctx, Lt) || is_floatlike(ctx, Rt)) {
    297 		gcc_jit_type* T = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_DOUBLE);
    298 		L = gcc_jit_context_new_cast(ctx, loc, L, T);
    299 		R = gcc_jit_context_new_cast(ctx, loc, R, T);
    300 		result = cmp ? gcc_jit_context_new_comparison(ctx, loc, gcc_jit_op, L, R)
    301 			     : gcc_jit_context_new_binary_op(ctx, loc, gcc_jit_op, T, L, R);
    302 		;
    303 	}
    304 
    305 	// integers: cast both to signed/unsigned long long (cheap, predictable)
    306 	if (is_intlike(ctx, Lt) && is_intlike(ctx, Rt)) {
    307 		int any_unsigned = (Lt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_CHAR))
    308 			|| (Lt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_SHORT))
    309 			|| (Lt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_INT))
    310 			|| (Lt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG))
    311 			|| (Lt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG_LONG))
    312 			|| (Rt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_CHAR))
    313 			|| (Rt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_SHORT))
    314 			|| (Rt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_INT))
    315 			|| (Rt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG))
    316 			|| (Rt == gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG_LONG));
    317 
    318 		gcc_jit_type* T = gcc_jit_context_get_type(ctx, any_unsigned ? GCC_JIT_TYPE_UINT64_T : GCC_JIT_TYPE_INT64_T);
    319 
    320 		L = gcc_jit_context_new_cast(ctx, loc, L, T);
    321 		R = gcc_jit_context_new_cast(ctx, loc, R, T);
    322 		result = cmp ? gcc_jit_context_new_comparison(ctx, loc, gcc_jit_op, L, R)
    323 			     : gcc_jit_context_new_binary_op(ctx, loc, gcc_jit_op, T, L, R);
    324 	}
    325 
    326 	// pointers: either reject or compare addresses (UB in C for unrelated objs).
    327 	if (
    328 #ifdef GCC_JIT_HAVE_gcc_jit_type_is_pointer
    329 		gcc_jit_type_is_pointer(Lt) && gcc_jit_type_is_pointer(Rt)
    330 #else
    331 		0
    332 #endif
    333 	) {
    334 		gcc_jit_type* T = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
    335 		L = gcc_jit_context_new_cast(ctx, loc, L, T);
    336 		R = gcc_jit_context_new_cast(ctx, loc, R, T);
    337 		result = cmp ? gcc_jit_context_new_comparison(ctx, loc, gcc_jit_op, L, R)
    338 			     : gcc_jit_context_new_binary_op(ctx, loc, gcc_jit_op, T, L, R);
    339 	}
    340 
    341 	return result;
    342 }
    343 
    344 static gcc_jit_rvalue*
    345 handle_binary_expr(Gen* gen, Node* node)
    346 {
    347 	int gcc_jit_op = -1;
    348 	OpType op = node->data.binary_expr.op;
    349 
    350 	switch (op) {
    351 	case OP_PLUS:
    352 		gcc_jit_op = GCC_JIT_BINARY_OP_PLUS;
    353 		return handle_bin_expr(gen, node, gcc_jit_op, false);
    354 		break;
    355 	case OP_MINUS:
    356 		gcc_jit_op = GCC_JIT_BINARY_OP_MINUS;
    357 		return handle_bin_expr(gen, node, gcc_jit_op, false);
    358 		break;
    359 	case OP_MUL:
    360 		gcc_jit_op = GCC_JIT_BINARY_OP_MULT;
    361 		return handle_bin_expr(gen, node, gcc_jit_op, false);
    362 		break;
    363 	case OP_DIV:
    364 		gcc_jit_op = GCC_JIT_BINARY_OP_DIVIDE;
    365 		return handle_bin_expr(gen, node, gcc_jit_op, false);
    366 		break;
    367 	case OP_MOD:
    368 		gcc_jit_op = GCC_JIT_BINARY_OP_MODULO;
    369 		return handle_bin_expr(gen, node, gcc_jit_op, false);
    370 		break;
    371 	case OP_LT:
    372 		gcc_jit_op = GCC_JIT_COMPARISON_LT;
    373 		break;
    374 	case OP_GT:
    375 		gcc_jit_op = GCC_JIT_COMPARISON_GT;
    376 		break;
    377 	case OP_GT_EQ:
    378 		gcc_jit_op = GCC_JIT_COMPARISON_GE;
    379 		break;
    380 	case OP_LT_EQ:
    381 		gcc_jit_op = GCC_JIT_COMPARISON_LE;
    382 		break;
    383 	default:
    384 		printf("handle_binary_expr unhandled OpType %d (can be ignored in var assignment "
    385 		       "(for now))\n",
    386 			op);
    387 		return NULL;
    388 		break;
    389 	}
    390 
    391 	if (gcc_jit_op < 0) {
    392 		// unsupported types (e.g., strings or structs)
    393 		printf("handle_binary_expr OP_LT: unsupported operand types\n");
    394 		return NULL;
    395 	}
    396 
    397 	return handle_bin_expr(gen, node, gcc_jit_op, true);
    398 }
    399 
    400 static gcc_jit_rvalue*
    401 handle_unary_expr(Gen* gen, Node* node)
    402 {
    403 	gcc_jit_context* ctx = gen->ctx;
    404 	gcc_jit_block* bb = gen->curr_block;
    405 
    406 	Node* opnd = node->data.unary_expr.operand;
    407 	Symbol* sym = find_symbol(gen, gen->scope, opnd->data.ident.name);
    408 	if (sym == NULL) {
    409 		panic_at(node,
    410 			"handle_unary_expr: undefined variable: %s\n",
    411 			span_str(gen->src, opnd->data.ident.name, (char[IDENTSZ]) { 0 }));
    412 	}
    413 
    414 	gcc_jit_lvalue* lv = sym->d.lvalue;
    415 	if (lv == NULL) {
    416 		printf("handle_unary_expr: no lvalue\n");
    417 		return NULL;
    418 	}
    419 	gcc_jit_rvalue* orig = gcc_jit_lvalue_as_rvalue(lv);
    420 	gcc_jit_type* ty = gcc_jit_rvalue_get_type(orig);
    421 	gcc_jit_rvalue* one = gcc_jit_context_one(ctx, ty);
    422 
    423 	gcc_jit_rvalue* inc = gcc_jit_context_new_binary_op(ctx, NULL, GCC_JIT_BINARY_OP_PLUS, ty, orig, one);
    424 	switch (node->data.unary_expr.op) {
    425 	case OPER_POSTINC: { // i++
    426 
    427 		if (!sym->is_variadic) {
    428 			panic_at(node,
    429 				"OPER_POSTINC: cannot change non variadic variable %s\n",
    430 				span_str(gen->src, opnd->data.ident_type.name, (char[IDENTSZ]) { 0 }));
    431 		} else if (sym->is_comp_time) {
    432 			panic_at(node,
    433 				"OPER_POSTINC: cannot change comp time constant %s\n",
    434 				span_str(gen->src, opnd->data.ident_type.name, (char[IDENTSZ]) { 0 }));
    435 		}
    436 		gcc_jit_block_add_assignment(bb, NULL, lv, inc);
    437 		return orig; // return value before incr as ++ is postfix
    438 
    439 		break;
    440 	}
    441 	default:
    442 		printf("handle_unary_expr, unhandled op %d\n", node->data.unary_expr.op);
    443 		return NULL;
    444 		break;
    445 	}
    446 	return NULL;
    447 }
    448 
    449 static gcc_jit_rvalue*
    450 emit_literal_bool(Gen* gen, Node* node)
    451 {
    452 	int v = node->data.boolean.value ? 1 : 0;
    453 	return gcc_jit_context_new_rvalue_from_int(gen->ctx, type_boolean, v);
    454 }
    455 
    456 static gcc_jit_rvalue*
    457 emit_literal_string(Gen* gen, Node* node)
    458 {
    459 	size_t len = node->data.string.value.end - node->data.string.value.start;
    460 	char* str = calloc(len + 1, sizeof(char));
    461 	if (str == NULL) panic_at(node, "emit_literal_string: could not alloc");
    462 	memcpy(str, gen->src + node->data.string.value.start, len);
    463 	str[len] = '\0';
    464 	return gcc_jit_context_new_string_literal(gen->ctx, str);
    465 }
    466 
    467 static gcc_jit_rvalue*
    468 emit_literal_int(Gen* gen, Node* node)
    469 {
    470 	return gcc_jit_context_new_rvalue_from_int(gen->ctx, type_int, (int)node->data.number.value);
    471 }
    472 
    473 static gcc_jit_rvalue*
    474 emit_literal_float(Gen* gen, Node* node)
    475 {
    476 	return gcc_jit_context_new_rvalue_from_double(gen->ctx, type_f32, node->data.number.value);
    477 }
    478 
    479 static void
    480 build_program(Gen* gen, Node* node)
    481 {
    482 	size_t cnt = node->data.program.len;
    483 	for (size_t i = 0; i < cnt; i++) {
    484 		gen_next(gen, node->data.program.decl[i]);
    485 	}
    486 }
    487 
    488 static gcc_jit_rvalue*
    489 lower_builtin_print(Gen* gen, Node* node)
    490 {
    491 	printf("lower_builtin_print\n");
    492 
    493 	size_t argc = node->data.call_expr.len;
    494 
    495 	// for (size_t i = 0; i < argc; i++) {
    496 	// Node* arg = node->data.call_expr.args[i];
    497 	// }
    498 
    499 	// 1-arg, treat as puts(arg)
    500 	if (argc == 1) {
    501 		gcc_jit_rvalue* arg = handle_expr(gen, node->data.call_expr.args[0]);
    502 		gcc_jit_type* t = gcc_jit_rvalue_get_type(arg);
    503 		gcc_jit_location* loc = loc_from_node(gen, node->data.call_expr.args[0]);
    504 		// print a string
    505 		if (is_cstr(gen->ctx, t)) {
    506 			gcc_jit_rvalue* args[] = { arg };
    507 			return gcc_jit_context_new_call(gen->ctx, loc, gen->puts_fn, 1, args);
    508 		}
    509 		// print an integer or bool
    510 		else if (is_intlike(gen->ctx, t) || t == type_boolean) {
    511 			// cast to int for a clean %d
    512 			// gcc_jit_type* t_int
    513 			// = gcc_jit_context_get_type(gen->ctx, GCC_JIT_TYPE_INT64_T);
    514 			gcc_jit_rvalue* fmt = gcc_jit_context_new_string_literal(gen->ctx, "%d\n");
    515 			gcc_jit_rvalue* ival = arg;
    516 			gcc_jit_rvalue* args[] = { fmt, ival };
    517 			return gcc_jit_context_new_call(gen->ctx, loc, gen->printf_fn, 2, args);
    518 		}
    519 		// cast common cases to const char*
    520 		// if (gcc_jit_rvalue_get_type(arg) != type_cstr) arg =
    521 		// gcc_jit_context_new_cast(gen->ctx, loc_from_node(gen, node),
    522 		// arg, type_cstr);
    523 
    524 		// gcc_jit_rvalue* args[] = { arg };
    525 		// return gcc_jit_context_new_call(
    526 		// 	gen->ctx, loc_from_node(gen, node), gen->puts_fn, 1, args);
    527 
    528 		// gcc_jit_type* type_of_args = gcc_jit_rvalue_get_type(arg);
    529 		// switch (type_of_args) {
    530 		// case GCC_JIT_TYPE_CONST_CHAR_PTR:
    531 
    532 		// 	break;
    533 		// default:
    534 		// 	printf("lower_builtin_print: unhandled type passed %s\n",
    535 		// type_of_args); 	break;
    536 		// }
    537 	}
    538 
    539 	return NULL;
    540 
    541 	// softpanic("we don't currently handle formatted strings to print");
    542 
    543 	// n>=1, treat as printf(fmt, ...) // Part of TODO about args as list
    544 	// and not
    545 	//
    546 	// through each args, form the ("formatted %s string %d etc.", str,
    547 	// intv) for clib's printf
    548 
    549 	// TODO we're talking about formatting here, which we plan on doing as a
    550 	// string interpolation, something along the lines of {{variable}}
    551 	// without defining its type would involve lookup split of the string
    552 	// and then formatting
    553 
    554 	// we need to discuss and decide what we'd do when the user inevitably
    555 	// would print out a ref to a struct. Do we say [[struct]] or do we have
    556 	// some automatic unwrap and display of struct data... probably, yes.
    557 
    558 	gcc_jit_rvalue** args = (gcc_jit_rvalue**)calloc(MAXARGS, sizeof(gcc_jit_rvalue*));
    559 
    560 	if (argc > MAXARGS) {
    561 		panic_at(node,
    562 			"we do not currently support more than 16 args to a "
    563 			"print call");
    564 	}
    565 
    566 	for (size_t i = 0; i < argc; i++) {
    567 		gcc_jit_rvalue* arg = handle_expr(gen, node->data.call_expr.args[i]);
    568 		if (i == 0) {
    569 			if (gcc_jit_rvalue_get_type(arg) != type_cstr) {
    570 				// note this is probably not going to work as
    571 				// limited cast supported and string isn't one
    572 				// of them
    573 				arg = gcc_jit_context_new_cast(gen->ctx, loc_from_node(gen, node), arg, type_cstr);
    574 			}
    575 		} else {
    576 			//
    577 			// simple widening for common scalar types
    578 			//
    579 			gcc_jit_type* ty = gcc_jit_rvalue_get_type(arg);
    580 			if (ty == type_int) {
    581 				arg = gcc_jit_context_new_cast(gen->ctx, loc_from_node(gen, node), arg, type_cstr);
    582 			} else if (ty == type_f32) { // TODO print() for other types
    583 				                     // variadics already promote float→double;
    584 				                     // double is
    585 			} else if (ty == type_cstr) {
    586 				// leave as const char*
    587 			} else if (ty == type_boolean) {
    588 				arg = gcc_jit_context_new_cast(gen->ctx, loc_from_node(gen, node), arg, type_cstr);
    589 			} else {
    590 				// fallback: pass pointer as void*
    591 				arg = gcc_jit_context_new_cast(gen->ctx,
    592 					loc_from_node(gen, node),
    593 					arg,
    594 					gcc_jit_context_get_type(gen->ctx, GCC_JIT_TYPE_VOID_PTR));
    595 			}
    596 		}
    597 		// TODO auto grow
    598 		args[i] = arg;
    599 	}
    600 	return gcc_jit_context_new_call(gen->ctx, NULL, gen->printf_fn, argc, args);
    601 	return NULL;
    602 }
    603 
    604 static gcc_jit_function*
    605 lookup_function(Gen* gen, Scope* scope, const char* func_name)
    606 {
    607 	for (size_t i = 0; i < scope->len; i++) {
    608 		Symbol* sym = scope->symbols[i];
    609 
    610 		if (sym->ctype == type_voidp) {
    611 			const char* name = span_str(gen->src, sym->name, (char[IDENTSZ]) { 0 });
    612 			if (strcmp(name, func_name) == 0) {
    613 				return sym->d.funcvalue; //
    614 			}
    615 		}
    616 	}
    617 
    618 	printf("lookup_function: not found locally: %s\n", func_name);
    619 
    620 	if (scope->parent != NULL) {
    621 		printf("looking up function %s in parent\n", func_name);
    622 		return lookup_function(gen, scope->parent, func_name);
    623 	}
    624 
    625 	return NULL;
    626 }
    627 
    628 static gcc_jit_rvalue*
    629 handle_func_call(Gen* gen, Node* node)
    630 {
    631 	Node* fcallee = node->data.call_expr.callee;
    632 	const char* func_name = span_str(gen->src, fcallee->data.ident.name, (char[IDENTSZ]) { 0 });
    633 
    634 	// short circuit to print
    635 	if (strcmp(func_name, "print") == 0) return lower_builtin_print(gen, node);
    636 
    637 	gcc_jit_function* callee = lookup_function(gen, gen->scope, func_name);
    638 	gcc_jit_location* loc = loc_from_node(gen, node);
    639 
    640 	// args handling
    641 	size_t argc = node->data.call_expr.len;
    642 
    643 	// alloc args
    644 	gcc_jit_rvalue** args = NULL;
    645 
    646 	if (argc > 0) {
    647 		args = calloc(argc, sizeof *args); // or alloca, or a fixed upper bound
    648 		for (size_t i = 0; i < argc; ++i) {
    649 			args[i] = handle_expr(gen, node->data.call_expr.args[i]);
    650 		}
    651 	}
    652 
    653 	for (size_t i = 0; i < argc; i++) {
    654 		args[i] = handle_expr(gen, node->data.call_expr.args[i]);
    655 	}
    656 
    657 	/*
    658 	        When generating the identifier expression message in the AST:
    659 	        Lookup env["message"] -> you get a gcc_jit_param* or gcc_jit_lvalue*.
    660 	        Use gcc_jit_param_as_rvalue / gcc_jit_lvalue_as_rvalue.
    661 
    662 	        gcc_jit_rvalue *msg = gcc_jit_param_as_rvalue(callee_param);
    663 
    664 	        gcc_jit_rvalue *args[1] = { msg };
    665 	        gcc_jit_block_add_eval(
    666 	            b, loc,
    667 	            gcc_jit_context_new_call(ctx, loc, print_fn, 1, args));
    668 	*/
    669 
    670 	// gcc_jit_rvalue *msg = gcc_jit_param_as_rvalue(callee_param);
    671 	// gcc_jit_rvalue *args[1] = { msg };
    672 	assert(callee != NULL && "callee not found");
    673 	return gcc_jit_context_new_call(gen->ctx, loc, callee, argc, args);
    674 
    675 	// TODO consider
    676 	/*
    677 	// calling bob() directly
    678 	   void emit_direct_call(gcc_jit_context *ctxt, SymbolId bob, gcc_jit_function *caller) {
    679 	                 GccObj *cal = ensure_func(ctxt, bob);
    680 	                 gcc_jit_block *b = gcc_jit_function_new_block(caller, "call_bob");
    681 	                 gcc_jit_rvalue *args[] = {};
    682 	                 gcc_jit_block_add_eval(b, NULL, gcc_jit_context_new_call(ctxt, cal->func, 0, args));
    683 	                 gcc_jit_block_end_with_void_return(b, NULL);
    684 	   }
    685 	*/
    686 
    687 	// return gcc_jit_context_new_call(gen->ctx, NULL, callee, 0, NULL);
    688 
    689 	// TODO handle return values
    690 	// almost unrelated could be useful to deal with return values:
    691 	// gcc_jit_rvalue* rv = handle_func_call(gen, node);
    692 	// if (rv) { gcc_jit_block_add_eval(gen->curr_block, loc_from_node(gen, node), rv); }
    693 	// return false;
    694 	return NULL;
    695 }
    696 
    697 static gcc_jit_rvalue*
    698 handle_expr(Gen* gen, Node* node)
    699 {
    700 	switch (node->type) {
    701 	case NODE_INT_LITERAL:
    702 		return emit_literal_int(gen, node);
    703 		break;
    704 	case NODE_FLOAT_LITERAL:
    705 		return emit_literal_float(gen, node);
    706 		break;
    707 	case NODE_STRING_LITERAL:
    708 		return emit_literal_string(gen, node);
    709 		break;
    710 	case NODE_BOOL_LITERAL:
    711 		return emit_literal_bool(gen, node);
    712 	case NODE_CALL_EXPR:
    713 		return handle_func_call(gen, node);
    714 		break;
    715 	case NODE_IDENT:
    716 		return handle_ident_call(gen, node);
    717 		break;
    718 	case NODE_UNARY_EXPR: // ++ etc.
    719 		return handle_unary_expr(gen, node);
    720 		break;
    721 	case NODE_BINARY_EXPR:
    722 		return handle_binary_expr(gen, node);
    723 		break;
    724 
    725 	// case NODE_IDENT: {
    726 	// 	return NULL; // fixme
    727 	//      break;
    728 	// }
    729 	default:
    730 		printf("handle_expr unhandled, %s\n", node_type_str(node->type));
    731 	}
    732 	return NULL;
    733 }
    734 
    735 static gcc_jit_type*
    736 ox_type_to_c_type(Gen* gen, Node* node)
    737 {
    738 	if (node == NULL) return type_void;
    739 
    740 	const char* type_name = span_str(gen->src, node->data.ident.name, (char[IDENTSZ]) { 0 });
    741 
    742 	if (strcmp(type_name, "int") == 0) {
    743 		return type_int;
    744 
    745 	} else if (strcmp(type_name, "i8") == 0) {
    746 		return type_i8;
    747 	} else if (strcmp(type_name, "i16") == 0) {
    748 		return type_i16;
    749 	} else if (strcmp(type_name, "i32") == 0) {
    750 		return type_i32;
    751 	} else if (strcmp(type_name, "i64") == 0) {
    752 		return type_i64;
    753 	} else if (strcmp(type_name, "i128") == 0) {
    754 		return type_i128;
    755 
    756 	} else if (strcmp(type_name, "u8") == 0) {
    757 		return type_u8;
    758 	} else if (strcmp(type_name, "u16") == 0) {
    759 		return type_u16;
    760 	} else if (strcmp(type_name, "u32") == 0) {
    761 		return type_u32;
    762 	} else if (strcmp(type_name, "u64") == 0) {
    763 		return type_u64;
    764 	} else if (strcmp(type_name, "u128") == 0) {
    765 		return type_u128;
    766 
    767 	} else if (strcmp(type_name, "f32") == 0) {
    768 		return type_f32;
    769 	} else if (strcmp(type_name, "f64") == 0) {
    770 		return type_f64;
    771 	} else if (strcmp(type_name, "f128") == 0) {
    772 		return type_f128;
    773 
    774 	} else if (strcmp(type_name, "str") == 0) {
    775 		return type_cstr;
    776 	} else if (strcmp(type_name, "float") == 0) {
    777 		return type_f32;
    778 	} else if (strcmp(type_name, "double") == 0) {
    779 		return type_f64;
    780 	} else if (strcmp(type_name, "longdouble") == 0) {
    781 		return type_f128;
    782 	} else if (strcmp(type_name, "uint") == 0) {
    783 		return type_uint;
    784 	} else if (strcmp(type_name, "void") == 0) {
    785 		return type_void;
    786 	} else {
    787 		panic_at(node, "unhandled type in gen %s", type_name);
    788 	}
    789 	return NULL;
    790 }
    791 
    792 static void
    793 print_symbols_here(Gen* gen)
    794 {
    795 	for (size_t i = 0; i < gen->scope->len; i++) {
    796 		Symbol* sym = gen->scope->symbols[i];
    797 		const char* name = span_str(gen->src, sym->name, (char[IDENTSZ]) { 0 });
    798 		printf("[%zu/%zu] symbol: %s (%s)\n", i + 1, gen->scope->len, name, sym->english_type);
    799 	}
    800 }
    801 
    802 static bool build_block(Gen*, Node*);
    803 static bool build_statement(Gen*, Node*);
    804 
    805 static gcc_jit_rvalue* build_bool_value(Gen*, Node*);
    806 
    807 static int block_counter = 0, loop_counter = 0, while_counter = 0;
    808 
    809 static bool
    810 build_while_statement(Gen* gen, Node* node)
    811 {
    812 	gcc_jit_location* loc = loc_from_node(gen, node);
    813 
    814 	Node* cond = node->data.while_statement.cond;
    815 	Node* body = node->data.while_statement.body;
    816 
    817 	while_counter++;
    818 	char label_cond[64], label_body[64], label_end[64];
    819 	snprintf(label_cond, sizeof label_cond, "while.cond%d", while_counter);
    820 	snprintf(label_body, sizeof label_body, "while.body%d", while_counter);
    821 	snprintf(label_end, sizeof label_end, "while.end%d", while_counter);
    822 
    823 	gcc_jit_block* cond_block = gcc_jit_function_new_block(gen->curr_func, label_cond);
    824 	gcc_jit_block* body_block = gcc_jit_function_new_block(gen->curr_func, label_body);
    825 	gcc_jit_block* end_block = gcc_jit_function_new_block(gen->curr_func, label_end);
    826 
    827 	/* jump from current block into the loop */
    828 	gcc_jit_block_end_with_jump(gen->curr_block, loc, cond_block);
    829 
    830 	gen->curr_block = cond_block;
    831 	gcc_jit_rvalue* cnd = NULL;
    832 
    833 	if (cond != NULL) {
    834 		cnd = build_bool_value(gen, cond);
    835 		gcc_jit_block_end_with_conditional(cond_block, loc, cnd, body_block, end_block);
    836 	} else {
    837 		/* while (1) */
    838 		gcc_jit_block_end_with_jump(cond_block, loc, body_block);
    839 	}
    840 
    841 	gcc_jit_block* continue_target = cond != NULL ? cond_block : body_block;
    842 	push_loop(gen, /*break to*/ end_block, /*continue to*/ continue_target);
    843 
    844 	gen->curr_block = body_block;
    845 	bool body_ended = build_block(gen, body);
    846 	if (!body_ended) { gcc_jit_block_end_with_jump(gen->curr_block, loc, continue_target); }
    847 
    848 	pop_loop(gen);
    849 
    850 	/* resume after loop */
    851 	gen->curr_block = end_block;
    852 	return false;
    853 }
    854 
    855 static bool
    856 build_for_statement(Gen* gen, Node* node)
    857 {
    858 	gcc_jit_location* loc = loc_from_node(gen, node);
    859 
    860 	Node* init = node->data.for_statement.init;
    861 	Node* cond = node->data.for_statement.cond;
    862 	Node* step = node->data.for_statement.increment;
    863 	Node* body = node->data.for_statement.body;
    864 
    865 	loop_counter++;
    866 
    867 	char label_cond[64], label_body[64], label_step[64], label_end[64];
    868 	snprintf(label_cond, 64, "for.cond%d", loop_counter);
    869 	snprintf(label_body, 64, "for.body%d", loop_counter);
    870 	snprintf(label_step, 64, "for.step%d", loop_counter);
    871 	snprintf(label_end, 64, "for.end%d", loop_counter);
    872 
    873 	gcc_jit_block* cond_block = gcc_jit_function_new_block(gen->curr_func, label_cond);
    874 	gcc_jit_block* body_block = gcc_jit_function_new_block(gen->curr_func, label_body);
    875 	gcc_jit_block* step_block = gcc_jit_function_new_block(gen->curr_func, label_step);
    876 	gcc_jit_block* end_block = gcc_jit_function_new_block(gen->curr_func, label_end);
    877 
    878 	// gcc_jit_block* saved_break = gen->loop->break_target;
    879 	// gcc_jit_block* saved_cont = gen->loop->continue_target;
    880 	// gen->loop->break_target = end_block;
    881 	// gen->loop->continue_target = step_block;
    882 
    883 	// header, e.g. for(int = 0 <-
    884 	if (init) { build_statement(gen, init); }
    885 
    886 	// jump to cond e.g. ; i < 5 <-
    887 	gcc_jit_block_end_with_jump(gen->curr_block, loc, cond_block);
    888 
    889 	// cond: evaluate
    890 	gen->curr_block = cond_block;
    891 	gcc_jit_rvalue* cnd = NULL;
    892 
    893 	if (cond != NULL) {
    894 		cnd = build_bool_value(gen, cond);
    895 		gcc_jit_block_end_with_conditional(cond_block, loc, cnd, body_block, end_block);
    896 	} else {
    897 		gcc_jit_block_end_with_jump(cond_block, loc, body_block); // presume for(;;)
    898 	}
    899 
    900 	push_loop(gen, /*break to*/ end_block, /*continue to*/ step_block);
    901 
    902 	// build for body
    903 
    904 	gen->curr_block = body_block;
    905 	bool for_body_ended = build_block(gen, body);
    906 	if (!for_body_ended) { gcc_jit_block_end_with_jump(gen->curr_block, loc, step_block); }
    907 
    908 	pop_loop(gen);
    909 
    910 	// step incr etc.
    911 
    912 	gen->curr_block = step_block;
    913 	if (step) { build_statement(gen, step); }
    914 	gcc_jit_block_end_with_jump(step_block, loc, cond != NULL ? cond_block : body_block);
    915 
    916 	// resume after loop
    917 
    918 	gen->curr_block = end_block;
    919 	return false;
    920 }
    921 
    922 static bool
    923 build_if_statement(Gen* gen, Node* node)
    924 {
    925 	gcc_jit_location* loc = loc_from_node(gen, node);
    926 	// build the condition
    927 
    928 	OpType op = node->data.if_statement.cond->data.binary_expr.op;
    929 	Node* lhs = node->data.if_statement.cond->data.binary_expr.lhs;
    930 	Node* rhs = node->data.if_statement.cond->data.binary_expr.rhs;
    931 
    932 	Node* then_body = node->data.if_statement.then_body;
    933 	Node* else_body = node->data.if_statement.else_body;
    934 
    935 	enum gcc_jit_comparison cmp;
    936 	switch (op) {
    937 	case OP_EQUALITY:
    938 		cmp = GCC_JIT_COMPARISON_EQ;
    939 		break;
    940 	case OP_INEQUALITY:
    941 		cmp = GCC_JIT_COMPARISON_NE;
    942 		break;
    943 	case OP_GT:
    944 		cmp = GCC_JIT_COMPARISON_GT;
    945 		break;
    946 	case OP_GT_EQ:
    947 		cmp = GCC_JIT_COMPARISON_GE;
    948 		break;
    949 	case OP_LT_EQ:
    950 		cmp = GCC_JIT_COMPARISON_LE;
    951 		break;
    952 	case OP_LT:
    953 		cmp = GCC_JIT_COMPARISON_LT;
    954 		break;
    955 	default:
    956 		printf("/!\\ build_statement NODE_IF unhandled, %d\n", op);
    957 		cmp = GCC_JIT_COMPARISON_NE;
    958 	}
    959 
    960 	gcc_jit_rvalue* lhs_val = handle_expr(gen, lhs);
    961 	gcc_jit_rvalue* rhs_val = handle_expr(gen, rhs);
    962 
    963 	gcc_jit_rvalue* cond = gcc_jit_context_new_comparison(gen->ctx, loc, cmp, lhs_val, rhs_val);
    964 
    965 	// create the BLOCKS
    966 
    967 	// labels
    968 	block_counter++;
    969 	char label_then[64], label_else[64], label_end[64];
    970 	snprintf(label_then, 64, "if.then%d", block_counter);
    971 	snprintf(label_else, 64, "if.else%d", block_counter);
    972 	snprintf(label_end, 64, "if.end%d", block_counter);
    973 
    974 	// blocks
    975 	gcc_jit_block* then_bb = gcc_jit_function_new_block(gen->curr_func, label_then);
    976 	gcc_jit_block* else_bb = else_body ? gcc_jit_function_new_block(gen->curr_func, label_else) : NULL;
    977 	gcc_jit_block* merge_bb = NULL;
    978 
    979 	if (!else_bb) {
    980 		// no else: need merge now for the false edge
    981 		merge_bb = gcc_jit_function_new_block(gen->curr_func, label_end);
    982 		gcc_jit_block_end_with_conditional(gen->curr_block, loc, cond, then_bb, merge_bb);
    983 	} else {
    984 		// with else: branch to then/else; decide on merge later
    985 		gcc_jit_block_end_with_conditional(gen->curr_block, loc, cond, then_bb, else_bb);
    986 	}
    987 
    988 	// THEN
    989 	gen->curr_block = then_bb;
    990 	bool then_ended = build_block(gen, then_body);
    991 	gcc_jit_block* then_open = gen->curr_block; // last open block in THEN
    992 	                                            // (may differ from then_bb)
    993 
    994 	// ELSE
    995 	bool else_ended = false;
    996 	gcc_jit_block* else_open = NULL;
    997 	if (else_bb) {
    998 		gen->curr_block = else_bb;
    999 		else_ended = build_block(gen, else_body);
   1000 		else_open = gen->curr_block; // last open block in ELSE
   1001 	}
   1002 
   1003 	// If both branches ended, no merge needed, we notify we have ended as
   1004 	// well
   1005 	if (else_bb && then_ended && else_ended) return true;
   1006 
   1007 	// Ensure we have a merge if any branch continues.
   1008 	if (!merge_bb) merge_bb = gcc_jit_function_new_block(gen->curr_func, label_end);
   1009 
   1010 	if (!then_ended) gcc_jit_block_end_with_jump(then_open, loc, merge_bb);
   1011 	if (else_bb && !else_ended) gcc_jit_block_end_with_jump(else_open, loc, merge_bb);
   1012 
   1013 	gen->curr_block = merge_bb;
   1014 	return false;
   1015 }
   1016 
   1017 static bool
   1018 build_var_decl_statement(Gen* gen, Node* node)
   1019 {
   1020 	gcc_jit_location* loc = loc_from_node(gen, node);
   1021 	const char* var_name = span_str(gen->src, node->data.var_decl.name, (char[IDENTSZ]) { 0 });
   1022 	gcc_jit_type* declared_type = ox_type_to_c_type(gen, node->data.var_decl.type);
   1023 
   1024 	gcc_jit_lvalue* var_decl = NULL;
   1025 
   1026 	gcc_jit_rvalue* rvalue = NULL;
   1027 	Node* init = node->data.var_decl.init;
   1028 	if (init != NULL) { rvalue = handle_expr(gen, init); }
   1029 
   1030 	if (gen->curr_func == NULL && gen->curr_block == NULL) {
   1031 		// global var
   1032 		var_decl = gcc_jit_context_new_global(gen->ctx, loc, GCC_JIT_GLOBAL_INTERNAL, declared_type, strdup(var_name));
   1033 		if (rvalue) gcc_jit_global_set_initializer_rvalue(var_decl, rvalue);
   1034 	} else {
   1035 		// local var
   1036 		var_decl = gcc_jit_function_new_local(gen->curr_func, loc, declared_type, strdup(var_name));
   1037 		if (rvalue) gcc_jit_block_add_assignment(gen->curr_block, loc, var_decl, rvalue);
   1038 	}
   1039 
   1040 	// this is not an error, there is just no initial value
   1041 	// if (node->data.var_decl.init == NULL) { panic("could not instanciate gcc jit new local"); }
   1042 
   1043 	printf("adding 1 symbol: %s\n", var_name);
   1044 
   1045 	Symbol* sym = (Symbol*)calloc(1, sizeof(Symbol));
   1046 	sym->name = node->data.var_decl.name;
   1047 	sym->decl = node;
   1048 	sym->ctype = declared_type;
   1049 	sym->d.lvalue = var_decl;
   1050 	sym->english_type = type_var;
   1051 	sym->is_variadic = node->data.var_decl.type->data.ident_type.is_variadic;
   1052 	sym->is_comp_time = node->data.var_decl.type->data.ident_type.is_comp_time;
   1053 	add_symbol(gen, sym); // add var_decl symbol
   1054 	return false;
   1055 }
   1056 
   1057 static void build_func_decl(Gen*, Node*);
   1058 
   1059 static bool
   1060 build_statement(Gen* gen, Node* node)
   1061 {
   1062 	gcc_jit_location* loc = loc_from_node(gen, node);
   1063 	switch (node->type) {
   1064 	case NODE_RETURN: {
   1065 		Node* return_expr = node->data.ret.expr;
   1066 		if (return_expr) {
   1067 			gcc_jit_rvalue* ret_rval = handle_expr(gen, return_expr);
   1068 			gcc_jit_type* expect_type = gcc_jit_function_get_return_type(gen->curr_func);
   1069 			gcc_jit_type* ret_type = gcc_jit_rvalue_get_type(ret_rval);
   1070 			types_match_or_panic(node, expect_type, ret_type);
   1071 			gcc_jit_block_end_with_return(gen->curr_block, loc, ret_rval);
   1072 		} else {
   1073 			gcc_jit_block_end_with_void_return(gen->curr_block, loc);
   1074 		}
   1075 		gen->curr_block = NULL; // important
   1076 		return true;            // we end the block here
   1077 	}
   1078 	case NODE_BREAK: {
   1079 		gcc_jit_block* t = current_break(gen);
   1080 		if (!t) return true; // break outside the loop
   1081 		gcc_jit_block_end_with_jump(gen->curr_block, loc, t);
   1082 		gen->curr_block = NULL;
   1083 		return true;
   1084 	}
   1085 	case NODE_CONTINUE: {
   1086 		gcc_jit_block* t = current_continue(gen);
   1087 		if (!t) return true; // continue outside of a loop
   1088 		gcc_jit_block_end_with_jump(gen->curr_block, loc, t);
   1089 		gen->curr_block = NULL;
   1090 		return true;
   1091 	}
   1092 	case NODE_VAR_DECL: {
   1093 		return build_var_decl_statement(gen, node);
   1094 	}
   1095 	case NODE_VAR_ASSIGN: {
   1096 		gcc_jit_rvalue* rvalue = handle_expr(gen, node->data.var_assign.rhs);
   1097 		// find the var_decl (d.lvalue) from the symbols table's symbol.
   1098 		for (size_t i = 0; i < gen->scope->len; i++) {
   1099 			Symbol* sym = gen->scope->symbols[i];
   1100 			if (span_ident_same(sym->name, node->data.var_assign.lhs->data.ident.name, gen->src)) {
   1101 				// we found the symbol we are assigning to
   1102 				// TODO check for variadic and comp_time
   1103 				if (!sym->is_variadic) {
   1104 					const char* name = span_str(gen->src, sym->name, (char[IDENTSZ]) { 0 });
   1105 					panic_at(node, "symbol %s is not variadic, cannot mutate.", name);
   1106 				}
   1107 				if (sym->is_comp_time) {
   1108 					const char* name = span_str(gen->src, sym->name, (char[IDENTSZ]) { 0 });
   1109 					panic_at(node, "symbol %s is comp time, cannot mutate.", name);
   1110 				}
   1111 
   1112 				gcc_jit_lvalue* lvalue = sym->d.lvalue;
   1113 
   1114 				// check the type of lvalue matches the rvalue
   1115 				gcc_jit_type* ltype = sym->ctype;
   1116 				gcc_jit_type* rtype = gcc_jit_rvalue_get_type(rvalue);
   1117 				if (rtype != ltype) {
   1118 					panic_at(node,
   1119 						"right hand side of assigment "
   1120 						"doesn't match the "
   1121 						"type of the left hand side: %s <-- %s",
   1122 						get_english_type(ltype),
   1123 						get_english_type(rtype));
   1124 				}
   1125 				if (lvalue) gcc_jit_block_add_assignment(gen->curr_block, loc, lvalue, rvalue);
   1126 			}
   1127 		}
   1128 		break;
   1129 	}
   1130 	case NODE_BINARY_EXPR: {
   1131 		Symbol* sym = find_symbol(gen, gen->scope, node->data.binary_expr.lhs->data.ident.name);
   1132 		if (!sym)
   1133 			panic_at(node,
   1134 				"NODE_BINARY_EXPR: Undefined symbol: %s\n",
   1135 				span_str(gen->src, node->data.ident.name, (char[IDENTSZ]) { 0 }));
   1136 
   1137 		gcc_jit_lvalue* lv = sym->d.lvalue;
   1138 		gcc_jit_rvalue* rhs = handle_expr(gen, node->data.binary_expr.rhs);
   1139 		gcc_jit_rvalue* lhs = handle_expr(gen, node->data.binary_expr.lhs);
   1140 		gcc_jit_rvalue* temp = gcc_jit_lvalue_as_rvalue(lv);
   1141 		gcc_jit_type* lvtype = gcc_jit_rvalue_get_type(temp);
   1142 		gcc_jit_rvalue* sum
   1143 			= gcc_jit_context_new_binary_op(gen->ctx, loc_from_node(gen, node), GCC_JIT_BINARY_OP_PLUS, lvtype, lhs, rhs);
   1144 
   1145 		gcc_jit_block_add_assignment(gen->curr_block, loc_from_node(gen, node), lv, sum);
   1146 	}
   1147 	case NODE_UNARY_EXPR: {
   1148 		gcc_jit_rvalue* rv = handle_unary_expr(gen, node);
   1149 		if (rv) gcc_jit_block_add_eval(gen->curr_block, loc_from_node(gen, node), rv);
   1150 		break;
   1151 	}
   1152 	case NODE_EXPR_STATEMENT: {
   1153 		gcc_jit_rvalue* rv = handle_expr(gen, node->data.expr_statement.expr);
   1154 		if (rv) gcc_jit_block_add_eval(gen->curr_block, loc_from_node(gen, node), rv);
   1155 		break;
   1156 	}
   1157 	case NODE_IF:
   1158 		return build_if_statement(gen, node);
   1159 	case NODE_FOR:
   1160 		return build_for_statement(gen, node);
   1161 	case NODE_WHILE:
   1162 		return build_while_statement(gen, node);
   1163 	case NODE_FUNCTION_DECL:
   1164 		// "closure"
   1165 		build_func_decl(gen, node);
   1166 		return false;
   1167 	case NODE_BLOCK:
   1168 		build_block(gen, node);
   1169 	default:
   1170 		printf("--- WARNING: build_statement unhandled, %s\n", node_type_str(node->type));
   1171 		break;
   1172 	}
   1173 	return false;
   1174 }
   1175 
   1176 static gcc_jit_rvalue*
   1177 build_bool_value(Gen* gen, Node* node)
   1178 {
   1179 	gcc_jit_location* loc = loc_from_node(gen, node);
   1180 
   1181 	switch (node->type) {
   1182 	case NODE_BOOL_LITERAL:
   1183 		/* true/false literal */
   1184 		return gcc_jit_context_new_rvalue_from_int(gen->ctx, type_boolean, node->data.boolean.value ? 1 : 0);
   1185 		break;
   1186 	case NODE_INT_LITERAL: {
   1187 		/* while (1) style – C truthiness */
   1188 		gcc_jit_rvalue* iv = emit_literal_int(gen, node);
   1189 		return gcc_jit_context_new_cast(gen->ctx, loc, iv, type_boolean);
   1190 	}
   1191 	case NODE_STRING_LITERAL: {
   1192 		/* while("word") should also be truthy if the pointer is non null */
   1193 		gcc_jit_rvalue* v = emit_literal_string(gen, node);
   1194 		gcc_jit_type* ty = gcc_jit_rvalue_get_type(v);
   1195 		gcc_jit_rvalue* nullv = gcc_jit_context_null(gen->ctx, ty);
   1196 		return gcc_jit_context_new_comparison(gen->ctx, loc, GCC_JIT_COMPARISON_NE, v, nullv);
   1197 	}
   1198 	case NODE_BINARY_EXPR: {
   1199 		gcc_jit_rvalue* lvalue = handle_expr(gen, node->data.binary_expr.lhs);
   1200 		gcc_jit_rvalue* rvalue = handle_expr(gen, node->data.binary_expr.rhs);
   1201 		enum gcc_jit_comparison op;
   1202 		switch (node->data.binary_expr.op) {
   1203 		case OP_LT:
   1204 			op = GCC_JIT_COMPARISON_LT;
   1205 			break;
   1206 		case OP_GT:
   1207 			op = GCC_JIT_COMPARISON_GT;
   1208 			break;
   1209 		case OP_LT_EQ:
   1210 			op = GCC_JIT_COMPARISON_LE;
   1211 			break;
   1212 		case OP_GT_EQ:
   1213 			op = GCC_JIT_COMPARISON_GE;
   1214 			break;
   1215 		default:
   1216 			printf("build_bool_rvalue nodebinary op unhandled, "
   1217 			       "%s\n",
   1218 				node_type_str(node->type));
   1219 			return NULL;
   1220 		}
   1221 		return gcc_jit_context_new_comparison(gen->ctx, loc, op, lvalue, rvalue);
   1222 		break;
   1223 	}
   1224 	default:
   1225 		printf("/!\\ build_bool_rvalue unhandled, %s\n", node_type_str(node->type));
   1226 		break;
   1227 	}
   1228 
   1229 	return NULL;
   1230 }
   1231 
   1232 // build_block: returns true if block ended with a terminator
   1233 static bool
   1234 build_block(Gen* gen, Node* body)
   1235 {
   1236 	// TODO if there is no block ({ ... }), we presume there is only 1 statement.
   1237 	// This might not always be valid, func declaration do require a block {}, but there might be cases...
   1238 	// FIXME: a symbol declared in a child block is accessible in the parent or in a sibling block...
   1239 	if (body->data.block.len == 0) { return build_statement(gen, body); }
   1240 
   1241 	for (size_t i = 0; i < body->data.block.len; i++) {
   1242 		if (gen->curr_block == NULL) return true;
   1243 		bool ended = build_statement(gen, body->data.block.stmts[i]);
   1244 		if (ended) return true;
   1245 	}
   1246 	return false;
   1247 }
   1248 
   1249 static void
   1250 build_func_decl(Gen* gen, Node* node)
   1251 {
   1252 	const char* func_name = span_str(gen->src, node->data.function_decl.name, (char[IDENTSZ]) { 0 });
   1253 
   1254 	Node* return_type = node->data.function_decl.return_type;
   1255 	gcc_jit_type* ret_type = ox_type_to_c_type(gen, return_type);
   1256 	gcc_jit_location* loc = loc_from_node(gen, node);
   1257 
   1258 	size_t argc = node->data.function_decl.p_len;
   1259 
   1260 	gcc_jit_param** params = calloc(argc, sizeof(gcc_jit_param*));
   1261 
   1262 	// 1) Create ONE gcc_jit_param per AST param
   1263 	for (size_t i = 0; i < argc; i++) {
   1264 		Node* pnode = node->data.function_decl.params[i];
   1265 		const char* pname = span_str(gen->src, pnode->data.param.name, (char[IDENTSZ]) { 0 });
   1266 
   1267 		gcc_jit_type* declared_type = ox_type_to_c_type(gen, pnode->data.param.type);
   1268 
   1269 		gcc_jit_param* p = gcc_jit_context_new_param(gen->ctx, loc, declared_type, strdup(pname));
   1270 
   1271 		params[i] = p;
   1272 	}
   1273 
   1274 	// 2) Create the function with those params
   1275 	gcc_jit_function* func = gcc_jit_context_new_function(gen->ctx,
   1276 		loc,
   1277 		GCC_JIT_FUNCTION_EXPORTED,
   1278 		ret_type,
   1279 		strdup(func_name),
   1280 		argc,
   1281 		params, // <-- these are now owned by 'func'
   1282 		0);
   1283 
   1284 	gcc_jit_block* block = gcc_jit_function_new_block(func, "entry");
   1285 
   1286 	gcc_jit_function* prev_func = gen->curr_func;
   1287 	gcc_jit_block* prev_block = gen->curr_block;
   1288 	gen->curr_func = func;
   1289 	gen->curr_block = block;
   1290 
   1291 	// 3) Add the function symbol to the current (enclosing) scope
   1292 	Symbol* sym = (Symbol*)calloc(1, sizeof(Symbol));
   1293 	sym->name = node->data.function_decl.name;
   1294 	sym->decl = node;
   1295 	sym->ctype = type_voidp; // whatever you use for function type metadata
   1296 	sym->d.funcvalue = func;
   1297 	sym->english_type = type_func;
   1298 	add_symbol(gen, sym); // add function symbol -- to the 'parent scope', before we push_scope
   1299 
   1300 	// ENTER FUNCTION SCOPE
   1301 	push_scope(gen);
   1302 
   1303 	// 4) Add parameter symbols to the FUNCTION scope, reusing the same gcc_jit_param*
   1304 	for (size_t i = 0; i < argc; i++) {
   1305 		Node* pnode = node->data.function_decl.params[i];
   1306 
   1307 		gcc_jit_param* p = params[i]; // <-- reuse, DO NOT new_param again
   1308 
   1309 		gcc_jit_type* declared_type = ox_type_to_c_type(gen, pnode->data.param.type);
   1310 
   1311 		Symbol* ps = (Symbol*)calloc(1, sizeof(Symbol));
   1312 		ps->name = pnode->data.param.name; // param identifier span
   1313 		ps->decl = pnode;
   1314 		ps->ctype = declared_type;
   1315 		ps->d.param = p;             // <-- this is associated with 'func'
   1316 		ps->english_type = type_var; // or type_param if you distinguish
   1317 		add_symbol(gen, ps);         // add param symbol
   1318 	}
   1319 
   1320 	print_symbols_here(gen);
   1321 
   1322 	build_block(gen, node->data.function_decl.body);
   1323 
   1324 	if (gen->curr_block == NULL) {
   1325 		// no open block: all paths already terminated, don't add an implicit return
   1326 	} else if (ret_type == type_int) {
   1327 		gcc_jit_rvalue* ret_value = gcc_jit_context_new_rvalue_from_int(gen->ctx, type_int, 0);
   1328 		gcc_jit_block_end_with_return(gen->curr_block, loc, ret_value);
   1329 	} else if (ret_type == type_void) {
   1330 		gcc_jit_block_end_with_void_return(gen->curr_block, loc);
   1331 	} else {
   1332 		printf("build_func_decl unhandled return type in func: %s - "
   1333 		       "defaulting to void\n",
   1334 			func_name);
   1335 		gcc_jit_block_end_with_void_return(gen->curr_block, loc);
   1336 	}
   1337 
   1338 	// LEAVE FUNCTION SCOPE
   1339 	pop_scope(gen);
   1340 
   1341 	gen->curr_func = prev_func;
   1342 	gen->curr_block = prev_block;
   1343 }
   1344 
   1345 void
   1346 gen_next(Gen* gen, Node* node)
   1347 {
   1348 	// printf("gen_next, %s\n", node_type_str(node->type));
   1349 
   1350 	switch (node->type) {
   1351 	case NODE_PROGRAM:
   1352 		build_program(gen, node);
   1353 		break;
   1354 	case NODE_FUNCTION_DECL:
   1355 		build_func_decl(gen, node);
   1356 		break;
   1357 	case NODE_STRING_LITERAL:
   1358 		emit_literal_string(gen, node);
   1359 		break;
   1360 	case NODE_INT_LITERAL:
   1361 		emit_literal_int(gen, node);
   1362 		break;
   1363 	case NODE_FLOAT_LITERAL:
   1364 		emit_literal_float(gen, node);
   1365 		break;
   1366 	case NODE_VAR_DECL:
   1367 		build_statement(gen, node);
   1368 		break;
   1369 	default:
   1370 		printf("gen: unhandled, %s\n", node_type_str(node->type));
   1371 	}
   1372 }