summaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/codegen.c3531
-rw-r--r--src/codegen/codegen.h6
-rw-r--r--src/codegen/codegen_decl.c1519
-rw-r--r--src/codegen/codegen_main.c902
-rw-r--r--src/codegen/codegen_utils.c782
5 files changed, 2989 insertions, 3751 deletions
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c
index 86295e4..e3e1ac6 100644
--- a/src/codegen/codegen.c
+++ b/src/codegen/codegen.c
@@ -20,2073 +20,1652 @@
// static function for internal use.
static char *g_current_func_ret_type = NULL;
-static void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, int use_result)
-{
- int id = tmp_counter++;
- int is_self = (node->match_stmt.expr->type == NODE_EXPR_VAR &&
- strcmp(node->match_stmt.expr->var_ref.name, "self") == 0);
-
- char *ret_type = infer_type(ctx, node);
- int is_expr = (use_result && ret_type && strcmp(ret_type, "void") != 0);
+static void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out,
+ int use_result) {
+ int id = tmp_counter++;
+ int is_self = (node->match_stmt.expr->type == NODE_EXPR_VAR &&
+ strcmp(node->match_stmt.expr->var_ref.name, "self") == 0);
+
+ char *ret_type = infer_type(ctx, node);
+ int is_expr = (use_result && ret_type && strcmp(ret_type, "void") != 0);
+
+ fprintf(out, "({ ");
+ emit_auto_type(ctx, node->match_stmt.expr, node->token, out);
+ fprintf(out, " _m_%d = ", id);
+ if (is_self) {
+ fprintf(out, "*(");
+ }
+ codegen_expression(ctx, node->match_stmt.expr, out);
+ if (is_self) {
+ fprintf(out, ")");
+ }
+ fprintf(out, "; ");
+
+ if (is_expr) {
+ fprintf(out, "%s _r_%d; ", ret_type, id);
+ }
+
+ char *expr_type = infer_type(ctx, node->match_stmt.expr);
+ int is_option = (expr_type && strncmp(expr_type, "Option_", 7) == 0);
+ int is_result = (expr_type && strncmp(expr_type, "Result_", 7) == 0);
+
+ char *enum_name = NULL;
+ ASTNode *chk = node->match_stmt.cases;
+ int has_wildcard = 0;
+ while (chk) {
+ if (strcmp(chk->match_case.pattern, "_") == 0) {
+ has_wildcard = 1;
+ } else if (!enum_name) {
+ EnumVariantReg *reg = find_enum_variant(ctx, chk->match_case.pattern);
+ if (reg) {
+ enum_name = reg->enum_name;
+ }
+ }
+ chk = chk->next;
+ }
+
+ if (enum_name && !has_wildcard) {
+ // Iterate through all registered variants for this enum
+ EnumVariantReg *v = ctx->enum_variants;
+ while (v) {
+ if (strcmp(v->enum_name, enum_name) == 0) {
+ int covered = 0;
+ ASTNode *c2 = node->match_stmt.cases;
+ while (c2) {
+ if (strcmp(c2->match_case.pattern, v->variant_name) == 0) {
+ covered = 1;
+ break;
+ }
+ c2 = c2->next;
+ }
+ if (!covered) {
+ zwarn_at(node->token, "Non-exhaustive match: Missing variant '%s'",
+ v->variant_name);
+ }
+ }
+ v = v->next;
+ }
+ }
- fprintf(out, "({ ");
- emit_auto_type(ctx, node->match_stmt.expr, node->token, out);
- fprintf(out, " _m_%d = ", id);
- if (is_self)
- {
- fprintf(out, "*(");
+ ASTNode *c = node->match_stmt.cases;
+ int first = 1;
+ while (c) {
+ if (!first) {
+ fprintf(out, " else ");
}
- codegen_expression(ctx, node->match_stmt.expr, out);
- if (is_self)
- {
- fprintf(out, ")");
+ fprintf(out, "if (");
+ if (strcmp(c->match_case.pattern, "_") == 0) {
+ fprintf(out, "1");
+ } else if (is_option) {
+ if (strcmp(c->match_case.pattern, "Some") == 0) {
+ fprintf(out, "_m_%d.is_some", id);
+ } else if (strcmp(c->match_case.pattern, "None") == 0) {
+ fprintf(out, "!_m_%d.is_some", id);
+ } else {
+ fprintf(out, "1");
+ }
+ } else if (is_result) {
+ if (strcmp(c->match_case.pattern, "Ok") == 0) {
+ fprintf(out, "_m_%d.is_ok", id);
+ } else if (strcmp(c->match_case.pattern, "Err") == 0) {
+ fprintf(out, "!_m_%d.is_ok", id);
+ } else {
+ fprintf(out, "1");
+ }
+ } else {
+ EnumVariantReg *reg = find_enum_variant(ctx, c->match_case.pattern);
+ if (reg) {
+ fprintf(out, "_m_%d.tag == %d", id, reg->tag_id);
+ } else if (c->match_case.pattern[0] == '"') {
+ fprintf(out, "strcmp(_m_%d, %s) == 0", id, c->match_case.pattern);
+ } else if (isdigit(c->match_case.pattern[0]) ||
+ c->match_case.pattern[0] == '-') {
+ // Numeric pattern
+ fprintf(out, "_m_%d == %s", id, c->match_case.pattern);
+ } else if (c->match_case.pattern[0] == '\'') {
+ // Char literal pattern
+ fprintf(out, "_m_%d == %s", id, c->match_case.pattern);
+ } else {
+ fprintf(out, "1");
+ }
+ }
+ fprintf(out, ") { ");
+ if (c->match_case.binding_name) {
+ if (is_option) {
+ if (strstr(g_config.cc, "tcc")) {
+ fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id,
+ c->match_case.binding_name, id);
+ } else {
+ fprintf(out, "__auto_type %s = _m_%d.val; ",
+ c->match_case.binding_name, id);
+ }
+ }
+ if (is_result) {
+ if (strcmp(c->match_case.pattern, "Ok") == 0) {
+ if (strstr(g_config.cc, "tcc")) {
+ fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id,
+ c->match_case.binding_name, id);
+ } else {
+ fprintf(out, "__auto_type %s = _m_%d.val; ",
+ c->match_case.binding_name, id);
+ }
+ } else {
+ if (strstr(g_config.cc, "tcc")) {
+ fprintf(out, "__typeof__(_m_%d.err) %s = _m_%d.err; ", id,
+ c->match_case.binding_name, id);
+ } else {
+ fprintf(out, "__auto_type %s = _m_%d.err; ",
+ c->match_case.binding_name, id);
+ }
+ }
+ } else {
+ char *f = strrchr(c->match_case.pattern, '_');
+ if (f) {
+ f++;
+ } else {
+ f = c->match_case.pattern;
+ }
+ fprintf(out, "__auto_type %s = _m_%d.data.%s; ",
+ c->match_case.binding_name, id, f);
+ }
}
- fprintf(out, "; ");
- if (is_expr)
- {
- fprintf(out, "%s _r_%d; ", ret_type, id);
+ // Check if body is a string literal (should auto-print).
+ ASTNode *body = c->match_case.body;
+ int is_string_literal =
+ (body->type == NODE_EXPR_LITERAL && body->literal.type_kind == 2);
+
+ if (is_expr) {
+ fprintf(out, "_r_%d = ", id);
+ if (is_string_literal) {
+ codegen_node_single(ctx, body, out);
+ } else {
+ if (body->type == NODE_BLOCK) {
+ int saved = defer_count;
+ fprintf(out, "({ ");
+ ASTNode *stmt = body->block.statements;
+ while (stmt) {
+ codegen_node_single(ctx, stmt, out);
+ stmt = stmt->next;
+ }
+ for (int i = defer_count - 1; i >= saved; i--) {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ defer_count = saved;
+ fprintf(out, " })");
+ } else {
+ codegen_node_single(ctx, body, out);
+ }
+ }
+ fprintf(out, ";");
+ } else {
+ if (is_string_literal) {
+ fprintf(out, "({ printf(\"%%s\", ");
+ codegen_expression(ctx, body, out);
+ fprintf(out, "); printf(\"\\n\"); 0; })");
+ } else {
+ codegen_node_single(ctx, body, out);
+ }
}
- char *expr_type = infer_type(ctx, node->match_stmt.expr);
- int is_option = (expr_type && strncmp(expr_type, "Option_", 7) == 0);
- int is_result = (expr_type && strncmp(expr_type, "Result_", 7) == 0);
+ fprintf(out, " }");
+ first = 0;
+ c = c->next;
+ }
- char *enum_name = NULL;
- ASTNode *chk = node->match_stmt.cases;
- int has_wildcard = 0;
- while (chk)
- {
- if (strcmp(chk->match_case.pattern, "_") == 0)
- {
- has_wildcard = 1;
- }
- else if (!enum_name)
- {
- EnumVariantReg *reg = find_enum_variant(ctx, chk->match_case.pattern);
- if (reg)
- {
- enum_name = reg->enum_name;
- }
- }
- chk = chk->next;
- }
+ if (is_expr) {
+ fprintf(out, " _r_%d; })", id);
+ } else {
+ fprintf(out, " })");
+ }
+}
- if (enum_name && !has_wildcard)
- {
- // Iterate through all registered variants for this enum
- EnumVariantReg *v = ctx->enum_variants;
- while (v)
- {
- if (strcmp(v->enum_name, enum_name) == 0)
- {
- int covered = 0;
- ASTNode *c2 = node->match_stmt.cases;
- while (c2)
- {
- if (strcmp(c2->match_case.pattern, v->variant_name) == 0)
- {
- covered = 1;
- break;
- }
- c2 = c2->next;
- }
- if (!covered)
- {
- zwarn_at(node->token, "Non-exhaustive match: Missing variant '%s'",
- v->variant_name);
- }
+void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) {
+ if (!node) {
+ return;
+ }
+ switch (node->type) {
+ case NODE_MATCH:
+ codegen_match_internal(ctx, node, out, 1);
+ break;
+ case NODE_EXPR_BINARY:
+ if (strncmp(node->binary.op, "??", 2) == 0 &&
+ strlen(node->binary.op) == 2) {
+ fprintf(out, "({ ");
+ emit_auto_type(ctx, node->binary.left, node->token, out);
+ fprintf(out, " _l = (");
+ codegen_expression(ctx, node->binary.left, out);
+ fprintf(out, "); _l ? _l : (");
+ codegen_expression(ctx, node->binary.right, out);
+ fprintf(out, "); })");
+ } else if (strcmp(node->binary.op, "?\?=") == 0) {
+ fprintf(out, "({ if (!(");
+ codegen_expression(ctx, node->binary.left, out);
+ fprintf(out, ")) ");
+ codegen_expression(ctx, node->binary.left, out);
+ fprintf(out, " = (");
+ codegen_expression(ctx, node->binary.right, out);
+ fprintf(out, "); ");
+ codegen_expression(ctx, node->binary.left, out);
+ fprintf(out, "; })");
+ } else if ((strcmp(node->binary.op, "==") == 0 ||
+ strcmp(node->binary.op, "!=") == 0)) {
+ char *t1 = infer_type(ctx, node->binary.left);
+
+ int is_ptr = 0;
+ if (t1) {
+ char *check = t1;
+ int depth = 0;
+ while (depth++ < 10) {
+ if (strchr(check, '*')) {
+ is_ptr = 1;
+ break;
+ }
+ int resolved = 0;
+ ASTNode *alias = global_user_structs;
+ if (alias) {
+ while (alias) {
+ if (alias->type == NODE_TYPE_ALIAS &&
+ strcmp(check, alias->type_alias.alias) == 0) {
+ check = alias->type_alias.original_type;
+ resolved = 1;
+ break;
+ }
+ alias = alias->next;
}
- v = v->next;
+ }
+ if (!resolved) {
+ break;
+ }
+ }
+ }
+
+ int is_basic = 0;
+ if (t1) {
+ is_basic =
+ (strcmp(t1, "int") == 0 || strcmp(t1, "bool") == 0 ||
+ strcmp(t1, "char") == 0 || strcmp(t1, "void") == 0 ||
+ strcmp(t1, "float") == 0 || strcmp(t1, "double") == 0 ||
+ strcmp(t1, "usize") == 0 || strcmp(t1, "size_t") == 0 ||
+ strcmp(t1, "ssize_t") == 0 || strcmp(t1, "__auto_type") == 0);
+ }
+
+ ASTNode *def = t1 ? find_struct_def(ctx, t1) : NULL;
+ if (t1 && def && (def->type == NODE_STRUCT || def->type == NODE_ENUM) &&
+ !is_basic && !is_ptr) {
+ char *base = t1;
+ if (strncmp(base, "struct ", 7) == 0) {
+ base += 7;
+ }
+
+ if (strcmp(node->binary.op, "!=") == 0) {
+ fprintf(out, "(!");
+ }
+ fprintf(out, "%s_eq(&", base);
+ codegen_expression(ctx, node->binary.left, out);
+ fprintf(out, ", ");
+ codegen_expression(ctx, node->binary.right, out);
+ fprintf(out, ")");
+ if (strcmp(node->binary.op, "!=") == 0) {
+ fprintf(out, ")");
}
+ } else {
+ fprintf(out, "(");
+ codegen_expression(ctx, node->binary.left, out);
+ fprintf(out, " %s ", node->binary.op);
+ codegen_expression(ctx, node->binary.right, out);
+ fprintf(out, ")");
+ }
+ } else {
+ fprintf(out, "(");
+ codegen_expression(ctx, node->binary.left, out);
+ fprintf(out, " %s ", node->binary.op);
+ codegen_expression(ctx, node->binary.right, out);
+ fprintf(out, ")");
+ }
+ break;
+ case NODE_EXPR_VAR:
+ if (g_current_lambda) {
+ for (int i = 0; i < g_current_lambda->lambda.num_captures; i++) {
+ if (strcmp(node->var_ref.name,
+ g_current_lambda->lambda.captured_vars[i]) == 0) {
+ fprintf(out, "ctx->%s", node->var_ref.name);
+ return;
+ }
+ }
}
- ASTNode *c = node->match_stmt.cases;
- int first = 1;
- while (c)
- {
- if (!first)
- {
- fprintf(out, " else ");
- }
- fprintf(out, "if (");
- if (strcmp(c->match_case.pattern, "_") == 0)
- {
- fprintf(out, "1");
- }
- else if (is_option)
- {
- if (strcmp(c->match_case.pattern, "Some") == 0)
- {
- fprintf(out, "_m_%d.is_some", id);
- }
- else if (strcmp(c->match_case.pattern, "None") == 0)
- {
- fprintf(out, "!_m_%d.is_some", id);
- }
- else
- {
- fprintf(out, "1");
- }
- }
- else if (is_result)
- {
- if (strcmp(c->match_case.pattern, "Ok") == 0)
- {
- fprintf(out, "_m_%d.is_ok", id);
- }
- else if (strcmp(c->match_case.pattern, "Err") == 0)
- {
- fprintf(out, "!_m_%d.is_ok", id);
- }
- else
- {
- fprintf(out, "1");
- }
- }
- else
- {
- EnumVariantReg *reg = find_enum_variant(ctx, c->match_case.pattern);
- if (reg)
- {
- fprintf(out, "_m_%d.tag == %d", id, reg->tag_id);
- }
- else if (c->match_case.pattern[0] == '"')
- {
- fprintf(out, "strcmp(_m_%d, %s) == 0", id, c->match_case.pattern);
- }
- else if (isdigit(c->match_case.pattern[0]) || c->match_case.pattern[0] == '-')
- {
- // Numeric pattern
- fprintf(out, "_m_%d == %s", id, c->match_case.pattern);
- }
- else if (c->match_case.pattern[0] == '\'')
- {
- // Char literal pattern
- fprintf(out, "_m_%d == %s", id, c->match_case.pattern);
- }
- else
- {
- fprintf(out, "1");
- }
- }
- fprintf(out, ") { ");
- if (c->match_case.binding_name)
- {
- if (is_option)
- {
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id,
- c->match_case.binding_name, id);
- }
- else
- {
- fprintf(out, "__auto_type %s = _m_%d.val; ", c->match_case.binding_name, id);
- }
- }
- if (is_result)
- {
- if (strcmp(c->match_case.pattern, "Ok") == 0)
- {
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id,
- c->match_case.binding_name, id);
- }
- else
- {
- fprintf(out, "__auto_type %s = _m_%d.val; ", c->match_case.binding_name,
- id);
- }
- }
- else
- {
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, "__typeof__(_m_%d.err) %s = _m_%d.err; ", id,
- c->match_case.binding_name, id);
- }
- else
- {
- fprintf(out, "__auto_type %s = _m_%d.err; ", c->match_case.binding_name,
- id);
- }
- }
- }
- else
- {
- char *f = strrchr(c->match_case.pattern, '_');
- if (f)
- {
- f++;
- }
- else
- {
- f = c->match_case.pattern;
- }
- fprintf(out, "__auto_type %s = _m_%d.data.%s; ", c->match_case.binding_name, id, f);
- }
- }
-
- // Check if body is a string literal (should auto-print).
- ASTNode *body = c->match_case.body;
- int is_string_literal = (body->type == NODE_EXPR_LITERAL && body->literal.type_kind == 2);
+ if (node->resolved_type && strcmp(node->resolved_type, "unknown") == 0) {
+ if (node->var_ref.suggestion) {
+ char msg[256];
+ sprintf(msg, "Undefined variable '%s'", node->var_ref.name);
+ char help[256];
+ sprintf(help, "Did you mean '%s'?", node->var_ref.suggestion);
- if (is_expr)
- {
- fprintf(out, "_r_%d = ", id);
- if (is_string_literal)
- {
- codegen_node_single(ctx, body, out);
- }
- else
- {
- if (body->type == NODE_BLOCK)
- {
- int saved = defer_count;
- fprintf(out, "({ ");
- ASTNode *stmt = body->block.statements;
- while (stmt)
- {
- codegen_node_single(ctx, stmt, out);
- stmt = stmt->next;
- }
- for (int i = defer_count - 1; i >= saved; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- defer_count = saved;
- fprintf(out, " })");
- }
- else
- {
- codegen_node_single(ctx, body, out);
- }
- }
- fprintf(out, ";");
- }
- else
- {
- if (is_string_literal)
- {
- fprintf(out, "({ printf(\"%%s\", ");
- codegen_expression(ctx, body, out);
- fprintf(out, "); printf(\"\\n\"); 0; })");
- }
- else
- {
- codegen_node_single(ctx, body, out);
- }
+ zwarn_at(node->token, "%s\n = help: %s", msg, help);
+ }
+ }
+ fprintf(out, "%s", node->var_ref.name);
+ break;
+ case NODE_LAMBDA:
+ if (node->lambda.num_captures > 0) {
+ fprintf(out,
+ "({ struct Lambda_%d_Ctx *ctx = malloc(sizeof(struct "
+ "Lambda_%d_Ctx));\n",
+ node->lambda.lambda_id, node->lambda.lambda_id);
+ for (int i = 0; i < node->lambda.num_captures; i++) {
+ fprintf(out, "ctx->%s = ", node->lambda.captured_vars[i]);
+ int found = 0;
+ if (g_current_lambda) {
+ for (int k = 0; k < g_current_lambda->lambda.num_captures; k++) {
+ if (strcmp(node->lambda.captured_vars[i],
+ g_current_lambda->lambda.captured_vars[k]) == 0) {
+ fprintf(out, "ctx->%s", node->lambda.captured_vars[i]);
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ fprintf(out, "%s", node->lambda.captured_vars[i]);
}
-
- fprintf(out, " }");
- first = 0;
- c = c->next;
+ fprintf(out, ";\n");
+ }
+ fprintf(out, "(z_closure_T){.func = _lambda_%d, .ctx = ctx}; })",
+ node->lambda.lambda_id);
+ } else {
+ fprintf(out, "((z_closure_T){.func = (void*)_lambda_%d, .ctx = NULL})",
+ node->lambda.lambda_id);
+ }
+ break;
+ case NODE_EXPR_LITERAL:
+ if (node->literal.type_kind == TOK_STRING) {
+ fprintf(out, "\"%s\"", node->literal.string_val);
+ } else if (node->literal.type_kind == TOK_CHAR) {
+ fprintf(out, "%s", node->literal.string_val);
+ } else if (node->literal.type_kind == 1) {
+ fprintf(out, "%f", node->literal.float_val);
}
- if (is_expr)
- {
- fprintf(out, " _r_%d; })", id);
+ else {
+ if (node->literal.int_val > 9223372036854775807ULL) {
+ fprintf(out, "%lluULL", (unsigned long long)node->literal.int_val);
+ } else {
+ fprintf(out, "%llu", (unsigned long long)node->literal.int_val);
+ }
}
- else
- {
- fprintf(out, " })");
+ break;
+ case NODE_EXPR_CALL: {
+ if (node->call.callee->type == NODE_EXPR_MEMBER) {
+ ASTNode *target = node->call.callee->member.target;
+ char *method = node->call.callee->member.field;
+
+ if (strcmp(method, "len") == 0) {
+ if (target->type_info && target->type_info->kind == TYPE_ARRAY) {
+ if (target->type_info->array_size > 0) {
+ fprintf(out, "%d", target->type_info->array_size);
+ } else {
+ codegen_expression(ctx, target, out);
+ fprintf(out, ".len");
+ }
+ return;
+ }
+ }
+
+ char *type = infer_type(ctx, target);
+ if (type) {
+ char *clean = xstrdup(type);
+ char *ptr = strchr(clean, '*');
+ if (ptr) {
+ *ptr = 0;
+ }
+
+ char *base = clean;
+ if (strncmp(base, "struct ", 7) == 0) {
+ base += 7;
+ }
+
+ if (!strchr(type, '*') && target->type == NODE_EXPR_CALL) {
+ fprintf(out, "({ %s _t = ", type);
+ codegen_expression(ctx, target, out);
+ fprintf(out, "; %s_%s(&_t", base, method);
+ ASTNode *arg = node->call.args;
+ while (arg) {
+ fprintf(out, ", ");
+ codegen_expression(ctx, arg, out);
+ arg = arg->next;
+ }
+ fprintf(out, "); })");
+ } else {
+ fprintf(out, "%s_%s(", base, method);
+ if (!strchr(type, '*')) {
+ fprintf(out, "&");
+ }
+ codegen_expression(ctx, target, out);
+ ASTNode *arg = node->call.args;
+ while (arg) {
+ fprintf(out, ", ");
+ codegen_expression(ctx, arg, out);
+ arg = arg->next;
+ }
+ fprintf(out, ")");
+ }
+ free(clean);
+ return;
+ }
}
-}
-
-void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
-{
- if (!node)
- {
+ if (node->call.callee->type == NODE_EXPR_VAR) {
+ ASTNode *def = find_struct_def(ctx, node->call.callee->var_ref.name);
+ if (def && def->type == NODE_STRUCT) {
+ fprintf(out, "(struct %s){0}", node->call.callee->var_ref.name);
return;
+ }
}
- switch (node->type)
- {
- case NODE_MATCH:
- codegen_match_internal(ctx, node, out, 1);
- break;
- case NODE_EXPR_BINARY:
- if (strncmp(node->binary.op, "??", 2) == 0 && strlen(node->binary.op) == 2)
- {
- fprintf(out, "({ ");
- emit_auto_type(ctx, node->binary.left, node->token, out);
- fprintf(out, " _l = (");
- codegen_expression(ctx, node->binary.left, out);
- fprintf(out, "); _l ? _l : (");
- codegen_expression(ctx, node->binary.right, out);
- fprintf(out, "); })");
- }
- else if (strcmp(node->binary.op, "?\?=") == 0)
- {
- fprintf(out, "({ if (!(");
- codegen_expression(ctx, node->binary.left, out);
- fprintf(out, ")) ");
- codegen_expression(ctx, node->binary.left, out);
- fprintf(out, " = (");
- codegen_expression(ctx, node->binary.right, out);
- fprintf(out, "); ");
- codegen_expression(ctx, node->binary.left, out);
- fprintf(out, "; })");
- }
- else if ((strcmp(node->binary.op, "==") == 0 || strcmp(node->binary.op, "!=") == 0))
- {
- char *t1 = infer_type(ctx, node->binary.left);
-
- int is_ptr = 0;
- if (t1)
- {
- char *check = t1;
- int depth = 0;
- while (depth++ < 10)
- {
- if (strchr(check, '*'))
- {
- is_ptr = 1;
- break;
- }
- int resolved = 0;
- ASTNode *alias = global_user_structs;
- if (alias)
- {
- while (alias)
- {
- if (alias->type == NODE_TYPE_ALIAS &&
- strcmp(check, alias->type_alias.alias) == 0)
- {
- check = alias->type_alias.original_type;
- resolved = 1;
- break;
- }
- alias = alias->next;
- }
- }
- if (!resolved)
- {
- break;
- }
- }
- }
- int is_basic = 0;
- if (t1)
- {
- is_basic = (strcmp(t1, "int") == 0 || strcmp(t1, "bool") == 0 ||
- strcmp(t1, "char") == 0 || strcmp(t1, "void") == 0 ||
- strcmp(t1, "float") == 0 || strcmp(t1, "double") == 0 ||
- strcmp(t1, "usize") == 0 || strcmp(t1, "size_t") == 0 ||
- strcmp(t1, "ssize_t") == 0 || strcmp(t1, "__auto_type") == 0);
- }
+ if (node->call.callee->type_info &&
+ node->call.callee->type_info->kind == TYPE_FUNCTION) {
+ fprintf(out, "({ z_closure_T _c = ");
+ codegen_expression(ctx, node->call.callee, out);
+ fprintf(out, "; ");
+
+ Type *ft = node->call.callee->type_info;
+ char *ret = type_to_string(ft->inner);
+ if (strcmp(ret, "string") == 0) {
+ free(ret);
+ ret = xstrdup("char*");
+ }
+
+ fprintf(out, "((%s (*)(void*", ret);
+ for (int i = 0; i < ft->arg_count; i++) {
+ char *as = type_to_string(ft->args[i]);
+ fprintf(out, ", %s", as);
+ free(as);
+ }
+ if (ft->is_varargs) {
+ fprintf(out, ", ...");
+ }
+ fprintf(out, "))_c.func)(_c.ctx");
+
+ ASTNode *arg = node->call.args;
+ while (arg) {
+ fprintf(out, ", ");
+ codegen_expression(ctx, arg, out);
+ arg = arg->next;
+ }
+ fprintf(out, "); })");
+ free(ret);
+ break;
+ }
- ASTNode *def = t1 ? find_struct_def(ctx, t1) : NULL;
- if (t1 && def && (def->type == NODE_STRUCT || def->type == NODE_ENUM) && !is_basic &&
- !is_ptr)
- {
- char *base = t1;
- if (strncmp(base, "struct ", 7) == 0)
- {
- base += 7;
- }
-
- if (strcmp(node->binary.op, "!=") == 0)
- {
- fprintf(out, "(!");
- }
- fprintf(out, "%s_eq(&", base);
- codegen_expression(ctx, node->binary.left, out);
- fprintf(out, ", ");
- codegen_expression(ctx, node->binary.right, out);
- fprintf(out, ")");
- if (strcmp(node->binary.op, "!=") == 0)
- {
- fprintf(out, ")");
- }
- }
- else
- {
- fprintf(out, "(");
- codegen_expression(ctx, node->binary.left, out);
- fprintf(out, " %s ", node->binary.op);
- codegen_expression(ctx, node->binary.right, out);
- fprintf(out, ")");
- }
- }
- else
- {
- fprintf(out, "(");
- codegen_expression(ctx, node->binary.left, out);
- fprintf(out, " %s ", node->binary.op);
- codegen_expression(ctx, node->binary.right, out);
- fprintf(out, ")");
- }
- break;
- case NODE_EXPR_VAR:
- if (g_current_lambda)
- {
- for (int i = 0; i < g_current_lambda->lambda.num_captures; i++)
- {
- if (strcmp(node->var_ref.name, g_current_lambda->lambda.captured_vars[i]) == 0)
- {
- fprintf(out, "ctx->%s", node->var_ref.name);
- return;
- }
- }
- }
+ codegen_expression(ctx, node->call.callee, out);
+ fprintf(out, "(");
- if (node->resolved_type && strcmp(node->resolved_type, "unknown") == 0)
- {
- if (node->var_ref.suggestion)
- {
- char msg[256];
- sprintf(msg, "Undefined variable '%s'", node->var_ref.name);
- char help[256];
- sprintf(help, "Did you mean '%s'?", node->var_ref.suggestion);
+ if (node->call.arg_names && node->call.callee->type == NODE_EXPR_VAR) {
+ char *fn_name = node->call.callee->var_ref.name;
+ FuncSig *sig = find_func(ctx, fn_name);
- zwarn_at(node->token, "%s\n = help: %s", msg, help);
- }
- }
- fprintf(out, "%s", node->var_ref.name);
- break;
- case NODE_LAMBDA:
- if (node->lambda.num_captures > 0)
- {
- fprintf(out,
- "({ struct Lambda_%d_Ctx *ctx = malloc(sizeof(struct "
- "Lambda_%d_Ctx));\n",
- node->lambda.lambda_id, node->lambda.lambda_id);
- for (int i = 0; i < node->lambda.num_captures; i++)
- {
- fprintf(out, "ctx->%s = ", node->lambda.captured_vars[i]);
- int found = 0;
- if (g_current_lambda)
- {
- for (int k = 0; k < g_current_lambda->lambda.num_captures; k++)
- {
- if (strcmp(node->lambda.captured_vars[i],
- g_current_lambda->lambda.captured_vars[k]) == 0)
- {
- fprintf(out, "ctx->%s", node->lambda.captured_vars[i]);
- found = 1;
- break;
- }
- }
- }
- if (!found)
- {
- fprintf(out, "%s", node->lambda.captured_vars[i]);
- }
- fprintf(out, ";\n");
- }
- fprintf(out, "(z_closure_T){.func = _lambda_%d, .ctx = ctx}; })",
- node->lambda.lambda_id);
- }
- else
- {
- fprintf(out, "((z_closure_T){.func = (void*)_lambda_%d, .ctx = NULL})",
- node->lambda.lambda_id);
- }
- break;
- case NODE_EXPR_LITERAL:
- if (node->literal.type_kind == TOK_STRING)
- {
- fprintf(out, "\"%s\"", node->literal.string_val);
- }
- else if (node->literal.type_kind == TOK_CHAR)
- {
- fprintf(out, "%s", node->literal.string_val);
- }
- else if (node->literal.type_kind == 1)
- {
- fprintf(out, "%f", node->literal.float_val);
- }
-
- else
- {
- if (node->literal.int_val > 9223372036854775807ULL)
- {
- fprintf(out, "%lluULL", (unsigned long long)node->literal.int_val);
- }
- else
- {
- fprintf(out, "%llu", (unsigned long long)node->literal.int_val);
- }
- }
- break;
- case NODE_EXPR_CALL:
- {
- if (node->call.callee->type == NODE_EXPR_MEMBER)
- {
- ASTNode *target = node->call.callee->member.target;
- char *method = node->call.callee->member.field;
-
- if (strcmp(method, "len") == 0)
- {
- if (target->type_info && target->type_info->kind == TYPE_ARRAY)
- {
- if (target->type_info->array_size > 0)
- {
- fprintf(out, "%d", target->type_info->array_size);
- }
- else
- {
- codegen_expression(ctx, target, out);
- fprintf(out, ".len");
- }
- return;
- }
- }
-
- char *type = infer_type(ctx, target);
- if (type)
- {
- char *clean = xstrdup(type);
- char *ptr = strchr(clean, '*');
- if (ptr)
- {
- *ptr = 0;
- }
-
- char *base = clean;
- if (strncmp(base, "struct ", 7) == 0)
- {
- base += 7;
- }
-
- if (!strchr(type, '*') && target->type == NODE_EXPR_CALL)
- {
- fprintf(out, "({ %s _t = ", type);
- codegen_expression(ctx, target, out);
- fprintf(out, "; %s_%s(&_t", base, method);
- ASTNode *arg = node->call.args;
- while (arg)
- {
- fprintf(out, ", ");
- codegen_expression(ctx, arg, out);
- arg = arg->next;
- }
- fprintf(out, "); })");
- }
- else
- {
- fprintf(out, "%s_%s(", base, method);
- if (!strchr(type, '*'))
- {
- fprintf(out, "&");
- }
- codegen_expression(ctx, target, out);
- ASTNode *arg = node->call.args;
- while (arg)
- {
- fprintf(out, ", ");
- codegen_expression(ctx, arg, out);
- arg = arg->next;
- }
- fprintf(out, ")");
- }
- free(clean);
- return;
- }
- }
- if (node->call.callee->type == NODE_EXPR_VAR)
- {
- ASTNode *def = find_struct_def(ctx, node->call.callee->var_ref.name);
- if (def && def->type == NODE_STRUCT)
- {
- fprintf(out, "(struct %s){0}", node->call.callee->var_ref.name);
- return;
- }
- }
+ if (sig && sig->arg_types) {
+ for (int p = 0; p < sig->total_args; p++) {
+ ASTNode *arg = node->call.args;
- if (node->call.callee->type_info && node->call.callee->type_info->kind == TYPE_FUNCTION)
- {
- fprintf(out, "({ z_closure_T _c = ");
- codegen_expression(ctx, node->call.callee, out);
- fprintf(out, "; ");
-
- Type *ft = node->call.callee->type_info;
- char *ret = type_to_string(ft->inner);
- if (strcmp(ret, "string") == 0)
- {
- free(ret);
- ret = xstrdup("char*");
- }
+ for (int i = 0; i < node->call.arg_count && arg;
+ i++, arg = arg->next) {
+ if (node->call.arg_names[i] && p < node->call.arg_count) {
- fprintf(out, "((%s (*)(void*", ret);
- for (int i = 0; i < ft->arg_count; i++)
- {
- char *as = type_to_string(ft->args[i]);
- fprintf(out, ", %s", as);
- free(as);
- }
- if (ft->is_varargs)
- {
- fprintf(out, ", ...");
- }
- fprintf(out, "))_c.func)(_c.ctx");
-
- ASTNode *arg = node->call.args;
- while (arg)
- {
- fprintf(out, ", ");
- codegen_expression(ctx, arg, out);
- arg = arg->next;
+ // For now, emit in order provided...
}
- fprintf(out, "); })");
- free(ret);
- break;
+ }
}
+ }
- codegen_expression(ctx, node->call.callee, out);
- fprintf(out, "(");
-
- if (node->call.arg_names && node->call.callee->type == NODE_EXPR_VAR)
- {
- char *fn_name = node->call.callee->var_ref.name;
- FuncSig *sig = find_func(ctx, fn_name);
-
- if (sig && sig->arg_types)
- {
- for (int p = 0; p < sig->total_args; p++)
- {
- ASTNode *arg = node->call.args;
-
- for (int i = 0; i < node->call.arg_count && arg; i++, arg = arg->next)
- {
- if (node->call.arg_names[i] && p < node->call.arg_count)
- {
-
- // For now, emit in order provided...
- }
- }
- }
- }
-
- ASTNode *arg = node->call.args;
- int first = 1;
- while (arg)
- {
- if (!first)
- {
- fprintf(out, ", ");
- }
- first = 0;
- codegen_expression(ctx, arg, out);
- arg = arg->next;
- }
- }
- else
- {
- ASTNode *arg = node->call.args;
- while (arg)
- {
- codegen_expression(ctx, arg, out);
- if (arg->next)
- {
- fprintf(out, ", ");
- }
- arg = arg->next;
- }
+ ASTNode *arg = node->call.args;
+ int first = 1;
+ while (arg) {
+ if (!first) {
+ fprintf(out, ", ");
}
- fprintf(out, ")");
- break;
+ first = 0;
+ codegen_expression(ctx, arg, out);
+ arg = arg->next;
+ }
+ } else {
+ ASTNode *arg = node->call.args;
+ while (arg) {
+ codegen_expression(ctx, arg, out);
+ if (arg->next) {
+ fprintf(out, ", ");
+ }
+ arg = arg->next;
+ }
}
- case NODE_EXPR_MEMBER:
- if (strcmp(node->member.field, "len") == 0)
- {
- if (node->member.target->type_info)
- {
- if (node->member.target->type_info->kind == TYPE_ARRAY)
- {
- if (node->member.target->type_info->array_size > 0)
- {
- fprintf(out, "%d", node->member.target->type_info->array_size);
- break;
- }
- }
- }
- }
-
- if (node->member.is_pointer_access == 2)
- {
- fprintf(out, "({ ");
- emit_auto_type(ctx, node->member.target, node->token, out);
- fprintf(out, " _t = (");
- codegen_expression(ctx, node->member.target, out);
- fprintf(out, "); _t ? _t->%s : 0; })", node->member.field);
- }
- else
- {
- codegen_expression(ctx, node->member.target, out);
- fprintf(out, "%s%s", node->member.is_pointer_access ? "->" : ".", node->member.field);
- }
- break;
- case NODE_EXPR_INDEX:
- {
- int is_slice_struct = 0;
- if (node->index.array->type_info)
- {
- if (node->index.array->type_info->kind == TYPE_ARRAY &&
- node->index.array->type_info->array_size == 0)
- {
- is_slice_struct = 1;
- }
- }
- if (node->index.array->resolved_type)
- {
- if (strncmp(node->index.array->resolved_type, "Slice_", 6) == 0)
- {
- is_slice_struct = 1;
- }
- }
-
- if (is_slice_struct)
- {
- if (node->index.array->type == NODE_EXPR_VAR)
- {
- codegen_expression(ctx, node->index.array, out);
- fprintf(out, ".data[_z_check_bounds(");
- codegen_expression(ctx, node->index.index, out);
- fprintf(out, ", ");
- codegen_expression(ctx, node->index.array, out);
- fprintf(out, ".len)]");
- }
- else
- {
- codegen_expression(ctx, node->index.array, out);
- fprintf(out, ".data[");
- codegen_expression(ctx, node->index.index, out);
- fprintf(out, "]");
- }
+ fprintf(out, ")");
+ break;
+ }
+ case NODE_EXPR_MEMBER:
+ if (strcmp(node->member.field, "len") == 0) {
+ if (node->member.target->type_info) {
+ if (node->member.target->type_info->kind == TYPE_ARRAY) {
+ if (node->member.target->type_info->array_size > 0) {
+ fprintf(out, "%d", node->member.target->type_info->array_size);
+ break;
+ }
}
- else
- {
- int fixed_size = -1;
- if (node->index.array->type_info && node->index.array->type_info->kind == TYPE_ARRAY)
- {
- fixed_size = node->index.array->type_info->array_size;
- }
+ }
+ }
- codegen_expression(ctx, node->index.array, out);
- fprintf(out, "[");
- if (fixed_size > 0)
- {
- fprintf(out, "_z_check_bounds(");
- }
- codegen_expression(ctx, node->index.index, out);
- if (fixed_size > 0)
- {
- fprintf(out, ", %d)", fixed_size);
- }
- fprintf(out, "]");
- }
+ if (node->member.is_pointer_access == 2) {
+ fprintf(out, "({ ");
+ emit_auto_type(ctx, node->member.target, node->token, out);
+ fprintf(out, " _t = (");
+ codegen_expression(ctx, node->member.target, out);
+ fprintf(out, "); _t ? _t->%s : 0; })", node->member.field);
+ } else {
+ codegen_expression(ctx, node->member.target, out);
+ fprintf(out, "%s%s", node->member.is_pointer_access ? "->" : ".",
+ node->member.field);
}
break;
- case NODE_EXPR_SLICE:
- {
- int known_size = -1;
- int is_slice_struct = 0;
- if (node->slice.array->type_info)
- {
- if (node->slice.array->type_info->kind == TYPE_ARRAY)
- {
- known_size = node->slice.array->type_info->array_size;
- if (known_size == 0)
- {
- is_slice_struct = 1;
- }
- }
- }
-
- char *tname = "unknown";
- if (node->type_info && node->type_info->inner)
- {
- tname = type_to_string(node->type_info->inner);
- }
+ case NODE_EXPR_INDEX: {
+ int is_slice_struct = 0;
+ if (node->index.array->type_info) {
+ if (node->index.array->type_info->kind == TYPE_ARRAY &&
+ node->index.array->type_info->array_size == 0) {
+ is_slice_struct = 1;
+ }
+ }
+ if (node->index.array->resolved_type) {
+ if (strncmp(node->index.array->resolved_type, "Slice_", 6) == 0) {
+ is_slice_struct = 1;
+ }
+ }
- fprintf(out, "({ ");
- emit_auto_type(ctx, node->slice.array, node->token, out);
- fprintf(out, " _arr = ");
- codegen_expression(ctx, node->slice.array, out);
- fprintf(out, "; int _start = ");
- if (node->slice.start)
- {
- codegen_expression(ctx, node->slice.start, out);
- }
- else
- {
- fprintf(out, "0");
- }
- fprintf(out, "; int _len = ");
+ if (is_slice_struct) {
+ if (node->index.array->type == NODE_EXPR_VAR) {
+ codegen_expression(ctx, node->index.array, out);
+ fprintf(out, ".data[_z_check_bounds(");
+ codegen_expression(ctx, node->index.index, out);
+ fprintf(out, ", ");
+ codegen_expression(ctx, node->index.array, out);
+ fprintf(out, ".len)]");
+ } else {
+ codegen_expression(ctx, node->index.array, out);
+ fprintf(out, ".data[");
+ codegen_expression(ctx, node->index.index, out);
+ fprintf(out, "]");
+ }
+ } else {
+ int fixed_size = -1;
+ if (node->index.array->type_info &&
+ node->index.array->type_info->kind == TYPE_ARRAY) {
+ fixed_size = node->index.array->type_info->array_size;
+ }
+
+ codegen_expression(ctx, node->index.array, out);
+ fprintf(out, "[");
+ if (fixed_size > 0) {
+ fprintf(out, "_z_check_bounds(");
+ }
+ codegen_expression(ctx, node->index.index, out);
+ if (fixed_size > 0) {
+ fprintf(out, ", %d)", fixed_size);
+ }
+ fprintf(out, "]");
+ }
+ } break;
+ case NODE_EXPR_SLICE: {
+ int known_size = -1;
+ int is_slice_struct = 0;
+ if (node->slice.array->type_info) {
+ if (node->slice.array->type_info->kind == TYPE_ARRAY) {
+ known_size = node->slice.array->type_info->array_size;
+ if (known_size == 0) {
+ is_slice_struct = 1;
+ }
+ }
+ }
- if (node->slice.end)
- {
- codegen_expression(ctx, node->slice.end, out);
- fprintf(out, " - _start; ");
- }
- else
- {
- if (known_size > 0)
- {
- fprintf(out, "%d - _start; ", known_size);
- }
- else if (is_slice_struct)
- {
- fprintf(out, "_arr.len - _start; ");
- }
- else
- {
- fprintf(out, "/* UNSAFE: Full Slice on unknown size */ 0; ");
- }
- }
+ char *tname = "unknown";
+ if (node->type_info && node->type_info->inner) {
+ tname = type_to_string(node->type_info->inner);
+ }
- if (is_slice_struct)
- {
- fprintf(out,
- "(Slice_%s){ .data = _arr.data + _start, .len = _len, .cap = "
- "_len }; })",
- tname);
- }
- else
- {
- fprintf(out, "(Slice_%s){ .data = _arr + _start, .len = _len, .cap = _len }; })",
- tname);
- }
- break;
+ fprintf(out, "({ ");
+ emit_auto_type(ctx, node->slice.array, node->token, out);
+ fprintf(out, " _arr = ");
+ codegen_expression(ctx, node->slice.array, out);
+ fprintf(out, "; int _start = ");
+ if (node->slice.start) {
+ codegen_expression(ctx, node->slice.start, out);
+ } else {
+ fprintf(out, "0");
}
- case NODE_BLOCK:
- {
- int saved = defer_count;
- fprintf(out, "({ ");
- codegen_walker(ctx, node->block.statements, out);
- for (int i = defer_count - 1; i >= saved; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- defer_count = saved;
- fprintf(out, " })");
- break;
+ fprintf(out, "; int _len = ");
+
+ if (node->slice.end) {
+ codegen_expression(ctx, node->slice.end, out);
+ fprintf(out, " - _start; ");
+ } else {
+ if (known_size > 0) {
+ fprintf(out, "%d - _start; ", known_size);
+ } else if (is_slice_struct) {
+ fprintf(out, "_arr.len - _start; ");
+ } else {
+ fprintf(out, "/* UNSAFE: Full Slice on unknown size */ 0; ");
+ }
}
- case NODE_TRY:
- {
- char *type_name = "Result";
- if (g_current_func_ret_type)
- {
- type_name = g_current_func_ret_type;
- }
- else if (node->try_stmt.expr->type_info && node->try_stmt.expr->type_info->name)
- {
- type_name = node->try_stmt.expr->type_info->name;
- }
- if (strcmp(type_name, "__auto_type") == 0 || strcmp(type_name, "unknown") == 0)
- {
- type_name = "Result";
- }
+ if (is_slice_struct) {
+ fprintf(out,
+ "(Slice_%s){ .data = _arr.data + _start, .len = _len, .cap = "
+ "_len }; })",
+ tname);
+ } else {
+ fprintf(
+ out,
+ "(Slice_%s){ .data = _arr + _start, .len = _len, .cap = _len }; })",
+ tname);
+ }
+ break;
+ }
+ case NODE_BLOCK: {
+ int saved = defer_count;
+ fprintf(out, "({ ");
+ codegen_walker(ctx, node->block.statements, out);
+ for (int i = defer_count - 1; i >= saved; i--) {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ defer_count = saved;
+ fprintf(out, " })");
+ break;
+ }
+ case NODE_TRY: {
+ char *type_name = "Result";
+ if (g_current_func_ret_type) {
+ type_name = g_current_func_ret_type;
+ } else if (node->try_stmt.expr->type_info &&
+ node->try_stmt.expr->type_info->name) {
+ type_name = node->try_stmt.expr->type_info->name;
+ }
- char *search_name = type_name;
- if (strncmp(search_name, "struct ", 7) == 0)
- {
- search_name += 7;
- }
+ if (strcmp(type_name, "__auto_type") == 0 ||
+ strcmp(type_name, "unknown") == 0) {
+ type_name = "Result";
+ }
- int is_enum = 0;
- StructRef *er = ctx->parsed_enums_list;
- while (er)
- {
- if (er->node && er->node->type == NODE_ENUM &&
- strcmp(er->node->enm.name, search_name) == 0)
- {
- is_enum = 1;
- break;
- }
- er = er->next;
- }
- if (!is_enum)
- {
- ASTNode *ins = ctx->instantiated_structs;
- while (ins)
- {
- if (ins->type == NODE_ENUM && strcmp(ins->enm.name, search_name) == 0)
- {
- is_enum = 1;
- break;
- }
- ins = ins->next;
- }
- }
+ char *search_name = type_name;
+ if (strncmp(search_name, "struct ", 7) == 0) {
+ search_name += 7;
+ }
- fprintf(out, "({ ");
- emit_auto_type(ctx, node->try_stmt.expr, node->token, out);
- fprintf(out, " _try = ");
- codegen_expression(ctx, node->try_stmt.expr, out);
-
- if (is_enum)
- {
- fprintf(out,
- "; if (_try.tag == %s_Err_Tag) return (%s_Err(_try.data.Err)); "
- "_try.data.Ok; })",
- search_name, search_name);
- }
- else
- {
- fprintf(out,
- "; if (!_try.is_ok) return %s_Err(_try.err); "
- "_try.val; })",
- search_name);
- }
+ int is_enum = 0;
+ StructRef *er = ctx->parsed_enums_list;
+ while (er) {
+ if (er->node && er->node->type == NODE_ENUM &&
+ strcmp(er->node->enm.name, search_name) == 0) {
+ is_enum = 1;
break;
+ }
+ er = er->next;
}
- case NODE_RAW_STMT:
- fprintf(out, "%s", node->raw_stmt.content);
- break;
- case NODE_PLUGIN:
- {
- // Plugin registry - declare external plugins
- ZPlugin *found = zptr_find_plugin(node->plugin_stmt.plugin_name);
-
- if (found)
- {
- ZApi api = {.filename = g_current_filename ? g_current_filename : "input.zc",
- .current_line = node->line,
- .out = out,
- .hoist_out = ctx->hoist_out};
- found->fn(node->plugin_stmt.body, &api);
- }
- else
- {
- fprintf(out, "/* Unknown plugin: %s */\n", node->plugin_stmt.plugin_name);
- }
- break;
+ if (!is_enum) {
+ ASTNode *ins = ctx->instantiated_structs;
+ while (ins) {
+ if (ins->type == NODE_ENUM && strcmp(ins->enm.name, search_name) == 0) {
+ is_enum = 1;
+ break;
+ }
+ ins = ins->next;
+ }
}
- case NODE_EXPR_UNARY:
- if (node->unary.op && strcmp(node->unary.op, "&_rval") == 0)
- {
- fprintf(out, "({ ");
- emit_auto_type(ctx, node->unary.operand, node->token, out);
- fprintf(out, " _t = (");
- codegen_expression(ctx, node->unary.operand, out);
- fprintf(out, "); &_t; })");
- }
- else if (node->unary.op && strcmp(node->unary.op, "?") == 0)
- {
- fprintf(out, "({ ");
- emit_auto_type(ctx, node->unary.operand, node->token, out);
- fprintf(out, " _t = (");
- codegen_expression(ctx, node->unary.operand, out);
- fprintf(out, "); if (_t.tag != 0) return _t; _t.data.Ok; })");
- }
- else if (node->unary.op && strcmp(node->unary.op, "_post++") == 0)
- {
- fprintf(out, "(");
- codegen_expression(ctx, node->unary.operand, out);
- fprintf(out, "++)");
- }
- else if (node->unary.op && strcmp(node->unary.op, "_post--") == 0)
- {
- fprintf(out, "(");
- codegen_expression(ctx, node->unary.operand, out);
- fprintf(out, "--)");
- }
- else
- {
- fprintf(out, "(%s", node->unary.op);
- codegen_expression(ctx, node->unary.operand, out);
- fprintf(out, ")");
- }
- break;
- case NODE_EXPR_CAST:
- fprintf(out, "(%s)(", node->cast.target_type);
- codegen_expression(ctx, node->cast.expr, out);
- fprintf(out, ")");
- break;
- case NODE_EXPR_SIZEOF:
- if (node->size_of.target_type)
- {
- fprintf(out, "sizeof(%s)", node->size_of.target_type);
- }
- else
- {
- fprintf(out, "sizeof(");
- codegen_expression(ctx, node->size_of.expr, out);
- fprintf(out, ")");
- }
- break;
- case NODE_TYPEOF:
- if (node->size_of.target_type)
- {
- fprintf(out, "typeof(%s)", node->size_of.target_type);
- }
- else
- {
- fprintf(out, "typeof(");
- codegen_expression(ctx, node->size_of.expr, out);
- fprintf(out, ")");
- }
- break;
-
- case NODE_REFLECTION:
- {
- Type *t = node->reflection.target_type;
- if (node->reflection.kind == 0)
- { // @type_name
- char *s = type_to_string(t);
- fprintf(out, "\"%s\"", s);
- free(s);
- }
- else
- { // @fields
- if (t->kind != TYPE_STRUCT || !t->name)
- {
- fprintf(out, "((void*)0)");
- break;
- }
- char *sname = t->name;
- // Find definition
- ASTNode *def = find_struct_def(ctx, sname);
- if (!def)
- {
- fprintf(out, "((void*)0)");
- break;
- }
- fprintf(out,
- "({ static struct { char *name; char *type; unsigned long offset; } "
- "_fields_%s[] = {",
- sname);
- ASTNode *f = def->strct.fields;
- while (f)
- {
- if (f->type == NODE_FIELD)
- {
- fprintf(out, "{ \"%s\", \"%s\", __builtin_offsetof(struct %s, %s) }, ",
- f->field.name, f->field.type, sname, f->field.name);
- }
- f = f->next;
- }
- fprintf(out, "{ 0 } }; (void*)_fields_%s; })", sname);
- }
- break;
+ fprintf(out, "({ ");
+ emit_auto_type(ctx, node->try_stmt.expr, node->token, out);
+ fprintf(out, " _try = ");
+ codegen_expression(ctx, node->try_stmt.expr, out);
+
+ if (is_enum) {
+ fprintf(out,
+ "; if (_try.tag == %s_Err_Tag) return (%s_Err(_try.data.Err)); "
+ "_try.data.Ok; })",
+ search_name, search_name);
+ } else {
+ fprintf(out,
+ "; if (!_try.is_ok) return %s_Err(_try.err); "
+ "_try.val; })",
+ search_name);
}
- case NODE_EXPR_STRUCT_INIT:
- {
- const char *struct_name = node->struct_init.struct_name;
- if (strcmp(struct_name, "Self") == 0 && g_current_impl_type)
- {
- struct_name = g_current_impl_type;
- }
- fprintf(out, "(struct %s){", struct_name);
- ASTNode *f = node->struct_init.fields;
- while (f)
- {
- fprintf(out, ".%s = ", f->var_decl.name);
- codegen_expression(ctx, f->var_decl.init_expr, out);
- if (f->next)
- {
- fprintf(out, ", ");
- }
- f = f->next;
- }
- fprintf(out, "}");
- break;
+ break;
+ }
+ case NODE_RAW_STMT:
+ fprintf(out, "%s", node->raw_stmt.content);
+ break;
+ case NODE_PLUGIN: {
+ // Plugin registry - declare external plugins
+ ZPlugin *found = zptr_find_plugin(node->plugin_stmt.plugin_name);
+
+ if (found) {
+ ZApi api = {.filename =
+ g_current_filename ? g_current_filename : "input.zc",
+ .current_line = node->line,
+ .out = out,
+ .hoist_out = ctx->hoist_out};
+ found->fn(node->plugin_stmt.body, &api);
+ } else {
+ fprintf(out, "/* Unknown plugin: %s */\n", node->plugin_stmt.plugin_name);
}
- case NODE_EXPR_ARRAY_LITERAL:
- fprintf(out, "{");
- ASTNode *elem = node->array_literal.elements;
- int first = 1;
- while (elem)
- {
- if (!first)
- {
- fprintf(out, ", ");
- }
- codegen_expression(ctx, elem, out);
- elem = elem->next;
- first = 0;
- }
- fprintf(out, "}");
+ break;
+ }
+ case NODE_EXPR_UNARY:
+ if (node->unary.op && strcmp(node->unary.op, "&_rval") == 0) {
+ fprintf(out, "({ ");
+ emit_auto_type(ctx, node->unary.operand, node->token, out);
+ fprintf(out, " _t = (");
+ codegen_expression(ctx, node->unary.operand, out);
+ fprintf(out, "); &_t; })");
+ } else if (node->unary.op && strcmp(node->unary.op, "?") == 0) {
+ fprintf(out, "({ ");
+ emit_auto_type(ctx, node->unary.operand, node->token, out);
+ fprintf(out, " _t = (");
+ codegen_expression(ctx, node->unary.operand, out);
+ fprintf(out, "); if (_t.tag != 0) return _t; _t.data.Ok; })");
+ } else if (node->unary.op && strcmp(node->unary.op, "_post++") == 0) {
+ fprintf(out, "(");
+ codegen_expression(ctx, node->unary.operand, out);
+ fprintf(out, "++)");
+ } else if (node->unary.op && strcmp(node->unary.op, "_post--") == 0) {
+ fprintf(out, "(");
+ codegen_expression(ctx, node->unary.operand, out);
+ fprintf(out, "--)");
+ } else {
+ fprintf(out, "(%s", node->unary.op);
+ codegen_expression(ctx, node->unary.operand, out);
+ fprintf(out, ")");
+ }
+ break;
+ case NODE_EXPR_CAST:
+ fprintf(out, "(%s)(", node->cast.target_type);
+ codegen_expression(ctx, node->cast.expr, out);
+ fprintf(out, ")");
+ break;
+ case NODE_EXPR_SIZEOF:
+ if (node->size_of.target_type) {
+ fprintf(out, "sizeof(%s)", node->size_of.target_type);
+ } else {
+ fprintf(out, "sizeof(");
+ codegen_expression(ctx, node->size_of.expr, out);
+ fprintf(out, ")");
+ }
+ break;
+ case NODE_TYPEOF:
+ if (node->size_of.target_type) {
+ fprintf(out, "typeof(%s)", node->size_of.target_type);
+ } else {
+ fprintf(out, "typeof(");
+ codegen_expression(ctx, node->size_of.expr, out);
+ fprintf(out, ")");
+ }
+ break;
+
+ case NODE_REFLECTION: {
+ Type *t = node->reflection.target_type;
+ if (node->reflection.kind == 0) { // @type_name
+ char *s = type_to_string(t);
+ fprintf(out, "\"%s\"", s);
+ free(s);
+ } else { // @fields
+ if (t->kind != TYPE_STRUCT || !t->name) {
+ fprintf(out, "((void*)0)");
break;
- case NODE_TERNARY:
- fprintf(out, "((");
- codegen_expression(ctx, node->ternary.cond, out);
- fprintf(out, ") ? (");
- codegen_expression(ctx, node->ternary.true_expr, out);
- fprintf(out, ") : (");
- codegen_expression(ctx, node->ternary.false_expr, out);
- fprintf(out, "))");
+ }
+ char *sname = t->name;
+ // Find definition
+ ASTNode *def = find_struct_def(ctx, sname);
+ if (!def) {
+ fprintf(out, "((void*)0)");
break;
- case NODE_AWAIT:
- {
- char *ret_type = "void*";
- int free_ret = 0;
- if (node->type_info)
- {
- char *t = type_to_string(node->type_info);
- if (t)
- {
- ret_type = t;
- free_ret = 1;
- }
- }
- else if (node->resolved_type)
- {
- ret_type = node->resolved_type;
- }
+ }
+
+ fprintf(
+ out,
+ "({ static struct { char *name; char *type; unsigned long offset; } "
+ "_fields_%s[] = {",
+ sname);
+ ASTNode *f = def->strct.fields;
+ while (f) {
+ if (f->type == NODE_FIELD) {
+ fprintf(out,
+ "{ \"%s\", \"%s\", __builtin_offsetof(struct %s, %s) }, ",
+ f->field.name, f->field.type, sname, f->field.name);
+ }
+ f = f->next;
+ }
+ fprintf(out, "{ 0 } }; (void*)_fields_%s; })", sname);
+ }
+ break;
+ }
+ case NODE_EXPR_STRUCT_INIT: {
+ const char *struct_name = node->struct_init.struct_name;
+ if (strcmp(struct_name, "Self") == 0 && g_current_impl_type) {
+ struct_name = g_current_impl_type;
+ }
+ fprintf(out, "(struct %s){", struct_name);
+ ASTNode *f = node->struct_init.fields;
+ while (f) {
+ fprintf(out, ".%s = ", f->var_decl.name);
+ codegen_expression(ctx, f->var_decl.init_expr, out);
+ if (f->next) {
+ fprintf(out, ", ");
+ }
+ f = f->next;
+ }
+ fprintf(out, "}");
+ break;
+ }
+ case NODE_EXPR_ARRAY_LITERAL:
+ fprintf(out, "{");
+ ASTNode *elem = node->array_literal.elements;
+ int first = 1;
+ while (elem) {
+ if (!first) {
+ fprintf(out, ", ");
+ }
+ codegen_expression(ctx, elem, out);
+ elem = elem->next;
+ first = 0;
+ }
+ fprintf(out, "}");
+ break;
+ case NODE_TERNARY:
+ fprintf(out, "((");
+ codegen_expression(ctx, node->ternary.cond, out);
+ fprintf(out, ") ? (");
+ codegen_expression(ctx, node->ternary.true_expr, out);
+ fprintf(out, ") : (");
+ codegen_expression(ctx, node->ternary.false_expr, out);
+ fprintf(out, "))");
+ break;
+ case NODE_AWAIT: {
+ char *ret_type = "void*";
+ int free_ret = 0;
+ if (node->type_info) {
+ char *t = type_to_string(node->type_info);
+ if (t) {
+ ret_type = t;
+ free_ret = 1;
+ }
+ } else if (node->resolved_type) {
+ ret_type = node->resolved_type;
+ }
- if (strcmp(ret_type, "Async") == 0 || strcmp(ret_type, "void*") == 0)
- {
- char *inf = infer_type(ctx, node);
- if (inf && strcmp(inf, "Async") != 0 && strcmp(inf, "void*") != 0)
- {
- if (free_ret)
- {
- free(ret_type);
- }
- ret_type = inf;
- free_ret = 0;
- }
+ if (strcmp(ret_type, "Async") == 0 || strcmp(ret_type, "void*") == 0) {
+ char *inf = infer_type(ctx, node);
+ if (inf && strcmp(inf, "Async") != 0 && strcmp(inf, "void*") != 0) {
+ if (free_ret) {
+ free(ret_type);
}
+ ret_type = inf;
+ free_ret = 0;
+ }
+ }
- int needs_long_cast = 0;
- int returns_struct = 0;
- if (strstr(ret_type, "*") == NULL && strcmp(ret_type, "string") != 0 &&
- strcmp(ret_type, "void") != 0 && strcmp(ret_type, "Async") != 0)
- {
- if (strcmp(ret_type, "int") != 0 && strcmp(ret_type, "bool") != 0 &&
- strcmp(ret_type, "char") != 0 && strcmp(ret_type, "float") != 0 &&
- strcmp(ret_type, "double") != 0 && strcmp(ret_type, "long") != 0 &&
- strcmp(ret_type, "usize") != 0 && strcmp(ret_type, "isize") != 0 &&
- strncmp(ret_type, "uint", 4) != 0 && strncmp(ret_type, "int", 3) != 0)
- {
- returns_struct = 1;
- }
- else
- {
- needs_long_cast = 1;
- }
- if (strncmp(ret_type, "struct", 6) == 0)
- {
- returns_struct = 1;
- }
- }
+ int needs_long_cast = 0;
+ int returns_struct = 0;
+ if (strstr(ret_type, "*") == NULL && strcmp(ret_type, "string") != 0 &&
+ strcmp(ret_type, "void") != 0 && strcmp(ret_type, "Async") != 0) {
+ if (strcmp(ret_type, "int") != 0 && strcmp(ret_type, "bool") != 0 &&
+ strcmp(ret_type, "char") != 0 && strcmp(ret_type, "float") != 0 &&
+ strcmp(ret_type, "double") != 0 && strcmp(ret_type, "long") != 0 &&
+ strcmp(ret_type, "usize") != 0 && strcmp(ret_type, "isize") != 0 &&
+ strncmp(ret_type, "uint", 4) != 0 &&
+ strncmp(ret_type, "int", 3) != 0) {
+ returns_struct = 1;
+ } else {
+ needs_long_cast = 1;
+ }
+ if (strncmp(ret_type, "struct", 6) == 0) {
+ returns_struct = 1;
+ }
+ }
- fprintf(out, "({ Async _a = ");
- codegen_expression(ctx, node->unary.operand, out);
- fprintf(out, "; void* _r; pthread_join(_a.thread, &_r); ");
- if (strcmp(ret_type, "void") == 0)
- {
- fprintf(out, "})");
- }
- else
- {
- if (returns_struct)
- {
- fprintf(out, "%s _val = *(%s*)_r; free(_r); _val; })", ret_type, ret_type);
- }
- else
- {
- if (needs_long_cast)
- {
- fprintf(out, "(%s)(long)_r; })", ret_type);
- }
- else
- {
- fprintf(out, "(%s)_r; })", ret_type);
- }
- }
- }
- if (free_ret)
- {
- free(ret_type);
- }
- break;
+ fprintf(out, "({ Async _a = ");
+ codegen_expression(ctx, node->unary.operand, out);
+ fprintf(out, "; void* _r; pthread_join(_a.thread, &_r); ");
+ if (strcmp(ret_type, "void") == 0) {
+ fprintf(out, "})");
+ } else {
+ if (returns_struct) {
+ fprintf(out, "%s _val = *(%s*)_r; free(_r); _val; })", ret_type,
+ ret_type);
+ } else {
+ if (needs_long_cast) {
+ fprintf(out, "(%s)(long)_r; })", ret_type);
+ } else {
+ fprintf(out, "(%s)_r; })", ret_type);
+ }
+ }
}
- default:
- break;
+ if (free_ret) {
+ free(ret_type);
}
+ break;
+ }
+ default:
+ break;
+ }
}
-void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
-{
- if (!node)
- {
- return;
+void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) {
+ if (!node) {
+ return;
+ }
+ switch (node->type) {
+ case NODE_MATCH:
+ codegen_match_internal(ctx, node, out, 0); // 0 = statement context
+ fprintf(out, ";\n");
+ break;
+ case NODE_FUNCTION:
+ if (!node->func.body) {
+ break;
}
- switch (node->type)
- {
- case NODE_MATCH:
- codegen_match_internal(ctx, node, out, 0); // 0 = statement context
- fprintf(out, ";\n");
- break;
- case NODE_FUNCTION:
- if (!node->func.body)
- {
- break;
- }
- if (node->func.is_async)
- {
- fprintf(out, "struct %s_Args {\n", node->func.name);
- char *args_copy = xstrdup(node->func.args);
- char *token = strtok(args_copy, ",");
- int arg_count = 0;
- char **arg_names = xmalloc(32 * sizeof(char *));
-
- while (token)
- {
- while (*token == ' ')
- {
- token++; // trim leading
- }
- char *last_space = strrchr(token, ' ');
- if (last_space)
- {
- *last_space = 0;
- char *type = token;
- char *name = last_space + 1;
- fprintf(out, "%s %s;\n", type, name);
-
- arg_names[arg_count++] = xstrdup(name);
- }
- token = strtok(NULL, ",");
- }
- free(args_copy);
- fprintf(out, "};\n");
-
- fprintf(out, "void* _runner_%s(void* _args)\n", node->func.name);
- fprintf(out, "{\n");
- fprintf(out, " struct %s_Args* args = (struct %s_Args*)_args;\n", node->func.name,
- node->func.name);
-
- // Determine mechanism: struct/large-type? -> malloc; primitive -> cast
- int returns_struct = 0;
- char *rt = node->func.ret_type;
- if (strcmp(rt, "void") != 0 && strcmp(rt, "Async") != 0)
- {
- if (strstr(rt, "*") == NULL && strcmp(rt, "string") != 0 &&
- strcmp(rt, "int") != 0 && strcmp(rt, "bool") != 0 && strcmp(rt, "char") != 0 &&
- strcmp(rt, "float") != 0 && strcmp(rt, "double") != 0 &&
- strcmp(rt, "long") != 0 && strcmp(rt, "usize") != 0 &&
- strcmp(rt, "isize") != 0 && strncmp(rt, "uint", 4) != 0 &&
- strncmp(rt, "int", 3) != 0)
- {
- returns_struct = 1;
- }
- }
-
- // Call Impl
- if (returns_struct)
- {
- fprintf(out, " %s *res_ptr = malloc(sizeof(%s));\n", rt, rt);
- fprintf(out, " *res_ptr = ");
- }
- else if (strcmp(rt, "void") != 0 && strcmp(rt, "Async") != 0)
- {
- fprintf(out, " %s res = ", rt);
- }
- else
- {
- fprintf(out, " ");
- }
-
- fprintf(out, "_impl_%s(", node->func.name);
- for (int i = 0; i < arg_count; i++)
- {
- fprintf(out, "%sargs->%s", i > 0 ? ", " : "", arg_names[i]);
- }
- fprintf(out, ");\n");
- fprintf(out, " free(args);\n");
-
- if (returns_struct)
- {
- fprintf(out, " return (void*)res_ptr;\n");
- }
- else if (strcmp(rt, "void") != 0)
- {
- fprintf(out, " return (void*)(long)res;\n");
- }
- else
- {
- fprintf(out, " return NULL;\n");
- }
- fprintf(out, "}\n");
-
- fprintf(out, "%s _impl_%s(%s)\n", node->func.ret_type, node->func.name,
- node->func.args);
- fprintf(out, "{\n");
- defer_count = 0;
- codegen_walker(ctx, node->func.body, out);
- for (int i = defer_count - 1; i >= 0; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- fprintf(out, "}\n");
-
- // 4. Define Public Wrapper (Spawns Thread)
- fprintf(out, "Async %s(%s)\n", node->func.name, node->func.args);
- fprintf(out, "{\n");
- fprintf(out, " struct %s_Args* args = malloc(sizeof(struct %s_Args));\n",
- node->func.name, node->func.name);
- for (int i = 0; i < arg_count; i++)
- {
- fprintf(out, " args->%s = %s;\n", arg_names[i], arg_names[i]);
- }
+ if (node->func.is_async) {
+ fprintf(out, "struct %s_Args {\n", node->func.name);
+ char *args_copy = xstrdup(node->func.args);
+ char *token = strtok(args_copy, ",");
+ int arg_count = 0;
+ char **arg_names = xmalloc(32 * sizeof(char *));
+
+ while (token) {
+ while (*token == ' ') {
+ token++; // trim leading
+ }
+ char *last_space = strrchr(token, ' ');
+ if (last_space) {
+ *last_space = 0;
+ char *type = token;
+ char *name = last_space + 1;
+ fprintf(out, "%s %s;\n", type, name);
+
+ arg_names[arg_count++] = xstrdup(name);
+ }
+ token = strtok(NULL, ",");
+ }
+ free(args_copy);
+ fprintf(out, "};\n");
+
+ fprintf(out, "void* _runner_%s(void* _args)\n", node->func.name);
+ fprintf(out, "{\n");
+ fprintf(out, " struct %s_Args* args = (struct %s_Args*)_args;\n",
+ node->func.name, node->func.name);
+
+ // Determine mechanism: struct/large-type? -> malloc; primitive -> cast
+ int returns_struct = 0;
+ char *rt = node->func.ret_type;
+ if (strcmp(rt, "void") != 0 && strcmp(rt, "Async") != 0) {
+ if (strstr(rt, "*") == NULL && strcmp(rt, "string") != 0 &&
+ strcmp(rt, "int") != 0 && strcmp(rt, "bool") != 0 &&
+ strcmp(rt, "char") != 0 && strcmp(rt, "float") != 0 &&
+ strcmp(rt, "double") != 0 && strcmp(rt, "long") != 0 &&
+ strcmp(rt, "usize") != 0 && strcmp(rt, "isize") != 0 &&
+ strncmp(rt, "uint", 4) != 0 && strncmp(rt, "int", 3) != 0) {
+ returns_struct = 1;
+ }
+ }
+
+ // Call Impl
+ if (returns_struct) {
+ fprintf(out, " %s *res_ptr = malloc(sizeof(%s));\n", rt, rt);
+ fprintf(out, " *res_ptr = ");
+ } else if (strcmp(rt, "void") != 0 && strcmp(rt, "Async") != 0) {
+ fprintf(out, " %s res = ", rt);
+ } else {
+ fprintf(out, " ");
+ }
+
+ fprintf(out, "_impl_%s(", node->func.name);
+ for (int i = 0; i < arg_count; i++) {
+ fprintf(out, "%sargs->%s", i > 0 ? ", " : "", arg_names[i]);
+ }
+ fprintf(out, ");\n");
+ fprintf(out, " free(args);\n");
+
+ if (returns_struct) {
+ fprintf(out, " return (void*)res_ptr;\n");
+ } else if (strcmp(rt, "void") != 0) {
+ fprintf(out, " return (void*)(long)res;\n");
+ } else {
+ fprintf(out, " return NULL;\n");
+ }
+ fprintf(out, "}\n");
+
+ fprintf(out, "%s _impl_%s(%s)\n", node->func.ret_type, node->func.name,
+ node->func.args);
+ fprintf(out, "{\n");
+ defer_count = 0;
+ codegen_walker(ctx, node->func.body, out);
+ for (int i = defer_count - 1; i >= 0; i--) {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ fprintf(out, "}\n");
+
+ // 4. Define Public Wrapper (Spawns Thread)
+ fprintf(out, "Async %s(%s)\n", node->func.name, node->func.args);
+ fprintf(out, "{\n");
+ fprintf(out,
+ " struct %s_Args* args = malloc(sizeof(struct %s_Args));\n",
+ node->func.name, node->func.name);
+ for (int i = 0; i < arg_count; i++) {
+ fprintf(out, " args->%s = %s;\n", arg_names[i], arg_names[i]);
+ }
+
+ fprintf(out, " pthread_t th;\n");
+ fprintf(out, " pthread_create(&th, NULL, _runner_%s, args);\n",
+ node->func.name);
+ fprintf(out, " return (Async){.thread=th, .result=NULL};\n");
+ fprintf(out, "}\n");
+
+ break;
+ }
- fprintf(out, " pthread_t th;\n");
- fprintf(out, " pthread_create(&th, NULL, _runner_%s, args);\n", node->func.name);
- fprintf(out, " return (Async){.thread=th, .result=NULL};\n");
- fprintf(out, "}\n");
+ defer_count = 0;
+ fprintf(out, "\n");
- break;
+ // Emit GCC attributes before function
+ {
+ int has_attrs = node->func.constructor || node->func.destructor ||
+ node->func.noinline || node->func.unused ||
+ node->func.weak || node->func.cold || node->func.hot ||
+ node->func.noreturn || node->func.pure ||
+ node->func.section;
+ if (has_attrs) {
+ fprintf(out, "__attribute__((");
+ int first = 1;
+#define EMIT_ATTR(cond, name) \
+ if (cond) { \
+ if (!first) \
+ fprintf(out, ", "); \
+ fprintf(out, name); \
+ first = 0; \
+ }
+ EMIT_ATTR(node->func.constructor, "constructor");
+ EMIT_ATTR(node->func.destructor, "destructor");
+ EMIT_ATTR(node->func.noinline, "noinline");
+ EMIT_ATTR(node->func.unused, "unused");
+ EMIT_ATTR(node->func.weak, "weak");
+ EMIT_ATTR(node->func.cold, "cold");
+ EMIT_ATTR(node->func.hot, "hot");
+ EMIT_ATTR(node->func.noreturn, "noreturn");
+ EMIT_ATTR(node->func.pure, "pure");
+ if (node->func.section) {
+ if (!first) {
+ fprintf(out, ", ");
+ }
+ fprintf(out, "section(\"%s%s%s\")", SEGMENT_NAME_PREFIX,
+ node->func.section, SEGMENT_NAME_SUFFIX);
}
-
- defer_count = 0;
- fprintf(out, "\n");
-
- // Emit GCC attributes before function
- {
- int has_attrs = node->func.constructor || node->func.destructor ||
- node->func.noinline || node->func.unused || node->func.weak ||
- node->func.cold || node->func.hot || node->func.noreturn ||
- node->func.pure || node->func.section;
- if (has_attrs)
- {
- fprintf(out, "__attribute__((");
- int first = 1;
-#define EMIT_ATTR(cond, name) \
- if (cond) \
- { \
- if (!first) \
- fprintf(out, ", "); \
- fprintf(out, name); \
- first = 0; \
- }
- EMIT_ATTR(node->func.constructor, "constructor");
- EMIT_ATTR(node->func.destructor, "destructor");
- EMIT_ATTR(node->func.noinline, "noinline");
- EMIT_ATTR(node->func.unused, "unused");
- EMIT_ATTR(node->func.weak, "weak");
- EMIT_ATTR(node->func.cold, "cold");
- EMIT_ATTR(node->func.hot, "hot");
- EMIT_ATTR(node->func.noreturn, "noreturn");
- EMIT_ATTR(node->func.pure, "pure");
- if (node->func.section)
- {
- if (!first)
- {
- fprintf(out, ", ");
- }
- fprintf(out, "section(\"%s%s%s\")", SEGMENT_NAME_PREFIX, node->func.section, SEGMENT_NAME_SUFFIX);
- }
#undef EMIT_ATTR
- fprintf(out, ")) ");
- }
- }
-
- if (node->func.is_inline)
- {
- fprintf(out, "inline ");
- }
- fprintf(out, "%s %s(%s)\n", node->func.ret_type, node->func.name, node->func.args);
- fprintf(out, "{\n");
- char *prev_ret = g_current_func_ret_type;
- g_current_func_ret_type = node->func.ret_type;
- codegen_walker(ctx, node->func.body, out);
- for (int i = defer_count - 1; i >= 0; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- g_current_func_ret_type = prev_ret;
- fprintf(out, "}\n");
- break;
-
- case NODE_DEFER:
- if (defer_count < MAX_DEFER)
- {
- defer_stack[defer_count++] = node->defer_stmt.stmt;
- }
- break;
- case NODE_IMPL:
- g_current_impl_type = node->impl.struct_name;
- codegen_walker(ctx, node->impl.methods, out);
- g_current_impl_type = NULL;
- break;
- case NODE_IMPL_TRAIT:
- g_current_impl_type = node->impl_trait.target_type;
- codegen_walker(ctx, node->impl_trait.methods, out);
-
- if (strcmp(node->impl_trait.trait_name, "Drop") == 0)
- {
- char *tname = node->impl_trait.target_type;
- fprintf(out, "\n// RAII Glue\n");
- fprintf(out, "void %s_Drop_glue(%s *self) {\n", tname, tname);
- fprintf(out, " %s_Drop_drop(self);\n", tname);
- fprintf(out, "}\n");
- }
- g_current_impl_type = NULL;
- break;
- case NODE_DESTRUCT_VAR:
- {
- int id = tmp_counter++;
- fprintf(out, " ");
- emit_auto_type(ctx, node->destruct.init_expr, node->token, out);
- fprintf(out, " _tmp_%d = ", id);
- codegen_expression(ctx, node->destruct.init_expr, out);
- fprintf(out, ";\n");
-
- if (node->destruct.is_guard)
- {
- // var Some(val) = opt else ...
- char *variant = node->destruct.guard_variant;
- char *check = "val"; // field to access
-
- if (strcmp(variant, "Some") == 0)
- {
- fprintf(out, " if (!_tmp_%d.is_some) {\n", id);
- }
- else if (strcmp(variant, "Ok") == 0)
- {
- fprintf(out, " if (!_tmp_%d.is_ok) {\n", id);
- }
- else if (strcmp(variant, "Err") == 0)
- {
- fprintf(out, " if (_tmp_%d.is_ok) {\n", id); // Err if NOT ok
- check = "err";
- }
- else
- {
- // Generic guard? Assume .is_variant present?
- fprintf(out, " if (!_tmp_%d.is_%s) {\n", id, variant);
- }
+ fprintf(out, ")) ");
+ }
+ }
- // Else block
- codegen_walker(ctx, node->destruct.else_block->block.statements, out);
- fprintf(out, " }\n");
+ if (node->func.is_inline) {
+ fprintf(out, "inline ");
+ }
+ fprintf(out, "%s %s(%s)\n", node->func.ret_type, node->func.name,
+ node->func.args);
+ fprintf(out, "{\n");
+ char *prev_ret = g_current_func_ret_type;
+ g_current_func_ret_type = node->func.ret_type;
+ codegen_walker(ctx, node->func.body, out);
+ for (int i = defer_count - 1; i >= 0; i--) {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ g_current_func_ret_type = prev_ret;
+ fprintf(out, "}\n");
+ break;
- // Bind value
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, " __typeof__(_tmp_%d.%s) %s = _tmp_%d.%s;\n", id, check,
- node->destruct.names[0], id, check);
- }
- else
- {
- fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[0], id,
- check);
- }
- }
- else
- {
- for (int i = 0; i < node->destruct.count; i++)
- {
- if (node->destruct.is_struct_destruct)
- {
- char *field = node->destruct.field_names ? node->destruct.field_names[i]
- : node->destruct.names[i];
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, " __typeof__(_tmp_%d.%s) %s = _tmp_%d.%s;\n", id, field,
- node->destruct.names[i], id, field);
- }
- else
- {
- fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[i],
- id, field);
- }
- }
- else
- {
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, " __typeof__(_tmp_%d.v%d) %s = _tmp_%d.v%d;\n", id, i,
- node->destruct.names[i], id, i);
- }
- else
- {
- fprintf(out, " __auto_type %s = _tmp_%d.v%d;\n", node->destruct.names[i],
- id, i);
- }
- }
- }
- }
- break;
+ case NODE_DEFER:
+ if (defer_count < MAX_DEFER) {
+ defer_stack[defer_count++] = node->defer_stmt.stmt;
+ }
+ break;
+ case NODE_IMPL:
+ g_current_impl_type = node->impl.struct_name;
+ codegen_walker(ctx, node->impl.methods, out);
+ g_current_impl_type = NULL;
+ break;
+ case NODE_IMPL_TRAIT:
+ g_current_impl_type = node->impl_trait.target_type;
+ codegen_walker(ctx, node->impl_trait.methods, out);
+
+ if (strcmp(node->impl_trait.trait_name, "Drop") == 0) {
+ char *tname = node->impl_trait.target_type;
+ fprintf(out, "\n// RAII Glue\n");
+ fprintf(out, "void %s_Drop_glue(%s *self) {\n", tname, tname);
+ fprintf(out, " %s_Drop_drop(self);\n", tname);
+ fprintf(out, "}\n");
+ }
+ g_current_impl_type = NULL;
+ break;
+ case NODE_DESTRUCT_VAR: {
+ int id = tmp_counter++;
+ fprintf(out, " ");
+ emit_auto_type(ctx, node->destruct.init_expr, node->token, out);
+ fprintf(out, " _tmp_%d = ", id);
+ codegen_expression(ctx, node->destruct.init_expr, out);
+ fprintf(out, ";\n");
+
+ if (node->destruct.is_guard) {
+ // var Some(val) = opt else ...
+ char *variant = node->destruct.guard_variant;
+ char *check = "val"; // field to access
+
+ if (strcmp(variant, "Some") == 0) {
+ fprintf(out, " if (!_tmp_%d.is_some) {\n", id);
+ } else if (strcmp(variant, "Ok") == 0) {
+ fprintf(out, " if (!_tmp_%d.is_ok) {\n", id);
+ } else if (strcmp(variant, "Err") == 0) {
+ fprintf(out, " if (_tmp_%d.is_ok) {\n", id); // Err if NOT ok
+ check = "err";
+ } else {
+ // Generic guard? Assume .is_variant present?
+ fprintf(out, " if (!_tmp_%d.is_%s) {\n", id, variant);
+ }
+
+ // Else block
+ codegen_walker(ctx, node->destruct.else_block->block.statements, out);
+ fprintf(out, " }\n");
+
+ // Bind value
+ if (strstr(g_config.cc, "tcc")) {
+ fprintf(out, " __typeof__(_tmp_%d.%s) %s = _tmp_%d.%s;\n", id, check,
+ node->destruct.names[0], id, check);
+ } else {
+ fprintf(out, " __auto_type %s = _tmp_%d.%s;\n",
+ node->destruct.names[0], id, check);
+ }
+ } else {
+ for (int i = 0; i < node->destruct.count; i++) {
+ if (node->destruct.is_struct_destruct) {
+ char *field = node->destruct.field_names
+ ? node->destruct.field_names[i]
+ : node->destruct.names[i];
+ if (strstr(g_config.cc, "tcc")) {
+ fprintf(out, " __typeof__(_tmp_%d.%s) %s = _tmp_%d.%s;\n", id,
+ field, node->destruct.names[i], id, field);
+ } else {
+ fprintf(out, " __auto_type %s = _tmp_%d.%s;\n",
+ node->destruct.names[i], id, field);
+ }
+ } else {
+ if (strstr(g_config.cc, "tcc")) {
+ fprintf(out, " __typeof__(_tmp_%d.v%d) %s = _tmp_%d.v%d;\n", id,
+ i, node->destruct.names[i], id, i);
+ } else {
+ fprintf(out, " __auto_type %s = _tmp_%d.v%d;\n",
+ node->destruct.names[i], id, i);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case NODE_BLOCK: {
+ int saved = defer_count;
+ fprintf(out, " {\n");
+ codegen_walker(ctx, node->block.statements, out);
+ for (int i = defer_count - 1; i >= saved; i--) {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ defer_count = saved;
+ fprintf(out, " }\n");
+ break;
+ }
+ case NODE_VAR_DECL:
+ fprintf(out, " ");
+ if (node->var_decl.is_static) {
+ fprintf(out, "static ");
+ }
+ if (node->var_decl.is_autofree) {
+ fprintf(out, "__attribute__((cleanup(_z_autofree_impl))) ");
}
- case NODE_BLOCK:
{
- int saved = defer_count;
- fprintf(out, " {\n");
- codegen_walker(ctx, node->block.statements, out);
- for (int i = defer_count - 1; i >= saved; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
- defer_count = saved;
- fprintf(out, " }\n");
- break;
+ char *tname = NULL;
+ Type *tinfo = node->var_decl.type_info;
+ if (tinfo && tinfo->name) {
+ tname = tinfo->name;
+ } else if (node->var_decl.type_str &&
+ strcmp(node->var_decl.type_str, "__auto_type") != 0) {
+ tname = node->var_decl.type_str;
+ }
+
+ if (tname) {
+ ASTNode *def = find_struct_def(ctx, tname);
+ if (def && def->type_info && def->type_info->has_drop) {
+ fprintf(out, "__attribute__((cleanup(%s_Drop_glue))) ", tname);
+ }
+ }
}
- case NODE_VAR_DECL:
- fprintf(out, " ");
- if (node->var_decl.is_static)
- {
- fprintf(out, "static ");
- }
- if (node->var_decl.is_autofree)
- {
- fprintf(out, "__attribute__((cleanup(_z_autofree_impl))) ");
- }
- {
- char *tname = NULL;
- Type *tinfo = node->var_decl.type_info;
- if (tinfo && tinfo->name)
- {
- tname = tinfo->name;
- }
- else if (node->var_decl.type_str && strcmp(node->var_decl.type_str, "__auto_type") != 0)
- {
- tname = node->var_decl.type_str;
- }
-
- if (tname)
- {
- ASTNode *def = find_struct_def(ctx, tname);
- if (def && def->type_info && def->type_info->has_drop)
- {
- fprintf(out, "__attribute__((cleanup(%s_Drop_glue))) ", tname);
- }
- }
- }
- if (node->var_decl.type_str && strcmp(node->var_decl.type_str, "__auto_type") != 0)
- {
- emit_var_decl_type(ctx, out, node->var_decl.type_str, node->var_decl.name);
- add_symbol(ctx, node->var_decl.name, node->var_decl.type_str, node->var_decl.type_info);
- if (node->var_decl.init_expr)
- {
- fprintf(out, " = ");
- codegen_expression(ctx, node->var_decl.init_expr, out);
- }
- fprintf(out, ";\n");
- }
- else
- {
- char *inferred = NULL;
- if (node->var_decl.init_expr)
- {
- inferred = infer_type(ctx, node->var_decl.init_expr);
- }
-
- if (inferred && strcmp(inferred, "__auto_type") != 0)
- {
- emit_var_decl_type(ctx, out, inferred, node->var_decl.name);
- add_symbol(ctx, node->var_decl.name, inferred, NULL);
- }
- else
- {
- emit_auto_type(ctx, node->var_decl.init_expr, node->token, out);
- fprintf(out, " %s", node->var_decl.name);
-
- if (inferred)
- {
- add_symbol(ctx, node->var_decl.name, inferred, NULL);
- }
- else
- {
- // Here we are cooked.
- }
- }
-
- fprintf(out, " = ");
- codegen_expression(ctx, node->var_decl.init_expr, out);
- fprintf(out, ";\n");
- }
- break;
- case NODE_CONST:
- fprintf(out, " const ");
- if (node->var_decl.type_str)
- {
- fprintf(out, "%s %s", node->var_decl.type_str, node->var_decl.name);
- }
- else
- {
- emit_auto_type(ctx, node->var_decl.init_expr, node->token, out);
- fprintf(out, " %s", node->var_decl.name);
- }
+ if (node->var_decl.type_str &&
+ strcmp(node->var_decl.type_str, "__auto_type") != 0) {
+ emit_var_decl_type(ctx, out, node->var_decl.type_str,
+ node->var_decl.name);
+ add_symbol(ctx, node->var_decl.name, node->var_decl.type_str,
+ node->var_decl.type_info);
+ if (node->var_decl.init_expr) {
fprintf(out, " = ");
codegen_expression(ctx, node->var_decl.init_expr, out);
- fprintf(out, ";\n");
- break;
- case NODE_FIELD:
- if (node->field.bit_width > 0)
- {
- fprintf(out, " %s %s : %d;\n", node->field.type, node->field.name,
- node->field.bit_width);
- }
- else
- {
- fprintf(out, " ");
- emit_var_decl_type(ctx, out, node->field.type, node->field.name);
- fprintf(out, ";\n");
- }
- break;
- case NODE_IF:
- fprintf(out, "if (");
- codegen_expression(ctx, node->if_stmt.condition, out);
- fprintf(out, ") ");
- codegen_node_single(ctx, node->if_stmt.then_body, out);
- if (node->if_stmt.else_body)
- {
- fprintf(out, " else ");
- codegen_node_single(ctx, node->if_stmt.else_body, out);
- }
- break;
- case NODE_UNLESS:
- fprintf(out, "if (!(");
- codegen_expression(ctx, node->unless_stmt.condition, out);
- fprintf(out, ")) ");
- codegen_node_single(ctx, node->unless_stmt.body, out);
- break;
- case NODE_GUARD:
- fprintf(out, "if (!(");
- codegen_expression(ctx, node->guard_stmt.condition, out);
- fprintf(out, ")) ");
- codegen_node_single(ctx, node->guard_stmt.body, out);
- break;
- case NODE_WHILE:
- fprintf(out, "while (");
- codegen_expression(ctx, node->while_stmt.condition, out);
- fprintf(out, ") ");
- codegen_node_single(ctx, node->while_stmt.body, out);
- break;
- case NODE_FOR:
- fprintf(out, "for (");
- if (node->for_stmt.init)
- {
- if (node->for_stmt.init->type == NODE_VAR_DECL)
- {
- ASTNode *v = node->for_stmt.init;
- if (v->var_decl.type_str && strcmp(v->var_decl.type_str, "__auto_type") != 0)
- {
- fprintf(out, "%s %s = (%s)(", v->var_decl.type_str, v->var_decl.name,
- v->var_decl.type_str);
- codegen_expression(ctx, v->var_decl.init_expr, out);
- fprintf(out, ")");
- }
- else
- {
- emit_auto_type(ctx, v->var_decl.init_expr, v->token, out);
- fprintf(out, " %s = ", v->var_decl.name);
- codegen_expression(ctx, v->var_decl.init_expr, out);
- }
- }
- else
- {
- codegen_expression(ctx, node->for_stmt.init, out);
- }
- }
- fprintf(out, "; ");
- if (node->for_stmt.condition)
- {
- codegen_expression(ctx, node->for_stmt.condition, out);
- }
- fprintf(out, "; ");
- if (node->for_stmt.step)
- {
- codegen_expression(ctx, node->for_stmt.step, out);
- }
- fprintf(out, ") ");
- codegen_node_single(ctx, node->for_stmt.body, out);
- break;
- case NODE_BREAK:
- if (node->break_stmt.target_label)
- {
- fprintf(out, "goto __break_%s;\n", node->break_stmt.target_label);
- }
- else
- {
- fprintf(out, "break;\n");
- }
- break;
- case NODE_CONTINUE:
- if (node->continue_stmt.target_label)
- {
- fprintf(out, "goto __continue_%s;\n", node->continue_stmt.target_label);
- }
- else
- {
- fprintf(out, "continue;\n");
- }
- break;
- case NODE_GOTO:
- if (node->goto_stmt.goto_expr)
- {
- // Computed goto: goto *expr;
- fprintf(out, "goto *(");
- codegen_expression(ctx, node->goto_stmt.goto_expr, out);
- fprintf(out, ");\n");
- }
- else
- {
- fprintf(out, "goto %s;\n", node->goto_stmt.label_name);
- }
- break;
- case NODE_LABEL:
- fprintf(out, "%s:;\n", node->label_stmt.label_name);
- break;
- case NODE_DO_WHILE:
- fprintf(out, "do ");
- codegen_node_single(ctx, node->do_while_stmt.body, out);
- fprintf(out, " while (");
- codegen_expression(ctx, node->do_while_stmt.condition, out);
- fprintf(out, ");\n");
- break;
- // Loop constructs: loop, repeat, for-in
- case NODE_LOOP:
- // loop { ... } => while (1) { ... }
- fprintf(out, "while (1) ");
- codegen_node_single(ctx, node->loop_stmt.body, out);
- break;
- case NODE_REPEAT:
- fprintf(out, "for (int _rpt_i = 0; _rpt_i < (%s); _rpt_i++) ", node->repeat_stmt.count);
- codegen_node_single(ctx, node->repeat_stmt.body, out);
- break;
- case NODE_FOR_RANGE:
- fprintf(out, "for (");
- if (strstr(g_config.cc, "tcc"))
- {
- fprintf(out, "__typeof__((");
- codegen_expression(ctx, node->for_range.start, out);
- fprintf(out, ")) %s = ", node->for_range.var_name);
- }
- else
- {
- fprintf(out, "__auto_type %s = ", node->for_range.var_name);
- }
- codegen_expression(ctx, node->for_range.start, out);
- fprintf(out, "; %s < ", node->for_range.var_name);
- codegen_expression(ctx, node->for_range.end, out);
- fprintf(out, "; %s", node->for_range.var_name);
- if (node->for_range.step)
- {
- fprintf(out, " += %s) ", node->for_range.step);
- }
- else
- {
- fprintf(out, "++) ");
- }
- codegen_node_single(ctx, node->for_range.body, out);
- break;
- case NODE_ASM:
- {
- int is_extended = (node->asm_stmt.num_outputs > 0 || node->asm_stmt.num_inputs > 0 ||
- node->asm_stmt.num_clobbers > 0);
+ }
+ fprintf(out, ";\n");
+ } else {
+ char *inferred = NULL;
+ if (node->var_decl.init_expr) {
+ inferred = infer_type(ctx, node->var_decl.init_expr);
+ }
+
+ if (inferred && strcmp(inferred, "__auto_type") != 0) {
+ emit_var_decl_type(ctx, out, inferred, node->var_decl.name);
+ add_symbol(ctx, node->var_decl.name, inferred, NULL);
+ } else {
+ emit_auto_type(ctx, node->var_decl.init_expr, node->token, out);
+ fprintf(out, " %s", node->var_decl.name);
+
+ if (inferred) {
+ add_symbol(ctx, node->var_decl.name, inferred, NULL);
+ } else {
+ // Here we are cooked.
+ }
+ }
+
+ fprintf(out, " = ");
+ codegen_expression(ctx, node->var_decl.init_expr, out);
+ fprintf(out, ";\n");
+ }
+ break;
+ case NODE_CONST:
+ fprintf(out, " const ");
+ if (node->var_decl.type_str) {
+ fprintf(out, "%s %s", node->var_decl.type_str, node->var_decl.name);
+ } else {
+ emit_auto_type(ctx, node->var_decl.init_expr, node->token, out);
+ fprintf(out, " %s", node->var_decl.name);
+ }
+ fprintf(out, " = ");
+ codegen_expression(ctx, node->var_decl.init_expr, out);
+ fprintf(out, ";\n");
+ break;
+ case NODE_FIELD:
+ if (node->field.bit_width > 0) {
+ fprintf(out, " %s %s : %d;\n", node->field.type, node->field.name,
+ node->field.bit_width);
+ } else {
+ fprintf(out, " ");
+ emit_var_decl_type(ctx, out, node->field.type, node->field.name);
+ fprintf(out, ";\n");
+ }
+ break;
+ case NODE_IF:
+ fprintf(out, "if (");
+ codegen_expression(ctx, node->if_stmt.condition, out);
+ fprintf(out, ") ");
+ codegen_node_single(ctx, node->if_stmt.then_body, out);
+ if (node->if_stmt.else_body) {
+ fprintf(out, " else ");
+ codegen_node_single(ctx, node->if_stmt.else_body, out);
+ }
+ break;
+ case NODE_UNLESS:
+ fprintf(out, "if (!(");
+ codegen_expression(ctx, node->unless_stmt.condition, out);
+ fprintf(out, ")) ");
+ codegen_node_single(ctx, node->unless_stmt.body, out);
+ break;
+ case NODE_GUARD:
+ fprintf(out, "if (!(");
+ codegen_expression(ctx, node->guard_stmt.condition, out);
+ fprintf(out, ")) ");
+ codegen_node_single(ctx, node->guard_stmt.body, out);
+ break;
+ case NODE_WHILE:
+ fprintf(out, "while (");
+ codegen_expression(ctx, node->while_stmt.condition, out);
+ fprintf(out, ") ");
+ codegen_node_single(ctx, node->while_stmt.body, out);
+ break;
+ case NODE_FOR:
+ fprintf(out, "for (");
+ if (node->for_stmt.init) {
+ if (node->for_stmt.init->type == NODE_VAR_DECL) {
+ ASTNode *v = node->for_stmt.init;
+ if (v->var_decl.type_str &&
+ strcmp(v->var_decl.type_str, "__auto_type") != 0) {
+ fprintf(out, "%s %s = (%s)(", v->var_decl.type_str, v->var_decl.name,
+ v->var_decl.type_str);
+ codegen_expression(ctx, v->var_decl.init_expr, out);
+ fprintf(out, ")");
+ } else {
+ emit_auto_type(ctx, v->var_decl.init_expr, v->token, out);
+ fprintf(out, " %s = ", v->var_decl.name);
+ codegen_expression(ctx, v->var_decl.init_expr, out);
+ }
+ } else {
+ codegen_expression(ctx, node->for_stmt.init, out);
+ }
+ }
+ fprintf(out, "; ");
+ if (node->for_stmt.condition) {
+ codegen_expression(ctx, node->for_stmt.condition, out);
+ }
+ fprintf(out, "; ");
+ if (node->for_stmt.step) {
+ codegen_expression(ctx, node->for_stmt.step, out);
+ }
+ fprintf(out, ") ");
+ codegen_node_single(ctx, node->for_stmt.body, out);
+ break;
+ case NODE_BREAK:
+ if (node->break_stmt.target_label) {
+ fprintf(out, "goto __break_%s;\n", node->break_stmt.target_label);
+ } else {
+ fprintf(out, "break;\n");
+ }
+ break;
+ case NODE_CONTINUE:
+ if (node->continue_stmt.target_label) {
+ fprintf(out, "goto __continue_%s;\n", node->continue_stmt.target_label);
+ } else {
+ fprintf(out, "continue;\n");
+ }
+ break;
+ case NODE_GOTO:
+ if (node->goto_stmt.goto_expr) {
+ // Computed goto: goto *expr;
+ fprintf(out, "goto *(");
+ codegen_expression(ctx, node->goto_stmt.goto_expr, out);
+ fprintf(out, ");\n");
+ } else {
+ fprintf(out, "goto %s;\n", node->goto_stmt.label_name);
+ }
+ break;
+ case NODE_LABEL:
+ fprintf(out, "%s:;\n", node->label_stmt.label_name);
+ break;
+ case NODE_DO_WHILE:
+ fprintf(out, "do ");
+ codegen_node_single(ctx, node->do_while_stmt.body, out);
+ fprintf(out, " while (");
+ codegen_expression(ctx, node->do_while_stmt.condition, out);
+ fprintf(out, ");\n");
+ break;
+ // Loop constructs: loop, repeat, for-in
+ case NODE_LOOP:
+ // loop { ... } => while (1) { ... }
+ fprintf(out, "while (1) ");
+ codegen_node_single(ctx, node->loop_stmt.body, out);
+ break;
+ case NODE_REPEAT:
+ fprintf(out, "for (int _rpt_i = 0; _rpt_i < (%s); _rpt_i++) ",
+ node->repeat_stmt.count);
+ codegen_node_single(ctx, node->repeat_stmt.body, out);
+ break;
+ case NODE_FOR_RANGE:
+ fprintf(out, "for (");
+ if (strstr(g_config.cc, "tcc")) {
+ fprintf(out, "__typeof__((");
+ codegen_expression(ctx, node->for_range.start, out);
+ fprintf(out, ")) %s = ", node->for_range.var_name);
+ } else {
+ fprintf(out, "__auto_type %s = ", node->for_range.var_name);
+ }
+ codegen_expression(ctx, node->for_range.start, out);
+ fprintf(out, "; %s < ", node->for_range.var_name);
+ codegen_expression(ctx, node->for_range.end, out);
+ fprintf(out, "; %s", node->for_range.var_name);
+ if (node->for_range.step) {
+ fprintf(out, " += %s) ", node->for_range.step);
+ } else {
+ fprintf(out, "++) ");
+ }
+ codegen_node_single(ctx, node->for_range.body, out);
+ break;
+ case NODE_ASM: {
+ int is_extended =
+ (node->asm_stmt.num_outputs > 0 || node->asm_stmt.num_inputs > 0 ||
+ node->asm_stmt.num_clobbers > 0);
+
+ if (node->asm_stmt.is_volatile) {
+ fprintf(out, " __asm__ __volatile__(");
+ } else {
+ fprintf(out, " __asm__(");
+ }
- if (node->asm_stmt.is_volatile)
- {
- fprintf(out, " __asm__ __volatile__(");
- }
- else
- {
- fprintf(out, " __asm__(");
- }
+ char *code = node->asm_stmt.code;
+ char *transformed = xmalloc(strlen(code) * 3); // Generous buffer
+ char *dst = transformed;
+
+ for (char *p = code; *p; p++) {
+ if (*p == '{') {
+ // Find matching }
+ char *end = strchr(p + 1, '}');
+ if (end) {
+ // Extract variable name
+ int var_len = end - p - 1;
+ char var_name[64];
+ strncpy(var_name, p + 1, var_len);
+ var_name[var_len] = 0;
+
+ // Find variable index
+ int idx = -1;
+
+ // Check outputs first
+ for (int i = 0; i < node->asm_stmt.num_outputs; i++) {
+ if (strcmp(node->asm_stmt.outputs[i], var_name) == 0) {
+ idx = i;
+ break;
+ }
+ }
+
+ // Then check inputs
+ if (idx == -1) {
+ for (int i = 0; i < node->asm_stmt.num_inputs; i++) {
+ if (strcmp(node->asm_stmt.inputs[i], var_name) == 0) {
+ idx = node->asm_stmt.num_outputs + i;
+ break;
+ }
+ }
+ }
+
+ if (idx >= 0) {
+ // Replace with %N
+ dst += sprintf(dst, "%%%d", idx);
+ } else {
+ // Variable not found - error or keep as-is?
+ dst += sprintf(dst, "{%s}", var_name);
+ }
+
+ p = end; // Skip past }
+ } else {
+ *dst++ = *p;
+ }
+ } else if (*p == '%') {
+ if (is_extended) {
+ *dst++ = '%';
+ *dst++ = '%';
+ } else {
+ *dst++ = '%';
+ }
+ } else {
+ *dst++ = *p;
+ }
+ }
+ *dst = 0;
+
+ fprintf(out, "\"");
+ for (char *p = transformed; *p; p++) {
+ if (*p == '\n') {
+ fprintf(out, "\\n\"\n \"");
+ } else if (*p == '"') {
+ fprintf(out, "\\\"");
+ } else if (*p == '\\') {
+ fprintf(out, "\\\\");
+ } else {
+ fputc(*p, out);
+ }
+ }
+ fprintf(out, "\\n\"");
- char *code = node->asm_stmt.code;
- char *transformed = xmalloc(strlen(code) * 3); // Generous buffer
- char *dst = transformed;
-
- for (char *p = code; *p; p++)
- {
- if (*p == '{')
- {
- // Find matching }
- char *end = strchr(p + 1, '}');
- if (end)
- {
- // Extract variable name
- int var_len = end - p - 1;
- char var_name[64];
- strncpy(var_name, p + 1, var_len);
- var_name[var_len] = 0;
-
- // Find variable index
- int idx = -1;
-
- // Check outputs first
- for (int i = 0; i < node->asm_stmt.num_outputs; i++)
- {
- if (strcmp(node->asm_stmt.outputs[i], var_name) == 0)
- {
- idx = i;
- break;
- }
- }
-
- // Then check inputs
- if (idx == -1)
- {
- for (int i = 0; i < node->asm_stmt.num_inputs; i++)
- {
- if (strcmp(node->asm_stmt.inputs[i], var_name) == 0)
- {
- idx = node->asm_stmt.num_outputs + i;
- break;
- }
- }
- }
-
- if (idx >= 0)
- {
- // Replace with %N
- dst += sprintf(dst, "%%%d", idx);
- }
- else
- {
- // Variable not found - error or keep as-is?
- dst += sprintf(dst, "{%s}", var_name);
- }
-
- p = end; // Skip past }
- }
- else
- {
- *dst++ = *p;
- }
- }
- else if (*p == '%')
- {
- if (is_extended)
- {
- *dst++ = '%';
- *dst++ = '%';
- }
- else
- {
- *dst++ = '%';
- }
- }
- else
- {
- *dst++ = *p;
- }
- }
- *dst = 0;
-
- fprintf(out, "\"");
- for (char *p = transformed; *p; p++)
- {
- if (*p == '\n')
- {
- fprintf(out, "\\n\"\n \"");
- }
- else if (*p == '"')
- {
- fprintf(out, "\\\"");
- }
- else if (*p == '\\')
- {
- fprintf(out, "\\\\");
- }
- else
- {
- fputc(*p, out);
- }
- }
- fprintf(out, "\\n\"");
-
- if (node->asm_stmt.num_outputs > 0)
- {
- fprintf(out, "\n : ");
- for (int i = 0; i < node->asm_stmt.num_outputs; i++)
- {
- if (i > 0)
- {
- fprintf(out, ", ");
- }
-
- // Determine constraint
- char *mode = node->asm_stmt.output_modes[i];
- if (strcmp(mode, "out") == 0)
- {
- fprintf(out, "\"=r\"(%s)", node->asm_stmt.outputs[i]);
- }
- else if (strcmp(mode, "inout") == 0)
- {
- fprintf(out, "\"+r\"(%s)", node->asm_stmt.outputs[i]);
- }
- else
- {
- fprintf(out, "\"=r\"(%s)", node->asm_stmt.outputs[i]);
- }
- }
+ if (node->asm_stmt.num_outputs > 0) {
+ fprintf(out, "\n : ");
+ for (int i = 0; i < node->asm_stmt.num_outputs; i++) {
+ if (i > 0) {
+ fprintf(out, ", ");
}
- if (node->asm_stmt.num_inputs > 0)
- {
- fprintf(out, "\n : ");
- for (int i = 0; i < node->asm_stmt.num_inputs; i++)
- {
- if (i > 0)
- {
- fprintf(out, ", ");
- }
- fprintf(out, "\"r\"(%s)", node->asm_stmt.inputs[i]);
- }
+ // Determine constraint
+ char *mode = node->asm_stmt.output_modes[i];
+ if (strcmp(mode, "out") == 0) {
+ fprintf(out, "\"=r\"(%s)", node->asm_stmt.outputs[i]);
+ } else if (strcmp(mode, "inout") == 0) {
+ fprintf(out, "\"+r\"(%s)", node->asm_stmt.outputs[i]);
+ } else {
+ fprintf(out, "\"=r\"(%s)", node->asm_stmt.outputs[i]);
}
- else if (node->asm_stmt.num_outputs > 0)
- {
- fprintf(out, "\n : ");
+ }
+ }
+
+ if (node->asm_stmt.num_inputs > 0) {
+ fprintf(out, "\n : ");
+ for (int i = 0; i < node->asm_stmt.num_inputs; i++) {
+ if (i > 0) {
+ fprintf(out, ", ");
}
+ fprintf(out, "\"r\"(%s)", node->asm_stmt.inputs[i]);
+ }
+ } else if (node->asm_stmt.num_outputs > 0) {
+ fprintf(out, "\n : ");
+ }
- if (node->asm_stmt.num_clobbers > 0)
- {
- fprintf(out, "\n : ");
- for (int i = 0; i < node->asm_stmt.num_clobbers; i++)
- {
- if (i > 0)
- {
- fprintf(out, ", ");
- }
- fprintf(out, "\"%s\"", node->asm_stmt.clobbers[i]);
- }
+ if (node->asm_stmt.num_clobbers > 0) {
+ fprintf(out, "\n : ");
+ for (int i = 0; i < node->asm_stmt.num_clobbers; i++) {
+ if (i > 0) {
+ fprintf(out, ", ");
}
+ fprintf(out, "\"%s\"", node->asm_stmt.clobbers[i]);
+ }
+ }
- fprintf(out, ");\n");
- break;
+ fprintf(out, ");\n");
+ break;
+ }
+ case NODE_RETURN:
+ fprintf(out, " return ");
+ codegen_expression(ctx, node->ret.value, out);
+ fprintf(out, ";\n");
+ break;
+ case NODE_EXPR_MEMBER: {
+ codegen_expression(ctx, node->member.target, out);
+ char *lt = infer_type(ctx, node->member.target);
+ if (lt && (lt[strlen(lt) - 1] == '*' || strstr(lt, "*"))) {
+ fprintf(out, "->%s", node->member.field);
+ } else {
+ fprintf(out, ".%s", node->member.field);
}
- case NODE_RETURN:
- fprintf(out, " return ");
- codegen_expression(ctx, node->ret.value, out);
- fprintf(out, ";\n");
- break;
- case NODE_EXPR_MEMBER:
- {
- codegen_expression(ctx, node->member.target, out);
- char *lt = infer_type(ctx, node->member.target);
- if (lt && (lt[strlen(lt) - 1] == '*' || strstr(lt, "*")))
- {
- fprintf(out, "->%s", node->member.field);
- }
- else
- {
- fprintf(out, ".%s", node->member.field);
- }
- if (lt)
- {
- free(lt);
- }
- break;
+ if (lt) {
+ free(lt);
}
- case NODE_REPL_PRINT:
- {
- fprintf(out, "{ ");
- emit_auto_type(ctx, node->repl_print.expr, node->token, out);
- fprintf(out, " _zval = (");
- codegen_expression(ctx, node->repl_print.expr, out);
- fprintf(out, "); fprintf(stdout, _z_str(_zval), _zval); fprintf(stdout, "
- "\"\\n\"); }\n");
- break;
+ break;
+ }
+ case NODE_REPL_PRINT: {
+ fprintf(out, "{ ");
+ emit_auto_type(ctx, node->repl_print.expr, node->token, out);
+ fprintf(out, " _zval = (");
+ codegen_expression(ctx, node->repl_print.expr, out);
+ fprintf(out, "); fprintf(stdout, _z_str(_zval), _zval); fprintf(stdout, "
+ "\"\\n\"); }\n");
+ break;
+ }
+ case NODE_AWAIT: {
+ char *ret_type = "void*";
+ int free_ret = 0;
+ if (node->type_info) {
+ char *t = type_to_string(node->type_info);
+ if (t) {
+ ret_type = t;
+ free_ret = 1;
+ }
+ } else if (node->resolved_type) {
+ ret_type = node->resolved_type;
}
- case NODE_AWAIT:
- {
- char *ret_type = "void*";
- int free_ret = 0;
- if (node->type_info)
- {
- char *t = type_to_string(node->type_info);
- if (t)
- {
- ret_type = t;
- free_ret = 1;
- }
- }
- else if (node->resolved_type)
- {
- ret_type = node->resolved_type;
- }
-
- // Fallback: If type is still Async/void* (likely from Future type, not
- // Result type), try to infer
- if (strcmp(ret_type, "Async") == 0 || strcmp(ret_type, "void*") == 0)
- {
- char *inf = infer_type(ctx, node);
- if (inf && strcmp(inf, "Async") != 0 && strcmp(inf, "void*") != 0)
- {
- if (free_ret)
- {
- free(ret_type);
- }
- ret_type = inf;
- free_ret = 0; // infer_type ownership ambiguous, avoid double free
- }
- }
- int needs_long_cast = 0;
- int returns_struct = 0;
- if (strstr(ret_type, "*") == NULL && strcmp(ret_type, "string") != 0 &&
- strcmp(ret_type, "void") != 0 && strcmp(ret_type, "Async") != 0)
- {
- if (strcmp(ret_type, "int") != 0 && strcmp(ret_type, "bool") != 0 &&
- strcmp(ret_type, "char") != 0 && strcmp(ret_type, "float") != 0 &&
- strcmp(ret_type, "double") != 0 && strcmp(ret_type, "long") != 0 &&
- strcmp(ret_type, "usize") != 0 && strcmp(ret_type, "isize") != 0 &&
- strncmp(ret_type, "uint", 4) != 0 && strncmp(ret_type, "int", 3) != 0)
- {
- returns_struct = 1;
- }
- else
- {
- needs_long_cast = 1;
- }
+ // Fallback: If type is still Async/void* (likely from Future type, not
+ // Result type), try to infer
+ if (strcmp(ret_type, "Async") == 0 || strcmp(ret_type, "void*") == 0) {
+ char *inf = infer_type(ctx, node);
+ if (inf && strcmp(inf, "Async") != 0 && strcmp(inf, "void*") != 0) {
+ if (free_ret) {
+ free(ret_type);
+ }
+ ret_type = inf;
+ free_ret = 0; // infer_type ownership ambiguous, avoid double free
+ }
+ }
- if (strncmp(ret_type, "struct", 6) == 0)
- {
- returns_struct = 1;
- }
- }
+ int needs_long_cast = 0;
+ int returns_struct = 0;
+ if (strstr(ret_type, "*") == NULL && strcmp(ret_type, "string") != 0 &&
+ strcmp(ret_type, "void") != 0 && strcmp(ret_type, "Async") != 0) {
+ if (strcmp(ret_type, "int") != 0 && strcmp(ret_type, "bool") != 0 &&
+ strcmp(ret_type, "char") != 0 && strcmp(ret_type, "float") != 0 &&
+ strcmp(ret_type, "double") != 0 && strcmp(ret_type, "long") != 0 &&
+ strcmp(ret_type, "usize") != 0 && strcmp(ret_type, "isize") != 0 &&
+ strncmp(ret_type, "uint", 4) != 0 &&
+ strncmp(ret_type, "int", 3) != 0) {
+ returns_struct = 1;
+ } else {
+ needs_long_cast = 1;
+ }
+
+ if (strncmp(ret_type, "struct", 6) == 0) {
+ returns_struct = 1;
+ }
+ }
- fprintf(out, "({ Async _a = ");
- codegen_expression(ctx, node->unary.operand, out);
- fprintf(out, "; void* _r; pthread_join(_a.thread, &_r); ");
- if (strcmp(ret_type, "void") == 0)
- {
- fprintf(out, "})"); // result unused
- }
- else
- {
- if (returns_struct)
- {
- // Dereference and free
- fprintf(out, "%s _val = *(%s*)_r; free(_r); _val; })", ret_type, ret_type);
- }
- else
- {
- if (needs_long_cast)
- {
- fprintf(out, "(%s)(long)_r; })", ret_type);
- }
- else
- {
- fprintf(out, "(%s)_r; })", ret_type);
- }
- }
- }
- if (free_ret)
- {
- free(ret_type);
- }
- fprintf(out, ";\n"); // Statement terminator
- break;
+ fprintf(out, "({ Async _a = ");
+ codegen_expression(ctx, node->unary.operand, out);
+ fprintf(out, "; void* _r; pthread_join(_a.thread, &_r); ");
+ if (strcmp(ret_type, "void") == 0) {
+ fprintf(out, "})"); // result unused
+ } else {
+ if (returns_struct) {
+ // Dereference and free
+ fprintf(out, "%s _val = *(%s*)_r; free(_r); _val; })", ret_type,
+ ret_type);
+ } else {
+ if (needs_long_cast) {
+ fprintf(out, "(%s)(long)_r; })", ret_type);
+ } else {
+ fprintf(out, "(%s)_r; })", ret_type);
+ }
+ }
}
- default:
- codegen_expression(ctx, node, out);
- fprintf(out, ";\n");
- break;
+ if (free_ret) {
+ free(ret_type);
}
+ fprintf(out, ";\n"); // Statement terminator
+ break;
+ }
+ default:
+ codegen_expression(ctx, node, out);
+ fprintf(out, ";\n");
+ break;
+ }
}
// Walks AST nodes and generates code.
-void codegen_walker(ParserContext *ctx, ASTNode *node, FILE *out)
-{
- while (node)
- {
- codegen_node_single(ctx, node, out);
- node = node->next;
- }
+void codegen_walker(ParserContext *ctx, ASTNode *node, FILE *out) {
+ while (node) {
+ codegen_node_single(ctx, node, out);
+ node = node->next;
+ }
}
diff --git a/src/codegen/codegen.h b/src/codegen/codegen.h
index 4b66f99..4d13d65 100644
--- a/src/codegen/codegen.h
+++ b/src/codegen/codegen.h
@@ -16,9 +16,11 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out);
// Utility functions (codegen_utils.c).
char *infer_type(ParserContext *ctx, ASTNode *node);
ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name);
-char *get_field_type_str(ParserContext *ctx, const char *struct_name, const char *field_name);
+char *get_field_type_str(ParserContext *ctx, const char *struct_name,
+ const char *field_name);
char *extract_call_args(const char *args);
-void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name);
+void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str,
+ const char *var_name);
char *replace_string_type(const char *args);
const char *parse_original_method_name(const char *mangled);
void emit_auto_type(ParserContext *ctx, ASTNode *init_expr, Token t, FILE *out);
diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c
index 026824e..53c4eb2 100644
--- a/src/codegen/codegen_decl.c
+++ b/src/codegen/codegen_decl.c
@@ -8,912 +8,763 @@
#include <string.h>
// Emit C preamble with standard includes and type definitions.
-void emit_preamble(ParserContext *ctx, FILE *out)
-{
- if (g_config.is_freestanding)
- {
- // Freestanding preamble.
- // It actually needs more work, but yk.
- fputs("#include <stddef.h>\n#include <stdint.h>\n#include "
- "<stdbool.h>\n#include <stdarg.h>\n",
- out);
- fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out);
- fputs("typedef size_t usize;\ntypedef char* string;\n", out);
- fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
- "int16_t\n#define U16 uint16_t\n",
- out);
- fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 "
- "int64_t\n#define U64 "
- "uint64_t\n",
- out);
- fputs("#define F32 float\n#define F64 double\n", out);
- fputs("#define _z_str(x) _Generic((x), _Bool: \"%d\", char: \"%c\", "
- "signed char: \"%c\", unsigned char: \"%u\", short: \"%d\", "
- "unsigned short: \"%u\", int: \"%d\", unsigned int: \"%u\", "
- "long: \"%ld\", unsigned long: \"%lu\", long long: \"%lld\", "
- "unsigned long long: \"%llu\", float: \"%f\", double: \"%f\", "
- "char*: \"%s\", void*: \"%p\")\n",
- out);
- fputs("typedef struct { void *func; void *ctx; } z_closure_T;\n", out);
-
- fputs("__attribute__((weak)) void* z_malloc(usize sz) { return NULL; }\n", out);
- fputs("__attribute__((weak)) void* z_realloc(void* ptr, usize sz) { return "
- "NULL; }\n",
- out);
- fputs("__attribute__((weak)) void z_free(void* ptr) { }\n", out);
- fputs("__attribute__((weak)) void z_print(const char* fmt, ...) { }\n", out);
- fputs("__attribute__((weak)) void z_panic(const char* msg) { while(1); }\n", out);
- }
- else
- {
- // Standard hosted preamble.
- fputs("#include <stdio.h>\n#include <stdlib.h>\n#include "
- "<stddef.h>\n#include <string.h>\n",
- out);
- fputs("#include <stdarg.h>\n#include <stdint.h>\n#include <stdbool.h>\n", out);
- fputs("#include <unistd.h>\n#include <fcntl.h>\n", out); // POSIX functions
- fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out);
- fputs("typedef size_t usize;\ntypedef char* string;\n", out);
- if (ctx->has_async)
- {
- fputs("#include <pthread.h>\n", out);
- fputs("typedef struct { pthread_t thread; void *result; } Async;\n", out);
- }
- fputs("typedef struct { void *func; void *ctx; } z_closure_T;\n", out);
- fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
- "int16_t\n#define U16 uint16_t\n",
- out);
- fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 "
- "int64_t\n#define U64 "
- "uint64_t\n",
- out);
- fputs("#define F32 float\n#define F64 double\n", out);
- fputs("#define _z_str(x) _Generic((x), _Bool: \"%d\", char: \"%c\", "
- "signed char: \"%c\", unsigned char: \"%u\", short: \"%d\", "
- "unsigned short: \"%u\", int: \"%d\", unsigned int: \"%u\", "
- "long: \"%ld\", unsigned long: \"%lu\", long long: \"%lld\", "
- "unsigned long long: \"%llu\", float: \"%f\", double: \"%f\", "
- "char*: \"%s\", void*: \"%p\")\n",
- out);
-
- // Memory Mapping.
- fputs("#define z_malloc malloc\n#define z_realloc realloc\n#define z_free "
- "free\n#define "
- "z_print printf\n",
- out);
- fputs("void z_panic(const char* msg) { fprintf(stderr, \"Panic: %s\\n\", "
- "msg); exit(1); }\n",
- out);
-
- fputs("void _z_autofree_impl(void *p) { void **pp = (void**)p; if(*pp) { "
- "z_free(*pp); *pp "
- "= NULL; } }\n",
- out);
- fputs("#define assert(cond, ...) if (!(cond)) { fprintf(stderr, "
- "\"Assertion failed: \" "
- "__VA_ARGS__); exit(1); }\n",
- out);
- fputs("string _z_readln_raw() { "
- "size_t cap = 64; size_t len = 0; "
- "char *line = z_malloc(cap); "
- "if(!line) return NULL; "
- "int c; "
- "while((c = fgetc(stdin)) != EOF) { "
- "if(c == '\\n') break; "
- "if(len + 1 >= cap) { cap *= 2; char *n = z_realloc(line, cap); "
- "if(!n) { z_free(line); return NULL; } line = n; } "
- "line[len++] = c; } "
- "if(len == 0 && c == EOF) { z_free(line); return NULL; } "
- "line[len] = 0; return line; }\n",
- out);
- fputs("int _z_scan_helper(const char *fmt, ...) { char *l = "
- "_z_readln_raw(); if(!l) return "
- "0; va_list ap; va_start(ap, fmt); int r = vsscanf(l, fmt, ap); "
- "va_end(ap); "
- "z_free(l); return r; }\n",
- out);
-
- // REPL helpers: suppress/restore stdout.
- fputs("int _z_orig_stdout = -1;\n", out);
- fputs("void _z_suppress_stdout() {\n", out);
- fputs(" fflush(stdout);\n", out);
- fputs(" if (_z_orig_stdout == -1) _z_orig_stdout = dup(STDOUT_FILENO);\n", out);
- fputs(" int nullfd = open(\"/dev/null\", O_WRONLY);\n", out);
- fputs(" dup2(nullfd, STDOUT_FILENO);\n", out);
- fputs(" close(nullfd);\n", out);
- fputs("}\n", out);
- fputs("void _z_restore_stdout() {\n", out);
- fputs(" fflush(stdout);\n", out);
- fputs(" if (_z_orig_stdout != -1) {\n", out);
- fputs(" dup2(_z_orig_stdout, STDOUT_FILENO);\n", out);
- fputs(" close(_z_orig_stdout);\n", out);
- fputs(" _z_orig_stdout = -1;\n", out);
- fputs(" }\n", out);
- fputs("}\n", out);
+void emit_preamble(ParserContext *ctx, FILE *out) {
+ if (g_config.is_freestanding) {
+ // Freestanding preamble.
+ // It actually needs more work, but yk.
+ fputs("#include <stddef.h>\n#include <stdint.h>\n#include "
+ "<stdbool.h>\n#include <stdarg.h>\n",
+ out);
+ fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out);
+ fputs("typedef size_t usize;\ntypedef char* string;\n", out);
+ fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
+ "int16_t\n#define U16 uint16_t\n",
+ out);
+ fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 "
+ "int64_t\n#define U64 "
+ "uint64_t\n",
+ out);
+ fputs("#define F32 float\n#define F64 double\n", out);
+ fputs("#define _z_str(x) _Generic((x), _Bool: \"%d\", char: \"%c\", "
+ "signed char: \"%c\", unsigned char: \"%u\", short: \"%d\", "
+ "unsigned short: \"%u\", int: \"%d\", unsigned int: \"%u\", "
+ "long: \"%ld\", unsigned long: \"%lu\", long long: \"%lld\", "
+ "unsigned long long: \"%llu\", float: \"%f\", double: \"%f\", "
+ "char*: \"%s\", void*: \"%p\")\n",
+ out);
+ fputs("typedef struct { void *func; void *ctx; } z_closure_T;\n", out);
+
+ fputs("__attribute__((weak)) void* z_malloc(usize sz) { return NULL; }\n",
+ out);
+ fputs("__attribute__((weak)) void* z_realloc(void* ptr, usize sz) { return "
+ "NULL; }\n",
+ out);
+ fputs("__attribute__((weak)) void z_free(void* ptr) { }\n", out);
+ fputs("__attribute__((weak)) void z_print(const char* fmt, ...) { }\n",
+ out);
+ fputs("__attribute__((weak)) void z_panic(const char* msg) { while(1); }\n",
+ out);
+ } else {
+ // Standard hosted preamble.
+ fputs("#include <stdio.h>\n#include <stdlib.h>\n#include "
+ "<stddef.h>\n#include <string.h>\n",
+ out);
+ fputs("#include <stdarg.h>\n#include <stdint.h>\n#include <stdbool.h>\n",
+ out);
+ fputs("#include <unistd.h>\n#include <fcntl.h>\n", out); // POSIX functions
+ fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out);
+ fputs("typedef size_t usize;\ntypedef char* string;\n", out);
+ if (ctx->has_async) {
+ fputs("#include <pthread.h>\n", out);
+ fputs("typedef struct { pthread_t thread; void *result; } Async;\n", out);
}
+ fputs("typedef struct { void *func; void *ctx; } z_closure_T;\n", out);
+ fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
+ "int16_t\n#define U16 uint16_t\n",
+ out);
+ fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 "
+ "int64_t\n#define U64 "
+ "uint64_t\n",
+ out);
+ fputs("#define F32 float\n#define F64 double\n", out);
+ fputs("#define _z_str(x) _Generic((x), _Bool: \"%d\", char: \"%c\", "
+ "signed char: \"%c\", unsigned char: \"%u\", short: \"%d\", "
+ "unsigned short: \"%u\", int: \"%d\", unsigned int: \"%u\", "
+ "long: \"%ld\", unsigned long: \"%lu\", long long: \"%lld\", "
+ "unsigned long long: \"%llu\", float: \"%f\", double: \"%f\", "
+ "char*: \"%s\", void*: \"%p\")\n",
+ out);
+
+ // Memory Mapping.
+ fputs("#define z_malloc malloc\n#define z_realloc realloc\n#define z_free "
+ "free\n#define "
+ "z_print printf\n",
+ out);
+ fputs("void z_panic(const char* msg) { fprintf(stderr, \"Panic: %s\\n\", "
+ "msg); exit(1); }\n",
+ out);
+
+ fputs("void _z_autofree_impl(void *p) { void **pp = (void**)p; if(*pp) { "
+ "z_free(*pp); *pp "
+ "= NULL; } }\n",
+ out);
+ fputs("#define assert(cond, ...) if (!(cond)) { fprintf(stderr, "
+ "\"Assertion failed: \" "
+ "__VA_ARGS__); exit(1); }\n",
+ out);
+ fputs("string _z_readln_raw() { "
+ "size_t cap = 64; size_t len = 0; "
+ "char *line = z_malloc(cap); "
+ "if(!line) return NULL; "
+ "int c; "
+ "while((c = fgetc(stdin)) != EOF) { "
+ "if(c == '\\n') break; "
+ "if(len + 1 >= cap) { cap *= 2; char *n = z_realloc(line, cap); "
+ "if(!n) { z_free(line); return NULL; } line = n; } "
+ "line[len++] = c; } "
+ "if(len == 0 && c == EOF) { z_free(line); return NULL; } "
+ "line[len] = 0; return line; }\n",
+ out);
+ fputs("int _z_scan_helper(const char *fmt, ...) { char *l = "
+ "_z_readln_raw(); if(!l) return "
+ "0; va_list ap; va_start(ap, fmt); int r = vsscanf(l, fmt, ap); "
+ "va_end(ap); "
+ "z_free(l); return r; }\n",
+ out);
+
+ // REPL helpers: suppress/restore stdout.
+ fputs("int _z_orig_stdout = -1;\n", out);
+ fputs("void _z_suppress_stdout() {\n", out);
+ fputs(" fflush(stdout);\n", out);
+ fputs(
+ " if (_z_orig_stdout == -1) _z_orig_stdout = dup(STDOUT_FILENO);\n",
+ out);
+ fputs(" int nullfd = open(\"/dev/null\", O_WRONLY);\n", out);
+ fputs(" dup2(nullfd, STDOUT_FILENO);\n", out);
+ fputs(" close(nullfd);\n", out);
+ fputs("}\n", out);
+ fputs("void _z_restore_stdout() {\n", out);
+ fputs(" fflush(stdout);\n", out);
+ fputs(" if (_z_orig_stdout != -1) {\n", out);
+ fputs(" dup2(_z_orig_stdout, STDOUT_FILENO);\n", out);
+ fputs(" close(_z_orig_stdout);\n", out);
+ fputs(" _z_orig_stdout = -1;\n", out);
+ fputs(" }\n", out);
+ fputs("}\n", out);
+ }
}
// Emit includes and type aliases.
-void emit_includes_and_aliases(ASTNode *node, FILE *out)
-{
- while (node)
- {
- if (node->type == NODE_INCLUDE)
- {
- if (node->include.is_system)
- {
- fprintf(out, "#include <%s>\n", node->include.path);
- }
- else
- {
- fprintf(out, "#include \"%s\"\n", node->include.path);
- }
- }
- else if (node->type == NODE_TYPE_ALIAS)
- {
- fprintf(out, "typedef %s %s;\n", node->type_alias.original_type,
- node->type_alias.alias);
- }
- node = node->next;
+void emit_includes_and_aliases(ASTNode *node, FILE *out) {
+ while (node) {
+ if (node->type == NODE_INCLUDE) {
+ if (node->include.is_system) {
+ fprintf(out, "#include <%s>\n", node->include.path);
+ } else {
+ fprintf(out, "#include \"%s\"\n", node->include.path);
+ }
+ } else if (node->type == NODE_TYPE_ALIAS) {
+ fprintf(out, "typedef %s %s;\n", node->type_alias.original_type,
+ node->type_alias.alias);
}
+ node = node->next;
+ }
}
// Emit enum constructor prototypes
-void emit_enum_protos(ASTNode *node, FILE *out)
-{
- while (node)
- {
- if (node->type == NODE_ENUM && !node->enm.is_template)
- {
- ASTNode *v = node->enm.variants;
- while (v)
- {
- if (v->variant.payload)
- {
- char *tstr = type_to_string(v->variant.payload);
- fprintf(out, "%s %s_%s(%s v);\n", node->enm.name, node->enm.name,
- v->variant.name, tstr);
- free(tstr);
- }
- else
- {
- fprintf(out, "%s %s_%s();\n", node->enm.name, node->enm.name, v->variant.name);
- }
- v = v->next;
- }
+void emit_enum_protos(ASTNode *node, FILE *out) {
+ while (node) {
+ if (node->type == NODE_ENUM && !node->enm.is_template) {
+ ASTNode *v = node->enm.variants;
+ while (v) {
+ if (v->variant.payload) {
+ char *tstr = type_to_string(v->variant.payload);
+ fprintf(out, "%s %s_%s(%s v);\n", node->enm.name, node->enm.name,
+ v->variant.name, tstr);
+ free(tstr);
+ } else {
+ fprintf(out, "%s %s_%s();\n", node->enm.name, node->enm.name,
+ v->variant.name);
}
- node = node->next;
+ v = v->next;
+ }
}
+ node = node->next;
+ }
}
// Emit lambda definitions.
-void emit_lambda_defs(ParserContext *ctx, FILE *out)
-{
- LambdaRef *cur = ctx->global_lambdas;
- while (cur)
- {
- ASTNode *node = cur->node;
- int saved_defer = defer_count;
- defer_count = 0;
-
- if (node->lambda.num_captures > 0)
- {
- fprintf(out, "struct Lambda_%d_Ctx {\n", node->lambda.lambda_id);
- for (int i = 0; i < node->lambda.num_captures; i++)
- {
- fprintf(out, " %s %s;\n", node->lambda.captured_types[i],
- node->lambda.captured_vars[i]);
- }
- fprintf(out, "};\n");
- }
+void emit_lambda_defs(ParserContext *ctx, FILE *out) {
+ LambdaRef *cur = ctx->global_lambdas;
+ while (cur) {
+ ASTNode *node = cur->node;
+ int saved_defer = defer_count;
+ defer_count = 0;
+
+ if (node->lambda.num_captures > 0) {
+ fprintf(out, "struct Lambda_%d_Ctx {\n", node->lambda.lambda_id);
+ for (int i = 0; i < node->lambda.num_captures; i++) {
+ fprintf(out, " %s %s;\n", node->lambda.captured_types[i],
+ node->lambda.captured_vars[i]);
+ }
+ fprintf(out, "};\n");
+ }
- fprintf(out, "%s _lambda_%d(void* _ctx", node->lambda.return_type, node->lambda.lambda_id);
+ fprintf(out, "%s _lambda_%d(void* _ctx", node->lambda.return_type,
+ node->lambda.lambda_id);
- for (int i = 0; i < node->lambda.num_params; i++)
- {
- fprintf(out, ", %s %s", node->lambda.param_types[i], node->lambda.param_names[i]);
- }
- fprintf(out, ") {\n");
+ for (int i = 0; i < node->lambda.num_params; i++) {
+ fprintf(out, ", %s %s", node->lambda.param_types[i],
+ node->lambda.param_names[i]);
+ }
+ fprintf(out, ") {\n");
- if (node->lambda.num_captures > 0)
- {
- fprintf(out, " struct Lambda_%d_Ctx* ctx = (struct Lambda_%d_Ctx*)_ctx;\n",
- node->lambda.lambda_id, node->lambda.lambda_id);
- }
+ if (node->lambda.num_captures > 0) {
+ fprintf(out,
+ " struct Lambda_%d_Ctx* ctx = (struct Lambda_%d_Ctx*)_ctx;\n",
+ node->lambda.lambda_id, node->lambda.lambda_id);
+ }
- g_current_lambda = node;
- if (node->lambda.body && node->lambda.body->type == NODE_BLOCK)
- {
- codegen_walker(ctx, node->lambda.body->block.statements, out);
- }
- g_current_lambda = NULL;
+ g_current_lambda = node;
+ if (node->lambda.body && node->lambda.body->type == NODE_BLOCK) {
+ codegen_walker(ctx, node->lambda.body->block.statements, out);
+ }
+ g_current_lambda = NULL;
- for (int i = defer_count - 1; i >= 0; i--)
- {
- codegen_node_single(ctx, defer_stack[i], out);
- }
+ for (int i = defer_count - 1; i >= 0; i--) {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
- fprintf(out, "}\n\n");
+ fprintf(out, "}\n\n");
- defer_count = saved_defer;
- cur = cur->next;
- }
+ defer_count = saved_defer;
+ cur = cur->next;
+ }
}
// Emit struct and enum definitions.
-void emit_struct_defs(ParserContext *ctx, ASTNode *node, FILE *out)
-{
- while (node)
- {
- if (node->type == NODE_STRUCT && node->strct.is_template)
- {
- node = node->next;
- continue;
+void emit_struct_defs(ParserContext *ctx, ASTNode *node, FILE *out) {
+ while (node) {
+ if (node->type == NODE_STRUCT && node->strct.is_template) {
+ node = node->next;
+ continue;
+ }
+ if (node->type == NODE_ENUM && node->enm.is_template) {
+ node = node->next;
+ continue;
+ }
+ if (node->type == NODE_STRUCT) {
+ if (node->strct.is_incomplete) {
+ // Forward declaration - no body needed (typedef handles it)
+ node = node->next;
+ continue;
+ }
+
+ if (node->strct.is_union) {
+ fprintf(out, "union %s {", node->strct.name);
+ } else {
+ fprintf(out, "struct %s {", node->strct.name);
+ }
+ fprintf(out, "\n");
+ codegen_walker(ctx, node->strct.fields, out);
+ fprintf(out, "}");
+
+ if (node->strct.is_packed && node->strct.align) {
+ fprintf(out, " __attribute__((packed, aligned(%d)))",
+ node->strct.align);
+ } else if (node->strct.is_packed) {
+ fprintf(out, " __attribute__((packed))");
+ } else if (node->strct.align) {
+ fprintf(out, " __attribute__((aligned(%d)))", node->strct.align);
+ }
+ fprintf(out, ";\n\n");
+ } else if (node->type == NODE_ENUM) {
+ fprintf(out, "typedef enum { ");
+ ASTNode *v = node->enm.variants;
+ while (v) {
+ fprintf(out, "%s_%s_Tag, ", node->enm.name, v->variant.name);
+ v = v->next;
+ }
+ fprintf(out, "} %s_Tag;\n", node->enm.name);
+ fprintf(out, "struct %s { %s_Tag tag; union { ", node->enm.name,
+ node->enm.name);
+ v = node->enm.variants;
+ while (v) {
+ if (v->variant.payload) {
+ char *tstr = type_to_string(v->variant.payload);
+ fprintf(out, "%s %s; ", tstr, v->variant.name);
+ free(tstr);
}
- if (node->type == NODE_ENUM && node->enm.is_template)
- {
- node = node->next;
- continue;
+ v = v->next;
+ }
+ fprintf(out, "} data; };\n\n");
+ v = node->enm.variants;
+ while (v) {
+ if (v->variant.payload) {
+ char *tstr = type_to_string(v->variant.payload);
+ fprintf(out,
+ "%s %s_%s(%s v) { return (%s){.tag=%s_%s_Tag, "
+ ".data.%s=v}; }\n",
+ node->enm.name, node->enm.name, v->variant.name, tstr,
+ node->enm.name, node->enm.name, v->variant.name,
+ v->variant.name);
+ free(tstr);
+ } else {
+ fprintf(out, "%s %s_%s() { return (%s){.tag=%s_%s_Tag}; }\n",
+ node->enm.name, node->enm.name, v->variant.name,
+ node->enm.name, node->enm.name, v->variant.name);
}
- if (node->type == NODE_STRUCT)
- {
- if (node->strct.is_incomplete)
- {
- // Forward declaration - no body needed (typedef handles it)
- node = node->next;
- continue;
- }
+ v = v->next;
+ }
+ }
+ node = node->next;
+ }
+}
- if (node->strct.is_union)
- {
- fprintf(out, "union %s {", node->strct.name);
- }
- else
- {
- fprintf(out, "struct %s {", node->strct.name);
- }
- fprintf(out, "\n");
- codegen_walker(ctx, node->strct.fields, out);
- fprintf(out, "}");
+// Emit trait definitions.
+void emit_trait_defs(ASTNode *node, FILE *out) {
+ while (node) {
+ if (node->type == NODE_TRAIT) {
+ fprintf(out, "typedef struct %s_VTable {\n", node->trait.name);
+ ASTNode *m = node->trait.methods;
+ while (m) {
+ fprintf(out, " %s (*%s)(", m->func.ret_type,
+ parse_original_method_name(m->func.name));
+ int has_self = (m->func.args && strstr(m->func.args, "self"));
+ if (!has_self) {
+ fprintf(out, "void* self");
+ }
- if (node->strct.is_packed && node->strct.align)
- {
- fprintf(out, " __attribute__((packed, aligned(%d)))", node->strct.align);
- }
- else if (node->strct.is_packed)
- {
- fprintf(out, " __attribute__((packed))");
- }
- else if (node->strct.align)
- {
- fprintf(out, " __attribute__((aligned(%d)))", node->strct.align);
- }
- fprintf(out, ";\n\n");
+ if (m->func.args) {
+ if (!has_self) {
+ fprintf(out, ", ");
+ }
+ fprintf(out, "%s", m->func.args);
}
- else if (node->type == NODE_ENUM)
- {
- fprintf(out, "typedef enum { ");
- ASTNode *v = node->enm.variants;
- while (v)
- {
- fprintf(out, "%s_%s_Tag, ", node->enm.name, v->variant.name);
- v = v->next;
- }
- fprintf(out, "} %s_Tag;\n", node->enm.name);
- fprintf(out, "struct %s { %s_Tag tag; union { ", node->enm.name, node->enm.name);
- v = node->enm.variants;
- while (v)
- {
- if (v->variant.payload)
- {
- char *tstr = type_to_string(v->variant.payload);
- fprintf(out, "%s %s; ", tstr, v->variant.name);
- free(tstr);
- }
- v = v->next;
- }
- fprintf(out, "} data; };\n\n");
- v = node->enm.variants;
- while (v)
- {
- if (v->variant.payload)
- {
- char *tstr = type_to_string(v->variant.payload);
- fprintf(out,
- "%s %s_%s(%s v) { return (%s){.tag=%s_%s_Tag, "
- ".data.%s=v}; }\n",
- node->enm.name, node->enm.name, v->variant.name, tstr, node->enm.name,
- node->enm.name, v->variant.name, v->variant.name);
- free(tstr);
- }
- else
- {
- fprintf(out, "%s %s_%s() { return (%s){.tag=%s_%s_Tag}; }\n", node->enm.name,
- node->enm.name, v->variant.name, node->enm.name, node->enm.name,
- v->variant.name);
- }
- v = v->next;
- }
+ fprintf(out, ");\n");
+ m = m->next;
+ }
+ fprintf(out, "} %s_VTable;\n", node->trait.name);
+ fprintf(out, "typedef struct %s { void *self; %s_VTable *vtable; } %s;\n",
+ node->trait.name, node->trait.name, node->trait.name);
+
+ m = node->trait.methods;
+ while (m) {
+ const char *orig = parse_original_method_name(m->func.name);
+ fprintf(out, "%s %s_%s(%s* self", m->func.ret_type, node->trait.name,
+ orig, node->trait.name);
+
+ int has_self = (m->func.args && strstr(m->func.args, "self"));
+ if (m->func.args) {
+ if (has_self) {
+ char *comma = strchr(m->func.args, ',');
+ if (comma) {
+ fprintf(out, ", %s", comma + 1);
+ }
+ } else {
+ fprintf(out, ", %s", m->func.args);
+ }
}
- node = node->next;
- }
-}
+ fprintf(out, ") {\n");
-// Emit trait definitions.
-void emit_trait_defs(ASTNode *node, FILE *out)
-{
- while (node)
- {
- if (node->type == NODE_TRAIT)
- {
- fprintf(out, "typedef struct %s_VTable {\n", node->trait.name);
- ASTNode *m = node->trait.methods;
- while (m)
- {
- fprintf(out, " %s (*%s)(", m->func.ret_type,
- parse_original_method_name(m->func.name));
- int has_self = (m->func.args && strstr(m->func.args, "self"));
- if (!has_self)
- {
- fprintf(out, "void* self");
- }
-
- if (m->func.args)
- {
- if (!has_self)
- {
- fprintf(out, ", ");
- }
- fprintf(out, "%s", m->func.args);
- }
- fprintf(out, ");\n");
- m = m->next;
+ fprintf(out, " return self->vtable->%s(self->self", orig);
+
+ if (m->func.args) {
+ char *call_args = extract_call_args(m->func.args);
+ if (has_self) {
+ char *comma = strchr(call_args, ',');
+ if (comma) {
+ fprintf(out, ", %s", comma + 1);
}
- fprintf(out, "} %s_VTable;\n", node->trait.name);
- fprintf(out, "typedef struct %s { void *self; %s_VTable *vtable; } %s;\n",
- node->trait.name, node->trait.name, node->trait.name);
-
- m = node->trait.methods;
- while (m)
- {
- const char *orig = parse_original_method_name(m->func.name);
- fprintf(out, "%s %s_%s(%s* self", m->func.ret_type, node->trait.name, orig,
- node->trait.name);
-
- int has_self = (m->func.args && strstr(m->func.args, "self"));
- if (m->func.args)
- {
- if (has_self)
- {
- char *comma = strchr(m->func.args, ',');
- if (comma)
- {
- fprintf(out, ", %s", comma + 1);
- }
- }
- else
- {
- fprintf(out, ", %s", m->func.args);
- }
- }
- fprintf(out, ") {\n");
-
- fprintf(out, " return self->vtable->%s(self->self", orig);
-
- if (m->func.args)
- {
- char *call_args = extract_call_args(m->func.args);
- if (has_self)
- {
- char *comma = strchr(call_args, ',');
- if (comma)
- {
- fprintf(out, ", %s", comma + 1);
- }
- }
- else
- {
- if (strlen(call_args) > 0)
- {
- fprintf(out, ", %s", call_args);
- }
- }
- free(call_args);
- }
- fprintf(out, ");\n}\n");
-
- m = m->next;
+ } else {
+ if (strlen(call_args) > 0) {
+ fprintf(out, ", %s", call_args);
}
- fprintf(out, "\n");
+ }
+ free(call_args);
}
- node = node->next;
+ fprintf(out, ");\n}\n");
+
+ m = m->next;
+ }
+ fprintf(out, "\n");
}
+ node = node->next;
+ }
}
// Emit global variables
-void emit_globals(ParserContext *ctx, ASTNode *node, FILE *out)
-{
- while (node)
- {
- if (node->type == NODE_VAR_DECL || node->type == NODE_CONST)
- {
- if (node->type == NODE_CONST)
- {
- fprintf(out, "const ");
- }
- if (node->var_decl.type_str)
- {
- emit_var_decl_type(ctx, out, node->var_decl.type_str, node->var_decl.name);
- }
- else
- {
- char *inferred = NULL;
- if (node->var_decl.init_expr)
- {
- inferred = infer_type(ctx, node->var_decl.init_expr);
- }
-
- if (inferred && strcmp(inferred, "__auto_type") != 0)
- {
- emit_var_decl_type(ctx, out, inferred, node->var_decl.name);
- }
- else
- {
- emit_auto_type(ctx, node->var_decl.init_expr, node->token, out);
- fprintf(out, " %s", node->var_decl.name);
- }
- }
- if (node->var_decl.init_expr)
- {
- fprintf(out, " = ");
- codegen_expression(ctx, node->var_decl.init_expr, out);
- }
- fprintf(out, ";\n");
+void emit_globals(ParserContext *ctx, ASTNode *node, FILE *out) {
+ while (node) {
+ if (node->type == NODE_VAR_DECL || node->type == NODE_CONST) {
+ if (node->type == NODE_CONST) {
+ fprintf(out, "const ");
+ }
+ if (node->var_decl.type_str) {
+ emit_var_decl_type(ctx, out, node->var_decl.type_str,
+ node->var_decl.name);
+ } else {
+ char *inferred = NULL;
+ if (node->var_decl.init_expr) {
+ inferred = infer_type(ctx, node->var_decl.init_expr);
}
- node = node->next;
+
+ if (inferred && strcmp(inferred, "__auto_type") != 0) {
+ emit_var_decl_type(ctx, out, inferred, node->var_decl.name);
+ } else {
+ emit_auto_type(ctx, node->var_decl.init_expr, node->token, out);
+ fprintf(out, " %s", node->var_decl.name);
+ }
+ }
+ if (node->var_decl.init_expr) {
+ fprintf(out, " = ");
+ codegen_expression(ctx, node->var_decl.init_expr, out);
+ }
+ fprintf(out, ";\n");
}
+ node = node->next;
+ }
}
// Emit function prototypes
-void emit_protos(ASTNode *node, FILE *out)
-{
- ASTNode *f = node;
- while (f)
- {
- if (f->type == NODE_FUNCTION)
- {
- if (f->func.is_async)
- {
- fprintf(out, "Async %s(%s);\n", f->func.name, f->func.args);
- // Also emit _impl_ prototype
- if (f->func.ret_type)
- {
- fprintf(out, "%s _impl_%s(%s);\n", f->func.ret_type, f->func.name,
- f->func.args);
- }
- else
- {
- fprintf(out, "void _impl_%s(%s);\n", f->func.name, f->func.args);
- }
- }
- else
- {
- fprintf(out, "%s %s(%s);\n", f->func.ret_type, f->func.name, f->func.args);
- }
+void emit_protos(ASTNode *node, FILE *out) {
+ ASTNode *f = node;
+ while (f) {
+ if (f->type == NODE_FUNCTION) {
+ if (f->func.is_async) {
+ fprintf(out, "Async %s(%s);\n", f->func.name, f->func.args);
+ // Also emit _impl_ prototype
+ if (f->func.ret_type) {
+ fprintf(out, "%s _impl_%s(%s);\n", f->func.ret_type, f->func.name,
+ f->func.args);
+ } else {
+ fprintf(out, "void _impl_%s(%s);\n", f->func.name, f->func.args);
}
- else if (f->type == NODE_IMPL)
- {
- char *sname = f->impl.struct_name;
- if (!sname)
- {
- f = f->next;
- continue;
- }
-
- char *mangled = replace_string_type(sname);
- ASTNode *def = find_struct_def_codegen(g_parser_ctx, mangled);
- int skip = 0;
- if (def)
- {
- if (def->type == NODE_STRUCT && def->strct.is_template)
- {
- skip = 1;
- }
- else if (def->type == NODE_ENUM && def->enm.is_template)
- {
- skip = 1;
- }
- }
- else
- {
- char *lt = strchr(sname, '<');
- if (lt)
- {
- int len = lt - sname;
- char *buf = xmalloc(len + 1);
- strncpy(buf, sname, len);
- buf[len] = 0;
- def = find_struct_def_codegen(g_parser_ctx, buf);
- if (def && def->strct.is_template)
- {
- skip = 1;
- }
- free(buf);
- }
- }
- if (mangled)
- {
- free(mangled);
- }
-
- if (skip)
- {
- f = f->next;
- continue;
- }
-
- ASTNode *m = f->impl.methods;
- while (m)
- {
- char *fname = m->func.name;
- char *proto = xmalloc(strlen(fname) + strlen(sname) + 2);
- int slen = strlen(sname);
- if (strncmp(fname, sname, slen) == 0 && fname[slen] == '_')
- {
- strcpy(proto, fname);
- }
- else
- {
- sprintf(proto, "%s_%s", sname, fname);
- }
-
- if (m->func.is_async)
- {
- fprintf(out, "Async %s(%s);\n", proto, m->func.args);
- }
- else
- {
- fprintf(out, "%s %s(%s);\n", m->func.ret_type, proto, m->func.args);
- }
-
- free(proto);
- m = m->next;
- }
+ } else {
+ fprintf(out, "%s %s(%s);\n", f->func.ret_type, f->func.name,
+ f->func.args);
+ }
+ } else if (f->type == NODE_IMPL) {
+ char *sname = f->impl.struct_name;
+ if (!sname) {
+ f = f->next;
+ continue;
+ }
+
+ char *mangled = replace_string_type(sname);
+ ASTNode *def = find_struct_def_codegen(g_parser_ctx, mangled);
+ int skip = 0;
+ if (def) {
+ if (def->type == NODE_STRUCT && def->strct.is_template) {
+ skip = 1;
+ } else if (def->type == NODE_ENUM && def->enm.is_template) {
+ skip = 1;
}
- else if (f->type == NODE_IMPL_TRAIT)
- {
- char *sname = f->impl_trait.target_type;
- if (!sname)
- {
- f = f->next;
- continue;
- }
+ } else {
+ char *lt = strchr(sname, '<');
+ if (lt) {
+ int len = lt - sname;
+ char *buf = xmalloc(len + 1);
+ strncpy(buf, sname, len);
+ buf[len] = 0;
+ def = find_struct_def_codegen(g_parser_ctx, buf);
+ if (def && def->strct.is_template) {
+ skip = 1;
+ }
+ free(buf);
+ }
+ }
+ if (mangled) {
+ free(mangled);
+ }
- char *mangled = replace_string_type(sname);
- ASTNode *def = find_struct_def_codegen(g_parser_ctx, mangled);
- int skip = 0;
- if (def)
- {
- if (def->strct.is_template)
- {
- skip = 1;
- }
- }
- else
- {
- char *lt = strchr(sname, '<');
- if (lt)
- {
- int len = lt - sname;
- char *buf = xmalloc(len + 1);
- strncpy(buf, sname, len);
- buf[len] = 0;
- def = find_struct_def_codegen(g_parser_ctx, buf);
- if (def && def->strct.is_template)
- {
- skip = 1;
- }
- free(buf);
- }
- }
- if (mangled)
- {
- free(mangled);
- }
+ if (skip) {
+ f = f->next;
+ continue;
+ }
+
+ ASTNode *m = f->impl.methods;
+ while (m) {
+ char *fname = m->func.name;
+ char *proto = xmalloc(strlen(fname) + strlen(sname) + 2);
+ int slen = strlen(sname);
+ if (strncmp(fname, sname, slen) == 0 && fname[slen] == '_') {
+ strcpy(proto, fname);
+ } else {
+ sprintf(proto, "%s_%s", sname, fname);
+ }
- if (skip)
- {
- f = f->next;
- continue;
- }
+ if (m->func.is_async) {
+ fprintf(out, "Async %s(%s);\n", proto, m->func.args);
+ } else {
+ fprintf(out, "%s %s(%s);\n", m->func.ret_type, proto, m->func.args);
+ }
- ASTNode *m = f->impl_trait.methods;
- while (m)
- {
- if (m->func.is_async)
- {
- fprintf(out, "Async %s(%s);\n", m->func.name, m->func.args);
- }
- else
- {
- fprintf(out, "%s %s(%s);\n", m->func.ret_type, m->func.name, m->func.args);
- }
- m = m->next;
- }
- // RAII: Emit glue prototype
- if (strcmp(f->impl_trait.trait_name, "Drop") == 0)
- {
- char *tname = f->impl_trait.target_type;
- fprintf(out, "void %s_Drop_glue(%s *self);\n", tname, tname);
- }
+ free(proto);
+ m = m->next;
+ }
+ } else if (f->type == NODE_IMPL_TRAIT) {
+ char *sname = f->impl_trait.target_type;
+ if (!sname) {
+ f = f->next;
+ continue;
+ }
+
+ char *mangled = replace_string_type(sname);
+ ASTNode *def = find_struct_def_codegen(g_parser_ctx, mangled);
+ int skip = 0;
+ if (def) {
+ if (def->strct.is_template) {
+ skip = 1;
}
+ } else {
+ char *lt = strchr(sname, '<');
+ if (lt) {
+ int len = lt - sname;
+ char *buf = xmalloc(len + 1);
+ strncpy(buf, sname, len);
+ buf[len] = 0;
+ def = find_struct_def_codegen(g_parser_ctx, buf);
+ if (def && def->strct.is_template) {
+ skip = 1;
+ }
+ free(buf);
+ }
+ }
+ if (mangled) {
+ free(mangled);
+ }
+
+ if (skip) {
f = f->next;
+ continue;
+ }
+
+ ASTNode *m = f->impl_trait.methods;
+ while (m) {
+ if (m->func.is_async) {
+ fprintf(out, "Async %s(%s);\n", m->func.name, m->func.args);
+ } else {
+ fprintf(out, "%s %s(%s);\n", m->func.ret_type, m->func.name,
+ m->func.args);
+ }
+ m = m->next;
+ }
+ // RAII: Emit glue prototype
+ if (strcmp(f->impl_trait.trait_name, "Drop") == 0) {
+ char *tname = f->impl_trait.target_type;
+ fprintf(out, "void %s_Drop_glue(%s *self);\n", tname, tname);
+ }
}
+ f = f->next;
+ }
}
// Emit VTable instances for trait implementations.
-void emit_impl_vtables(ParserContext *ctx, FILE *out)
-{
- StructRef *ref = ctx->parsed_impls_list;
- struct
- {
- char *trait;
- char *strct;
- } emitted[1024];
- int count = 0;
-
- while (ref)
- {
- ASTNode *node = ref->node;
- if (node && node->type == NODE_IMPL_TRAIT)
- {
- char *trait = node->impl_trait.trait_name;
- char *strct = node->impl_trait.target_type;
-
- // Filter templates
- char *mangled = replace_string_type(strct);
- ASTNode *def = find_struct_def_codegen(ctx, mangled);
- int skip = 0;
- if (def)
- {
- if (def->type == NODE_STRUCT && def->strct.is_template)
- {
- skip = 1;
- }
- else if (def->type == NODE_ENUM && def->enm.is_template)
- {
- skip = 1;
- }
- }
- else
- {
- char *lt = strchr(strct, '<');
- if (lt)
- {
- int len = lt - strct;
- char *buf = xmalloc(len + 1);
- strncpy(buf, strct, len);
- buf[len] = 0;
- def = find_struct_def_codegen(ctx, buf);
- if (def && def->strct.is_template)
- {
- skip = 1;
- }
- free(buf);
- }
- }
- if (mangled)
- {
- free(mangled);
- }
- if (skip)
- {
- ref = ref->next;
- continue;
- }
-
- // Check duplication
- int dup = 0;
- for (int i = 0; i < count; i++)
- {
- if (strcmp(emitted[i].trait, trait) == 0 && strcmp(emitted[i].strct, strct) == 0)
- {
- dup = 1;
- break;
- }
- }
- if (dup)
- {
- ref = ref->next;
- continue;
- }
-
- emitted[count].trait = trait;
- emitted[count].strct = strct;
- count++;
-
- fprintf(out, "%s_VTable %s_%s_VTable = {", trait, strct, trait);
-
- ASTNode *m = node->impl_trait.methods;
- while (m)
- {
- const char *orig = parse_original_method_name(m->func.name);
- fprintf(out, ".%s = (__typeof__(((%s_VTable*)0)->%s))%s_%s_%s", orig, trait, orig,
- strct, trait, orig);
- if (m->next)
- {
- fprintf(out, ", ");
- }
- m = m->next;
- }
- fprintf(out, "};\n");
+void emit_impl_vtables(ParserContext *ctx, FILE *out) {
+ StructRef *ref = ctx->parsed_impls_list;
+ struct {
+ char *trait;
+ char *strct;
+ } emitted[1024];
+ int count = 0;
+
+ while (ref) {
+ ASTNode *node = ref->node;
+ if (node && node->type == NODE_IMPL_TRAIT) {
+ char *trait = node->impl_trait.trait_name;
+ char *strct = node->impl_trait.target_type;
+
+ // Filter templates
+ char *mangled = replace_string_type(strct);
+ ASTNode *def = find_struct_def_codegen(ctx, mangled);
+ int skip = 0;
+ if (def) {
+ if (def->type == NODE_STRUCT && def->strct.is_template) {
+ skip = 1;
+ } else if (def->type == NODE_ENUM && def->enm.is_template) {
+ skip = 1;
+ }
+ } else {
+ char *lt = strchr(strct, '<');
+ if (lt) {
+ int len = lt - strct;
+ char *buf = xmalloc(len + 1);
+ strncpy(buf, strct, len);
+ buf[len] = 0;
+ def = find_struct_def_codegen(ctx, buf);
+ if (def && def->strct.is_template) {
+ skip = 1;
+ }
+ free(buf);
+ }
+ }
+ if (mangled) {
+ free(mangled);
+ }
+ if (skip) {
+ ref = ref->next;
+ continue;
+ }
+
+ // Check duplication
+ int dup = 0;
+ for (int i = 0; i < count; i++) {
+ if (strcmp(emitted[i].trait, trait) == 0 &&
+ strcmp(emitted[i].strct, strct) == 0) {
+ dup = 1;
+ break;
}
+ }
+ if (dup) {
ref = ref->next;
+ continue;
+ }
+
+ emitted[count].trait = trait;
+ emitted[count].strct = strct;
+ count++;
+
+ fprintf(out, "%s_VTable %s_%s_VTable = {", trait, strct, trait);
+
+ ASTNode *m = node->impl_trait.methods;
+ while (m) {
+ const char *orig = parse_original_method_name(m->func.name);
+ fprintf(out, ".%s = (__typeof__(((%s_VTable*)0)->%s))%s_%s_%s", orig,
+ trait, orig, strct, trait, orig);
+ if (m->next) {
+ fprintf(out, ", ");
+ }
+ m = m->next;
+ }
+ fprintf(out, "};\n");
}
+ ref = ref->next;
+ }
}
// Emit test functions and runner
-void emit_tests_and_runner(ParserContext *ctx, ASTNode *node, FILE *out)
-{
- ASTNode *cur = node;
- int test_count = 0;
- while (cur)
- {
- if (cur->type == NODE_TEST)
- {
- fprintf(out, "static void _z_test_%d() {\n", test_count);
- codegen_walker(ctx, cur->test_stmt.body, out);
- fprintf(out, "}\n");
- test_count++;
- }
- cur = cur->next;
+void emit_tests_and_runner(ParserContext *ctx, ASTNode *node, FILE *out) {
+ ASTNode *cur = node;
+ int test_count = 0;
+ while (cur) {
+ if (cur->type == NODE_TEST) {
+ fprintf(out, "static void _z_test_%d() {\n", test_count);
+ codegen_walker(ctx, cur->test_stmt.body, out);
+ fprintf(out, "}\n");
+ test_count++;
}
- if (test_count > 0)
- {
- fprintf(out, "\nvoid _z_run_tests() {\n");
- for (int i = 0; i < test_count; i++)
- {
- fprintf(out, " _z_test_%d();\n", i);
- }
- fprintf(out, "}\n\n");
- }
- else
- {
- fprintf(out, "void _z_run_tests() {}\n");
+ cur = cur->next;
+ }
+ if (test_count > 0) {
+ fprintf(out, "\nvoid _z_run_tests() {\n");
+ for (int i = 0; i < test_count; i++) {
+ fprintf(out, " _z_test_%d();\n", i);
}
+ fprintf(out, "}\n\n");
+ } else {
+ fprintf(out, "void _z_run_tests() {}\n");
+ }
}
// Emit type definitions-
-void print_type_defs(ParserContext *ctx, FILE *out, ASTNode *nodes)
-{
- if (!g_config.is_freestanding)
- {
- fprintf(out, "typedef char* string;\n");
- }
-
- fprintf(out, "typedef struct { void **data; int len; int cap; } Vec;\n");
- fprintf(out, "#define Vec_new() (Vec){.data=0, .len=0, .cap=0}\n");
- fprintf(out, "void _z_vec_push(Vec *v, void *item) { if(v->len >= v->cap) { "
- "v->cap = v->cap?v->cap*2:8; "
- "v->data = z_realloc(v->data, v->cap * sizeof(void*)); } "
- "v->data[v->len++] = item; }\n");
- fprintf(out, "#define Vec_push(v, i) _z_vec_push(&(v), (void*)(long)(i))\n");
- fprintf(out, "static inline Vec _z_make_vec(int count, ...) { Vec v = {0}; v.cap = "
- "count > 8 ? "
- "count : 8; v.data = z_malloc(v.cap * sizeof(void*)); v.len = 0; va_list "
- "args; "
- "va_start(args, count); for(int i=0; i<count; i++) { v.data[v.len++] = "
- "va_arg(args, void*); } va_end(args); return v; }\n");
-
- if (g_config.is_freestanding)
- {
- fprintf(out, "#define _z_check_bounds(index, limit) ({ __auto_type _i = "
- "(index); if(_i < 0 "
- "|| _i >= (limit)) { z_panic(\"index out of bounds\"); } _i; })\n");
+void print_type_defs(ParserContext *ctx, FILE *out, ASTNode *nodes) {
+ if (!g_config.is_freestanding) {
+ fprintf(out, "typedef char* string;\n");
+ }
+
+ fprintf(out, "typedef struct { void **data; int len; int cap; } Vec;\n");
+ fprintf(out, "#define Vec_new() (Vec){.data=0, .len=0, .cap=0}\n");
+ fprintf(out, "void _z_vec_push(Vec *v, void *item) { if(v->len >= v->cap) { "
+ "v->cap = v->cap?v->cap*2:8; "
+ "v->data = z_realloc(v->data, v->cap * sizeof(void*)); } "
+ "v->data[v->len++] = item; }\n");
+ fprintf(out, "#define Vec_push(v, i) _z_vec_push(&(v), (void*)(long)(i))\n");
+ fprintf(
+ out,
+ "static inline Vec _z_make_vec(int count, ...) { Vec v = {0}; v.cap = "
+ "count > 8 ? "
+ "count : 8; v.data = z_malloc(v.cap * sizeof(void*)); v.len = 0; va_list "
+ "args; "
+ "va_start(args, count); for(int i=0; i<count; i++) { v.data[v.len++] = "
+ "va_arg(args, void*); } va_end(args); return v; }\n");
+
+ if (g_config.is_freestanding) {
+ fprintf(out,
+ "#define _z_check_bounds(index, limit) ({ __auto_type _i = "
+ "(index); if(_i < 0 "
+ "|| _i >= (limit)) { z_panic(\"index out of bounds\"); } _i; })\n");
+ } else {
+ fprintf(out, "#define _z_check_bounds(index, limit) ({ __auto_type _i = "
+ "(index); if(_i < 0 "
+ "|| _i >= (limit)) { fprintf(stderr, \"Index out of bounds: "
+ "%%ld (limit "
+ "%%d)\\n\", (long)_i, (int)(limit)); exit(1); } _i; })\n");
+ }
+
+ SliceType *c = ctx->used_slices;
+ while (c) {
+ fprintf(out,
+ "typedef struct Slice_%s Slice_%s;\nstruct Slice_%s { %s *data; "
+ "int len; int cap; };\n",
+ c->name, c->name, c->name, c->name);
+ c = c->next;
+ }
+
+ TupleType *t = ctx->used_tuples;
+ while (t) {
+ fprintf(out, "typedef struct Tuple_%s Tuple_%s;\nstruct Tuple_%s { ",
+ t->sig, t->sig, t->sig);
+ char *s = xstrdup(t->sig);
+ char *p = strtok(s, "_");
+ int i = 0;
+ while (p) {
+ fprintf(out, "%s v%d; ", p, i++);
+ p = strtok(NULL, "_");
}
- else
- {
- fprintf(out, "#define _z_check_bounds(index, limit) ({ __auto_type _i = "
- "(index); if(_i < 0 "
- "|| _i >= (limit)) { fprintf(stderr, \"Index out of bounds: "
- "%%ld (limit "
- "%%d)\\n\", (long)_i, (int)(limit)); exit(1); } _i; })\n");
+ free(s);
+ fprintf(out, "};\n");
+ t = t->next;
+ }
+ fprintf(out, "\n");
+
+ // FIRST: Emit typedefs for ALL structs and enums in the current compilation
+ // unit (local definitions)
+ ASTNode *local = nodes;
+ while (local) {
+ if (local->type == NODE_STRUCT && !local->strct.is_template) {
+ const char *keyword = local->strct.is_union ? "union" : "struct";
+ fprintf(out, "typedef %s %s %s;\n", keyword, local->strct.name,
+ local->strct.name);
}
-
- SliceType *c = ctx->used_slices;
- while (c)
- {
- fprintf(out,
- "typedef struct Slice_%s Slice_%s;\nstruct Slice_%s { %s *data; "
- "int len; int cap; };\n",
- c->name, c->name, c->name, c->name);
- c = c->next;
+ if (local->type == NODE_ENUM && !local->enm.is_template) {
+ fprintf(out, "typedef struct %s %s;\n", local->enm.name, local->enm.name);
}
-
- TupleType *t = ctx->used_tuples;
- while (t)
- {
- fprintf(out, "typedef struct Tuple_%s Tuple_%s;\nstruct Tuple_%s { ", t->sig, t->sig,
- t->sig);
- char *s = xstrdup(t->sig);
- char *p = strtok(s, "_");
- int i = 0;
- while (p)
- {
- fprintf(out, "%s v%d; ", p, i++);
- p = strtok(NULL, "_");
- }
- free(s);
- fprintf(out, "};\n");
- t = t->next;
+ local = local->next;
+ }
+
+ // THEN: Emit typedefs for instantiated generics
+ Instantiation *i = ctx->instantiations;
+ while (i) {
+ if (i->struct_node->type == NODE_RAW_STMT) {
+ fprintf(out, "%s\n", i->struct_node->raw_stmt.content);
+ } else {
+ fprintf(out, "typedef struct %s %s;\n", i->struct_node->strct.name,
+ i->struct_node->strct.name);
+ codegen_node(ctx, i->struct_node, out);
}
- fprintf(out, "\n");
-
- // FIRST: Emit typedefs for ALL structs and enums in the current compilation
- // unit (local definitions)
- ASTNode *local = nodes;
- while (local)
- {
- if (local->type == NODE_STRUCT && !local->strct.is_template)
- {
- const char *keyword = local->strct.is_union ? "union" : "struct";
- fprintf(out, "typedef %s %s %s;\n", keyword, local->strct.name, local->strct.name);
- }
- if (local->type == NODE_ENUM && !local->enm.is_template)
- {
- fprintf(out, "typedef struct %s %s;\n", local->enm.name, local->enm.name);
- }
- local = local->next;
+ i = i->next;
+ }
+
+ StructRef *sr = ctx->parsed_structs_list;
+ while (sr) {
+ if (sr->node && sr->node->type == NODE_STRUCT &&
+ !sr->node->strct.is_template) {
+ const char *keyword = sr->node->strct.is_union ? "union" : "struct";
+ fprintf(out, "typedef %s %s %s;\n", keyword, sr->node->strct.name,
+ sr->node->strct.name);
}
- // THEN: Emit typedefs for instantiated generics
- Instantiation *i = ctx->instantiations;
- while (i)
- {
- if (i->struct_node->type == NODE_RAW_STMT)
- {
- fprintf(out, "%s\n", i->struct_node->raw_stmt.content);
- }
- else
- {
- fprintf(out, "typedef struct %s %s;\n", i->struct_node->strct.name,
- i->struct_node->strct.name);
- codegen_node(ctx, i->struct_node, out);
- }
- i = i->next;
+ if (sr->node && sr->node->type == NODE_ENUM && !sr->node->enm.is_template) {
+ fprintf(out, "typedef struct %s %s;\n", sr->node->enm.name,
+ sr->node->enm.name);
}
-
- StructRef *sr = ctx->parsed_structs_list;
- while (sr)
- {
- if (sr->node && sr->node->type == NODE_STRUCT && !sr->node->strct.is_template)
- {
- const char *keyword = sr->node->strct.is_union ? "union" : "struct";
- fprintf(out, "typedef %s %s %s;\n", keyword, sr->node->strct.name,
- sr->node->strct.name);
- }
-
- if (sr->node && sr->node->type == NODE_ENUM && !sr->node->enm.is_template)
- {
- fprintf(out, "typedef struct %s %s;\n", sr->node->enm.name, sr->node->enm.name);
- }
- sr = sr->next;
+ sr = sr->next;
+ }
+
+ // Also check instantiated_structs list.
+ ASTNode *inst_s = ctx->instantiated_structs;
+ while (inst_s) {
+ if (inst_s->type == NODE_STRUCT && !inst_s->strct.is_template) {
+ const char *keyword = inst_s->strct.is_union ? "union" : "struct";
+ fprintf(out, "typedef %s %s %s;\n", keyword, inst_s->strct.name,
+ inst_s->strct.name);
}
- // Also check instantiated_structs list.
- ASTNode *inst_s = ctx->instantiated_structs;
- while (inst_s)
- {
- if (inst_s->type == NODE_STRUCT && !inst_s->strct.is_template)
- {
- const char *keyword = inst_s->strct.is_union ? "union" : "struct";
- fprintf(out, "typedef %s %s %s;\n", keyword, inst_s->strct.name, inst_s->strct.name);
- }
-
- if (inst_s->type == NODE_ENUM && !inst_s->enm.is_template)
- {
- fprintf(out, "typedef struct %s %s;\n", inst_s->enm.name, inst_s->enm.name);
- }
- inst_s = inst_s->next;
+ if (inst_s->type == NODE_ENUM && !inst_s->enm.is_template) {
+ fprintf(out, "typedef struct %s %s;\n", inst_s->enm.name,
+ inst_s->enm.name);
}
+ inst_s = inst_s->next;
+ }
}
diff --git a/src/codegen/codegen_main.c b/src/codegen/codegen_main.c
index 3634af3..3b0e4dc 100644
--- a/src/codegen/codegen_main.c
+++ b/src/codegen/codegen_main.c
@@ -7,563 +7,457 @@
#include <string.h>
// Helper: Check if a struct depends on another struct/enum by-value.
-static int struct_depends_on(ASTNode *s1, const char *target_name)
-{
- if (!s1)
- {
- return 0;
- }
-
- // Only structs have dependencies that matter for ordering.
- if (s1->type != NODE_STRUCT)
- {
- return 0;
- }
-
- ASTNode *field = s1->strct.fields;
- while (field)
- {
- if (field->type == NODE_FIELD && field->field.type)
- {
- char *type_str = field->field.type;
- // Skip pointers - they don't create ordering dependency.
- if (strchr(type_str, '*'))
- {
- field = field->next;
- continue;
- }
+static int struct_depends_on(ASTNode *s1, const char *target_name) {
+ if (!s1) {
+ return 0;
+ }
- // Check if this field's type matches target (struct or enum).
- if (strcmp(type_str, target_name) == 0)
- {
- return 1;
- }
- }
+ // Only structs have dependencies that matter for ordering.
+ if (s1->type != NODE_STRUCT) {
+ return 0;
+ }
+
+ ASTNode *field = s1->strct.fields;
+ while (field) {
+ if (field->type == NODE_FIELD && field->field.type) {
+ char *type_str = field->field.type;
+ // Skip pointers - they don't create ordering dependency.
+ if (strchr(type_str, '*')) {
field = field->next;
+ continue;
+ }
+
+ // Check if this field's type matches target (struct or enum).
+ if (strcmp(type_str, target_name) == 0) {
+ return 1;
+ }
}
- return 0;
+ field = field->next;
+ }
+ return 0;
}
// Topologically sort a list of struct/enum nodes.
-static ASTNode *topo_sort_structs(ASTNode *head)
-{
- if (!head)
- {
- return NULL;
+static ASTNode *topo_sort_structs(ASTNode *head) {
+ if (!head) {
+ return NULL;
+ }
+
+ // Count all nodes (structs + enums).
+ int count = 0;
+ ASTNode *n = head;
+ while (n) {
+ if (n->type == NODE_STRUCT || n->type == NODE_ENUM) {
+ count++;
+ }
+ n = n->next;
+ }
+ if (count == 0) {
+ return head;
+ }
+
+ // Build array of all nodes.
+ ASTNode **nodes = malloc(count * sizeof(ASTNode *));
+ int *emitted = calloc(count, sizeof(int));
+ n = head;
+ int idx = 0;
+ while (n) {
+ if (n->type == NODE_STRUCT || n->type == NODE_ENUM) {
+ nodes[idx++] = n;
}
+ n = n->next;
+ }
+
+ // Build order array (indices in emission order).
+ int *order = malloc(count * sizeof(int));
+ int order_idx = 0;
+
+ int changed = 1;
+ int max_iterations = count * count;
+ int iterations = 0;
+
+ while (changed && iterations < max_iterations) {
+ changed = 0;
+ iterations++;
+
+ for (int i = 0; i < count; i++) {
+ if (emitted[i]) {
+ continue;
+ }
+
+ // Enums have no dependencies, emit first.
+ if (nodes[i]->type == NODE_ENUM) {
+ order[order_idx++] = i;
+ emitted[i] = 1;
+ changed = 1;
+ continue;
+ }
+
+ // For structs, check if all dependencies are emitted.
+ int can_emit = 1;
+ for (int j = 0; j < count; j++) {
+ if (i == j || emitted[j]) {
+ continue;
+ }
- // Count all nodes (structs + enums).
- int count = 0;
- ASTNode *n = head;
- while (n)
- {
- if (n->type == NODE_STRUCT || n->type == NODE_ENUM)
- {
- count++;
+ // Get the name of the potential dependency.
+ const char *dep_name = NULL;
+ if (nodes[j]->type == NODE_STRUCT) {
+ dep_name = nodes[j]->strct.name;
+ } else if (nodes[j]->type == NODE_ENUM) {
+ dep_name = nodes[j]->enm.name;
}
- n = n->next;
- }
- if (count == 0)
- {
- return head;
- }
- // Build array of all nodes.
- ASTNode **nodes = malloc(count * sizeof(ASTNode *));
- int *emitted = calloc(count, sizeof(int));
- n = head;
- int idx = 0;
- while (n)
- {
- if (n->type == NODE_STRUCT || n->type == NODE_ENUM)
- {
- nodes[idx++] = n;
+ if (dep_name && struct_depends_on(nodes[i], dep_name)) {
+ can_emit = 0;
+ break;
}
- n = n->next;
- }
+ }
- // Build order array (indices in emission order).
- int *order = malloc(count * sizeof(int));
- int order_idx = 0;
+ if (can_emit) {
+ order[order_idx++] = i;
+ emitted[i] = 1;
+ changed = 1;
+ }
+ }
+ }
- int changed = 1;
- int max_iterations = count * count;
- int iterations = 0;
+ // Add any remaining nodes (cycles).
+ for (int i = 0; i < count; i++) {
+ if (!emitted[i]) {
+ order[order_idx++] = i;
+ }
+ }
+
+ // Now build the linked list in the correct order.
+ ASTNode *result = NULL;
+ ASTNode *result_tail = NULL;
+
+ for (int i = 0; i < order_idx; i++) {
+ ASTNode *node = nodes[order[i]];
+ if (!result) {
+ result = node;
+ result_tail = node;
+ } else {
+ result_tail->next = node;
+ result_tail = node;
+ }
+ }
+ if (result_tail) {
+ result_tail->next = NULL;
+ }
+
+ free(nodes);
+ free(emitted);
+ free(order);
+ return result;
+}
- while (changed && iterations < max_iterations)
- {
- changed = 0;
- iterations++;
+// Main entry point for code generation.
+void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out) {
+ if (node->type == NODE_ROOT) {
+ ASTNode *kids = node->root.children;
+ // Recursive Unwrap of Nested Roots (if accidentally wrapped multiple
+ // times).
+ while (kids && kids->type == NODE_ROOT) {
+ kids = kids->root.children;
+ }
- for (int i = 0; i < count; i++)
- {
- if (emitted[i])
- {
- continue;
- }
+ global_user_structs = kids;
- // Enums have no dependencies, emit first.
- if (nodes[i]->type == NODE_ENUM)
- {
- order[order_idx++] = i;
- emitted[i] = 1;
- changed = 1;
- continue;
- }
+ if (!ctx->skip_preamble) {
+ emit_preamble(ctx, out);
+ }
+ emit_includes_and_aliases(kids, out);
+
+ // Emit Hoisted Code (from plugins)
+ if (ctx->hoist_out) {
+ long pos = ftell(ctx->hoist_out);
+ rewind(ctx->hoist_out);
+ char buf[4096];
+ size_t n;
+ while ((n = fread(buf, 1, sizeof(buf), ctx->hoist_out)) > 0) {
+ fwrite(buf, 1, n, out);
+ }
+ fseek(ctx->hoist_out, pos, SEEK_SET);
+ }
- // For structs, check if all dependencies are emitted.
- int can_emit = 1;
- for (int j = 0; j < count; j++)
- {
- if (i == j || emitted[j])
- {
- continue;
- }
-
- // Get the name of the potential dependency.
- const char *dep_name = NULL;
- if (nodes[j]->type == NODE_STRUCT)
- {
- dep_name = nodes[j]->strct.name;
- }
- else if (nodes[j]->type == NODE_ENUM)
- {
- dep_name = nodes[j]->enm.name;
- }
-
- if (dep_name && struct_depends_on(nodes[i], dep_name))
- {
- can_emit = 0;
- break;
- }
- }
+ ASTNode *merged = NULL;
+ ASTNode *merged_tail = NULL;
+
+ ASTNode *s = ctx->instantiated_structs;
+ while (s) {
+ ASTNode *copy = xmalloc(sizeof(ASTNode));
+ *copy = *s;
+ copy->next = NULL;
+ if (!merged) {
+ merged = copy;
+ merged_tail = copy;
+ } else {
+ merged_tail->next = copy;
+ merged_tail = copy;
+ }
+ s = s->next;
+ }
- if (can_emit)
- {
- order[order_idx++] = i;
- emitted[i] = 1;
- changed = 1;
- }
+ StructRef *sr = ctx->parsed_structs_list;
+ while (sr) {
+ if (sr->node) {
+ ASTNode *copy = xmalloc(sizeof(ASTNode));
+ *copy = *sr->node;
+ copy->next = NULL;
+ if (!merged) {
+ merged = copy;
+ merged_tail = copy;
+ } else {
+ merged_tail->next = copy;
+ merged_tail = copy;
}
+ }
+ sr = sr->next;
}
- // Add any remaining nodes (cycles).
- for (int i = 0; i < count; i++)
- {
- if (!emitted[i])
- {
- order[order_idx++] = i;
+ StructRef *er = ctx->parsed_enums_list;
+ while (er) {
+ if (er->node) {
+ ASTNode *copy = xmalloc(sizeof(ASTNode));
+ *copy = *er->node;
+ copy->next = NULL;
+ if (!merged) {
+ merged = copy;
+ merged_tail = copy;
+ } else {
+ merged_tail->next = copy;
+ merged_tail = copy;
}
+ }
+ er = er->next;
}
- // Now build the linked list in the correct order.
- ASTNode *result = NULL;
- ASTNode *result_tail = NULL;
-
- for (int i = 0; i < order_idx; i++)
- {
- ASTNode *node = nodes[order[i]];
- if (!result)
- {
- result = node;
- result_tail = node;
+ ASTNode *k = kids;
+ while (k) {
+ if (k->type == NODE_STRUCT || k->type == NODE_ENUM) {
+ int found = 0;
+ ASTNode *chk = merged;
+ while (chk) {
+ if (chk->type == k->type) {
+ const char *n1 =
+ (k->type == NODE_STRUCT) ? k->strct.name : k->enm.name;
+ const char *n2 =
+ (chk->type == NODE_STRUCT) ? chk->strct.name : chk->enm.name;
+ if (n1 && n2 && strcmp(n1, n2) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ chk = chk->next;
}
- else
- {
- result_tail->next = node;
- result_tail = node;
+
+ if (!found) {
+ ASTNode *copy = xmalloc(sizeof(ASTNode));
+ *copy = *k;
+ copy->next = NULL;
+ if (!merged) {
+ merged = copy;
+ merged_tail = copy;
+ } else {
+ merged_tail->next = copy;
+ merged_tail = copy;
+ }
}
- }
- if (result_tail)
- {
- result_tail->next = NULL;
+ }
+ k = k->next;
}
- free(nodes);
- free(emitted);
- free(order);
- return result;
-}
+ // Topologically sort.
+ ASTNode *sorted = topo_sort_structs(merged);
-// Main entry point for code generation.
-void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out)
-{
- if (node->type == NODE_ROOT)
- {
- ASTNode *kids = node->root.children;
- // Recursive Unwrap of Nested Roots (if accidentally wrapped multiple
- // times).
- while (kids && kids->type == NODE_ROOT)
- {
- kids = kids->root.children;
- }
+ print_type_defs(ctx, out, sorted);
+ emit_enum_protos(sorted, out);
- global_user_structs = kids;
+ if (sorted) {
+ emit_struct_defs(ctx, sorted, out);
+ }
+ emit_trait_defs(kids, out);
+
+ ASTNode *raw_iter = kids;
+ while (raw_iter) {
+ if (raw_iter->type == NODE_RAW_STMT) {
+ fprintf(out, "%s\n", raw_iter->raw_stmt.content);
+ }
+ raw_iter = raw_iter->next;
+ }
- if (!ctx->skip_preamble)
- {
- emit_preamble(ctx, out);
- }
- emit_includes_and_aliases(kids, out);
-
- // Emit Hoisted Code (from plugins)
- if (ctx->hoist_out)
- {
- long pos = ftell(ctx->hoist_out);
- rewind(ctx->hoist_out);
- char buf[4096];
- size_t n;
- while ((n = fread(buf, 1, sizeof(buf), ctx->hoist_out)) > 0)
- {
- fwrite(buf, 1, n, out);
- }
- fseek(ctx->hoist_out, pos, SEEK_SET);
- }
+ ASTNode *merged_globals = NULL; // Head
- ASTNode *merged = NULL;
- ASTNode *merged_tail = NULL;
-
- ASTNode *s = ctx->instantiated_structs;
- while (s)
- {
- ASTNode *copy = xmalloc(sizeof(ASTNode));
- *copy = *s;
- copy->next = NULL;
- if (!merged)
- {
- merged = copy;
- merged_tail = copy;
- }
- else
- {
- merged_tail->next = copy;
- merged_tail = copy;
- }
- s = s->next;
- }
+ if (ctx->parsed_globals_list) {
+ StructRef *s = ctx->parsed_globals_list;
+ while (s) {
+ ASTNode *copy = xmalloc(sizeof(ASTNode));
+ *copy = *s->node;
+ copy->next = merged_globals;
+ merged_globals = copy;
- StructRef *sr = ctx->parsed_structs_list;
- while (sr)
- {
- if (sr->node)
- {
- ASTNode *copy = xmalloc(sizeof(ASTNode));
- *copy = *sr->node;
- copy->next = NULL;
- if (!merged)
- {
- merged = copy;
- merged_tail = copy;
- }
- else
- {
- merged_tail->next = copy;
- merged_tail = copy;
- }
- }
- sr = sr->next;
- }
+ s = s->next;
+ }
+ }
- StructRef *er = ctx->parsed_enums_list;
- while (er)
- {
- if (er->node)
- {
- ASTNode *copy = xmalloc(sizeof(ASTNode));
- *copy = *er->node;
- copy->next = NULL;
- if (!merged)
- {
- merged = copy;
- merged_tail = copy;
- }
- else
- {
- merged_tail->next = copy;
- merged_tail = copy;
- }
- }
- er = er->next;
+ emit_globals(ctx, merged_globals, out);
+
+ ASTNode *merged_funcs = NULL;
+ ASTNode *merged_funcs_tail = NULL;
+
+ if (ctx->instantiated_funcs) {
+ ASTNode *s = ctx->instantiated_funcs;
+ while (s) {
+ ASTNode *copy = xmalloc(sizeof(ASTNode));
+ *copy = *s;
+ copy->next = NULL;
+ if (!merged_funcs) {
+ merged_funcs = copy;
+ merged_funcs_tail = copy;
+ } else {
+ merged_funcs_tail->next = copy;
+ merged_funcs_tail = copy;
}
+ s = s->next;
+ }
+ }
- ASTNode *k = kids;
- while (k)
- {
- if (k->type == NODE_STRUCT || k->type == NODE_ENUM)
- {
- int found = 0;
- ASTNode *chk = merged;
- while (chk)
- {
- if (chk->type == k->type)
- {
- const char *n1 = (k->type == NODE_STRUCT) ? k->strct.name : k->enm.name;
- const char *n2 =
- (chk->type == NODE_STRUCT) ? chk->strct.name : chk->enm.name;
- if (n1 && n2 && strcmp(n1, n2) == 0)
- {
- found = 1;
- break;
- }
- }
- chk = chk->next;
- }
-
- if (!found)
- {
- ASTNode *copy = xmalloc(sizeof(ASTNode));
- *copy = *k;
- copy->next = NULL;
- if (!merged)
- {
- merged = copy;
- merged_tail = copy;
- }
- else
- {
- merged_tail->next = copy;
- merged_tail = copy;
- }
- }
- }
- k = k->next;
+ if (ctx->parsed_funcs_list) {
+ StructRef *s = ctx->parsed_funcs_list;
+ while (s) {
+ ASTNode *copy = xmalloc(sizeof(ASTNode));
+ *copy = *s->node;
+ copy->next = NULL;
+ if (!merged_funcs) {
+ merged_funcs = copy;
+ merged_funcs_tail = copy;
+ } else {
+ merged_funcs_tail->next = copy;
+ merged_funcs_tail = copy;
}
+ s = s->next;
+ }
+ }
- // Topologically sort.
- ASTNode *sorted = topo_sort_structs(merged);
+ if (ctx->parsed_impls_list) {
+ StructRef *s = ctx->parsed_impls_list;
+ while (s) {
+ ASTNode *copy = xmalloc(sizeof(ASTNode));
+ *copy = *s->node;
+ copy->next = NULL;
+ if (!merged_funcs) {
+ merged_funcs = copy;
+ merged_funcs_tail = copy;
+ } else {
+ merged_funcs_tail->next = copy;
+ merged_funcs_tail = copy;
+ }
+ s = s->next;
+ }
+ }
- print_type_defs(ctx, out, sorted);
- emit_enum_protos(sorted, out);
+ emit_protos(merged_funcs, out);
- if (sorted)
- {
- emit_struct_defs(ctx, sorted, out);
- }
- emit_trait_defs(kids, out);
-
- ASTNode *raw_iter = kids;
- while (raw_iter)
- {
- if (raw_iter->type == NODE_RAW_STMT)
- {
- fprintf(out, "%s\n", raw_iter->raw_stmt.content);
- }
- raw_iter = raw_iter->next;
- }
+ emit_impl_vtables(ctx, out);
- ASTNode *merged_globals = NULL; // Head
+ emit_lambda_defs(ctx, out);
- if (ctx->parsed_globals_list)
- {
- StructRef *s = ctx->parsed_globals_list;
- while (s)
- {
- ASTNode *copy = xmalloc(sizeof(ASTNode));
- *copy = *s->node;
- copy->next = merged_globals;
- merged_globals = copy;
+ emit_tests_and_runner(ctx, kids, out);
- s = s->next;
- }
+ ASTNode *iter = merged_funcs;
+ while (iter) {
+ if (iter->type == NODE_IMPL) {
+ char *sname = iter->impl.struct_name;
+ if (!sname) {
+ iter = iter->next;
+ continue;
}
- emit_globals(ctx, merged_globals, out);
-
- ASTNode *merged_funcs = NULL;
- ASTNode *merged_funcs_tail = NULL;
-
- if (ctx->instantiated_funcs)
- {
- ASTNode *s = ctx->instantiated_funcs;
- while (s)
- {
- ASTNode *copy = xmalloc(sizeof(ASTNode));
- *copy = *s;
- copy->next = NULL;
- if (!merged_funcs)
- {
- merged_funcs = copy;
- merged_funcs_tail = copy;
- }
- else
- {
- merged_funcs_tail->next = copy;
- merged_funcs_tail = copy;
- }
- s = s->next;
+ char *mangled = replace_string_type(sname);
+ ASTNode *def = find_struct_def_codegen(ctx, mangled);
+ int skip = 0;
+ if (def) {
+ if (def->type == NODE_STRUCT && def->strct.is_template) {
+ skip = 1;
+ } else if (def->type == NODE_ENUM && def->enm.is_template) {
+ skip = 1;
+ }
+ } else {
+ char *lt = strchr(sname, '<');
+ if (lt) {
+ int len = lt - sname;
+ char *buf = xmalloc(len + 1);
+ strncpy(buf, sname, len);
+ buf[len] = 0;
+ def = find_struct_def_codegen(ctx, buf);
+ if (def && def->strct.is_template) {
+ skip = 1;
}
+ free(buf);
+ }
}
-
- if (ctx->parsed_funcs_list)
- {
- StructRef *s = ctx->parsed_funcs_list;
- while (s)
- {
- ASTNode *copy = xmalloc(sizeof(ASTNode));
- *copy = *s->node;
- copy->next = NULL;
- if (!merged_funcs)
- {
- merged_funcs = copy;
- merged_funcs_tail = copy;
- }
- else
- {
- merged_funcs_tail->next = copy;
- merged_funcs_tail = copy;
- }
- s = s->next;
- }
+ if (mangled) {
+ free(mangled);
}
-
- if (ctx->parsed_impls_list)
- {
- StructRef *s = ctx->parsed_impls_list;
- while (s)
- {
- ASTNode *copy = xmalloc(sizeof(ASTNode));
- *copy = *s->node;
- copy->next = NULL;
- if (!merged_funcs)
- {
- merged_funcs = copy;
- merged_funcs_tail = copy;
- }
- else
- {
- merged_funcs_tail->next = copy;
- merged_funcs_tail = copy;
- }
- s = s->next;
- }
+ if (skip) {
+ iter = iter->next;
+ continue;
}
-
- emit_protos(merged_funcs, out);
-
- emit_impl_vtables(ctx, out);
-
- emit_lambda_defs(ctx, out);
-
- emit_tests_and_runner(ctx, kids, out);
-
- ASTNode *iter = merged_funcs;
- while (iter)
- {
- if (iter->type == NODE_IMPL)
- {
- char *sname = iter->impl.struct_name;
- if (!sname)
- {
- iter = iter->next;
- continue;
- }
-
- char *mangled = replace_string_type(sname);
- ASTNode *def = find_struct_def_codegen(ctx, mangled);
- int skip = 0;
- if (def)
- {
- if (def->type == NODE_STRUCT && def->strct.is_template)
- {
- skip = 1;
- }
- else if (def->type == NODE_ENUM && def->enm.is_template)
- {
- skip = 1;
- }
- }
- else
- {
- char *lt = strchr(sname, '<');
- if (lt)
- {
- int len = lt - sname;
- char *buf = xmalloc(len + 1);
- strncpy(buf, sname, len);
- buf[len] = 0;
- def = find_struct_def_codegen(ctx, buf);
- if (def && def->strct.is_template)
- {
- skip = 1;
- }
- free(buf);
- }
- }
- if (mangled)
- {
- free(mangled);
- }
- if (skip)
- {
- iter = iter->next;
- continue;
- }
- }
- if (iter->type == NODE_IMPL_TRAIT)
- {
- char *sname = iter->impl_trait.target_type;
- if (!sname)
- {
- iter = iter->next;
- continue;
- }
-
- char *mangled = replace_string_type(sname);
- ASTNode *def = find_struct_def_codegen(ctx, mangled);
- int skip = 0;
- if (def)
- {
- if (def->strct.is_template)
- {
- skip = 1;
- }
- }
- else
- {
- char *lt = strchr(sname, '<');
- if (lt)
- {
- int len = lt - sname;
- char *buf = xmalloc(len + 1);
- strncpy(buf, sname, len);
- buf[len] = 0;
- def = find_struct_def_codegen(ctx, buf);
- if (def && def->strct.is_template)
- {
- skip = 1;
- }
- free(buf);
- }
- }
- if (mangled)
- {
- free(mangled);
- }
- if (skip)
- {
- iter = iter->next;
- continue;
- }
- }
- codegen_node_single(ctx, iter, out);
- iter = iter->next;
+ }
+ if (iter->type == NODE_IMPL_TRAIT) {
+ char *sname = iter->impl_trait.target_type;
+ if (!sname) {
+ iter = iter->next;
+ continue;
}
- int has_user_main = 0;
- ASTNode *chk = merged_funcs;
- while (chk)
- {
- if (chk->type == NODE_FUNCTION && strcmp(chk->func.name, "main") == 0)
- {
- has_user_main = 1;
- break;
+ char *mangled = replace_string_type(sname);
+ ASTNode *def = find_struct_def_codegen(ctx, mangled);
+ int skip = 0;
+ if (def) {
+ if (def->strct.is_template) {
+ skip = 1;
+ }
+ } else {
+ char *lt = strchr(sname, '<');
+ if (lt) {
+ int len = lt - sname;
+ char *buf = xmalloc(len + 1);
+ strncpy(buf, sname, len);
+ buf[len] = 0;
+ def = find_struct_def_codegen(ctx, buf);
+ if (def && def->strct.is_template) {
+ skip = 1;
}
- chk = chk->next;
+ free(buf);
+ }
}
-
- if (!has_user_main)
- {
- fprintf(out, "\nint main() { _z_run_tests(); return 0; }\n");
+ if (mangled) {
+ free(mangled);
+ }
+ if (skip) {
+ iter = iter->next;
+ continue;
}
+ }
+ codegen_node_single(ctx, iter, out);
+ iter = iter->next;
+ }
+
+ int has_user_main = 0;
+ ASTNode *chk = merged_funcs;
+ while (chk) {
+ if (chk->type == NODE_FUNCTION && strcmp(chk->func.name, "main") == 0) {
+ has_user_main = 1;
+ break;
+ }
+ chk = chk->next;
+ }
+
+ if (!has_user_main) {
+ fprintf(out, "\nint main() { _z_run_tests(); return 0; }\n");
}
+ }
}
diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c
index 2feb757..c10685b 100644
--- a/src/codegen/codegen_utils.c
+++ b/src/codegen/codegen_utils.c
@@ -17,505 +17,417 @@ int defer_count = 0;
ASTNode *g_current_lambda = NULL;
// Helper to emit variable declarations with array types.
-void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name)
-{
- (void)ctx;
-
- char *bracket = strchr(type_str, '[');
-
- if (bracket)
- {
- int base_len = bracket - type_str;
- fprintf(out, "%.*s %s%s", base_len, type_str, var_name, bracket);
- }
- else
- {
- fprintf(out, "%s %s", type_str, var_name);
- }
+void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str,
+ const char *var_name) {
+ (void)ctx;
+
+ char *bracket = strchr(type_str, '[');
+
+ if (bracket) {
+ int base_len = bracket - type_str;
+ fprintf(out, "%.*s %s%s", base_len, type_str, var_name, bracket);
+ } else {
+ fprintf(out, "%s %s", type_str, var_name);
+ }
}
// Find struct definition
-ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name)
-{
- if (!name)
- {
- return NULL;
- }
- ASTNode *s = global_user_structs;
- while (s)
- {
- if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0 && !s->strct.is_incomplete)
- {
- return s;
- }
- s = s->next;
+ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name) {
+ if (!name) {
+ return NULL;
+ }
+ ASTNode *s = global_user_structs;
+ while (s) {
+ if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0 &&
+ !s->strct.is_incomplete) {
+ return s;
}
-
- // Check parsed structs list (imports)-
- StructRef *sr = ctx->parsed_structs_list;
- while (sr)
- {
- if (sr->node && sr->node->type == NODE_STRUCT && strcmp(sr->node->strct.name, name) == 0 &&
- !sr->node->strct.is_incomplete)
- {
- return sr->node;
- }
- sr = sr->next;
+ s = s->next;
+ }
+
+ // Check parsed structs list (imports)-
+ StructRef *sr = ctx->parsed_structs_list;
+ while (sr) {
+ if (sr->node && sr->node->type == NODE_STRUCT &&
+ strcmp(sr->node->strct.name, name) == 0 &&
+ !sr->node->strct.is_incomplete) {
+ return sr->node;
}
- s = ctx->instantiated_structs;
- while (s)
- {
- if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0 && !s->strct.is_incomplete)
- {
- return s;
- }
- s = s->next;
+ sr = sr->next;
+ }
+ s = ctx->instantiated_structs;
+ while (s) {
+ if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0 &&
+ !s->strct.is_incomplete) {
+ return s;
}
- return NULL;
+ s = s->next;
+ }
+ return NULL;
}
// Get field type from struct.
-char *get_field_type_str(ParserContext *ctx, const char *struct_name, const char *field_name)
-{
- char clean_name[256];
- strncpy(clean_name, struct_name, sizeof(clean_name) - 1);
- clean_name[sizeof(clean_name) - 1] = 0;
-
- char *ptr = strchr(clean_name, '<');
- if (ptr)
- {
- *ptr = 0;
- }
-
- ASTNode *def = find_struct_def_codegen(ctx, clean_name);
- if (!def)
- {
- return NULL;
- }
+char *get_field_type_str(ParserContext *ctx, const char *struct_name,
+ const char *field_name) {
+ char clean_name[256];
+ strncpy(clean_name, struct_name, sizeof(clean_name) - 1);
+ clean_name[sizeof(clean_name) - 1] = 0;
+
+ char *ptr = strchr(clean_name, '<');
+ if (ptr) {
+ *ptr = 0;
+ }
+
+ ASTNode *def = find_struct_def_codegen(ctx, clean_name);
+ if (!def) {
+ return NULL;
+ }
- ASTNode *f = def->strct.fields;
- while (f)
- {
- if (strcmp(f->field.name, field_name) == 0)
- {
- return f->field.type;
- }
- f = f->next;
+ ASTNode *f = def->strct.fields;
+ while (f) {
+ if (strcmp(f->field.name, field_name) == 0) {
+ return f->field.type;
}
- return NULL;
+ f = f->next;
+ }
+ return NULL;
}
// Type inference.
-char *infer_type(ParserContext *ctx, ASTNode *node)
-{
- if (!node)
- {
- return NULL;
+char *infer_type(ParserContext *ctx, ASTNode *node) {
+ if (!node) {
+ return NULL;
+ }
+ if (node->resolved_type && strcmp(node->resolved_type, "unknown") != 0) {
+ return node->resolved_type;
+ }
+
+ if (node->type == NODE_EXPR_LITERAL) {
+ if (node->type_info) {
+ return type_to_string(node->type_info);
}
- if (node->resolved_type && strcmp(node->resolved_type, "unknown") != 0)
- {
- return node->resolved_type;
+ return NULL;
+ }
+
+ if (node->type == NODE_EXPR_VAR) {
+ Symbol *sym = find_symbol_entry(ctx, node->var_ref.name);
+ if (sym) {
+ if (sym->type_name) {
+ return sym->type_name;
+ }
+ if (sym->type_info) {
+ return type_to_string(sym->type_info);
+ }
}
+ }
- if (node->type == NODE_EXPR_LITERAL)
- {
- if (node->type_info)
- {
- return type_to_string(node->type_info);
+ if (node->type == NODE_EXPR_CALL) {
+ if (node->call.callee->type == NODE_EXPR_VAR) {
+ FuncSig *sig = find_func(ctx, node->call.callee->var_ref.name);
+ if (sig) {
+ if (sig->is_async) {
+ return "Async";
}
- return NULL;
- }
-
- if (node->type == NODE_EXPR_VAR)
- {
- Symbol *sym = find_symbol_entry(ctx, node->var_ref.name);
- if (sym)
- {
- if (sym->type_name)
- {
- return sym->type_name;
- }
- if (sym->type_info)
- {
- return type_to_string(sym->type_info);
- }
+ if (sig->ret_type) {
+ return type_to_string(sig->ret_type);
}
- }
+ }
- if (node->type == NODE_EXPR_CALL)
- {
- if (node->call.callee->type == NODE_EXPR_VAR)
- {
- FuncSig *sig = find_func(ctx, node->call.callee->var_ref.name);
- if (sig)
- {
- if (sig->is_async)
- {
- return "Async";
- }
- if (sig->ret_type)
- {
- return type_to_string(sig->ret_type);
- }
- }
-
- // Fallback for known stdlib memory functions.
- if (strcmp(node->call.callee->var_ref.name, "malloc") == 0 ||
- strcmp(node->call.callee->var_ref.name, "calloc") == 0 ||
- strcmp(node->call.callee->var_ref.name, "realloc") == 0)
- {
- return "void*";
- }
- ASTNode *sdef = find_struct_def_codegen(ctx, node->call.callee->var_ref.name);
- if (sdef)
- {
- return node->call.callee->var_ref.name;
- }
- }
- // Method call: target.method() - look up Type_method signature.
- if (node->call.callee->type == NODE_EXPR_MEMBER)
- {
- char *target_type = infer_type(ctx, node->call.callee->member.target);
- if (target_type)
- {
- char clean_type[256];
- strcpy(clean_type, target_type);
- char *ptr = strchr(clean_type, '*');
- if (ptr)
- {
- *ptr = 0;
- }
-
- char *base = clean_type;
- if (strncmp(base, "struct ", 7) == 0)
- {
- base += 7;
- }
-
- char func_name[512];
- sprintf(func_name, "%s_%s", base, node->call.callee->member.field);
-
- FuncSig *sig = find_func(ctx, func_name);
- if (sig && sig->ret_type)
- {
- return type_to_string(sig->ret_type);
- }
- }
+ // Fallback for known stdlib memory functions.
+ if (strcmp(node->call.callee->var_ref.name, "malloc") == 0 ||
+ strcmp(node->call.callee->var_ref.name, "calloc") == 0 ||
+ strcmp(node->call.callee->var_ref.name, "realloc") == 0) {
+ return "void*";
+ }
+ ASTNode *sdef =
+ find_struct_def_codegen(ctx, node->call.callee->var_ref.name);
+ if (sdef) {
+ return node->call.callee->var_ref.name;
+ }
+ }
+ // Method call: target.method() - look up Type_method signature.
+ if (node->call.callee->type == NODE_EXPR_MEMBER) {
+ char *target_type = infer_type(ctx, node->call.callee->member.target);
+ if (target_type) {
+ char clean_type[256];
+ strcpy(clean_type, target_type);
+ char *ptr = strchr(clean_type, '*');
+ if (ptr) {
+ *ptr = 0;
}
- if (node->call.callee->type == NODE_EXPR_VAR)
- {
- Symbol *sym = find_symbol_entry(ctx, node->call.callee->var_ref.name);
- if (sym && sym->type_info && sym->type_info->kind == TYPE_FUNCTION &&
- sym->type_info->inner)
- {
- return type_to_string(sym->type_info->inner);
- }
+ char *base = clean_type;
+ if (strncmp(base, "struct ", 7) == 0) {
+ base += 7;
}
- }
- if (node->type == NODE_TRY)
- {
- char *inner_type = infer_type(ctx, node->try_stmt.expr);
- if (inner_type)
- {
- // Extract T from Result<T> or Option<T>
- char *start = strchr(inner_type, '<');
- if (start)
- {
- start++; // Skip <
- char *end = strrchr(inner_type, '>');
- if (end && end > start)
- {
- int len = end - start;
- char *extracted = xmalloc(len + 1);
- strncpy(extracted, start, len);
- extracted[len] = 0;
- return extracted;
- }
- }
- }
- }
+ char func_name[512];
+ sprintf(func_name, "%s_%s", base, node->call.callee->member.field);
- if (node->type == NODE_EXPR_MEMBER)
- {
- char *parent_type = infer_type(ctx, node->member.target);
- if (!parent_type)
- {
- return NULL;
+ FuncSig *sig = find_func(ctx, func_name);
+ if (sig && sig->ret_type) {
+ return type_to_string(sig->ret_type);
}
+ }
+ }
- char clean_name[256];
- strcpy(clean_name, parent_type);
- char *ptr = strchr(clean_name, '*');
- if (ptr)
- {
- *ptr = 0;
- }
+ if (node->call.callee->type == NODE_EXPR_VAR) {
+ Symbol *sym = find_symbol_entry(ctx, node->call.callee->var_ref.name);
+ if (sym && sym->type_info && sym->type_info->kind == TYPE_FUNCTION &&
+ sym->type_info->inner) {
+ return type_to_string(sym->type_info->inner);
+ }
+ }
+ }
+
+ if (node->type == NODE_TRY) {
+ char *inner_type = infer_type(ctx, node->try_stmt.expr);
+ if (inner_type) {
+ // Extract T from Result<T> or Option<T>
+ char *start = strchr(inner_type, '<');
+ if (start) {
+ start++; // Skip <
+ char *end = strrchr(inner_type, '>');
+ if (end && end > start) {
+ int len = end - start;
+ char *extracted = xmalloc(len + 1);
+ strncpy(extracted, start, len);
+ extracted[len] = 0;
+ return extracted;
+ }
+ }
+ }
+ }
- return get_field_type_str(ctx, clean_name, node->member.field);
+ if (node->type == NODE_EXPR_MEMBER) {
+ char *parent_type = infer_type(ctx, node->member.target);
+ if (!parent_type) {
+ return NULL;
}
- if (node->type == NODE_EXPR_BINARY)
- {
- if (strcmp(node->binary.op, "??") == 0)
- {
- return infer_type(ctx, node->binary.left);
- }
+ char clean_name[256];
+ strcpy(clean_name, parent_type);
+ char *ptr = strchr(clean_name, '*');
+ if (ptr) {
+ *ptr = 0;
+ }
- const char *op = node->binary.op;
- char *left_type = infer_type(ctx, node->binary.left);
- char *right_type = infer_type(ctx, node->binary.right);
+ return get_field_type_str(ctx, clean_name, node->member.field);
+ }
- int is_logical = (strcmp(op, "&&") == 0 || strcmp(op, "||") == 0 || strcmp(op, "==") == 0 ||
- strcmp(op, "!=") == 0 || strcmp(op, "<") == 0 || strcmp(op, ">") == 0 ||
- strcmp(op, "<=") == 0 || strcmp(op, ">=") == 0);
+ if (node->type == NODE_EXPR_BINARY) {
+ if (strcmp(node->binary.op, "??") == 0) {
+ return infer_type(ctx, node->binary.left);
+ }
- if (is_logical)
- {
- return xstrdup("int");
- }
+ const char *op = node->binary.op;
+ char *left_type = infer_type(ctx, node->binary.left);
+ char *right_type = infer_type(ctx, node->binary.right);
- if (left_type && strcmp(left_type, "usize") == 0)
- {
- return "usize";
- }
- if (right_type && strcmp(right_type, "usize") == 0)
- {
- return "usize";
- }
- if (left_type && strcmp(left_type, "double") == 0)
- {
- return "double";
- }
+ int is_logical = (strcmp(op, "&&") == 0 || strcmp(op, "||") == 0 ||
+ strcmp(op, "==") == 0 || strcmp(op, "!=") == 0 ||
+ strcmp(op, "<") == 0 || strcmp(op, ">") == 0 ||
+ strcmp(op, "<=") == 0 || strcmp(op, ">=") == 0);
- return left_type ? left_type : right_type;
+ if (is_logical) {
+ return xstrdup("int");
}
- if (node->type == NODE_MATCH)
- {
- ASTNode *case_node = node->match_stmt.cases;
- while (case_node)
- {
- char *type = infer_type(ctx, case_node->match_case.body);
- if (type && strcmp(type, "void") != 0 && strcmp(type, "unknown") != 0)
- {
- return type;
- }
- case_node = case_node->next;
- }
- return NULL;
+ if (left_type && strcmp(left_type, "usize") == 0) {
+ return "usize";
}
-
- if (node->type == NODE_EXPR_INDEX)
- {
- char *array_type = infer_type(ctx, node->index.array);
- if (array_type)
- {
- // If T*, returns T. If T[], returns T.
- char *ptr = strrchr(array_type, '*');
- if (ptr)
- {
- int len = ptr - array_type;
- char *buf = xmalloc(len + 1);
- strncpy(buf, array_type, len);
- buf[len] = 0;
- return buf;
- }
- }
- return "int";
+ if (right_type && strcmp(right_type, "usize") == 0) {
+ return "usize";
+ }
+ if (left_type && strcmp(left_type, "double") == 0) {
+ return "double";
}
- if (node->type == NODE_EXPR_UNARY)
- {
- if (strcmp(node->unary.op, "&") == 0)
- {
- char *inner = infer_type(ctx, node->unary.operand);
- if (inner)
- {
- char *buf = xmalloc(strlen(inner) + 2);
- sprintf(buf, "%s*", inner);
- return buf;
- }
- }
- if (strcmp(node->unary.op, "*") == 0)
- {
- char *inner = infer_type(ctx, node->unary.operand);
- if (inner)
- {
- char *ptr = strchr(inner, '*');
- if (ptr)
- {
- // Return base type (naive)
- int len = ptr - inner;
- char *dup = xmalloc(len + 1);
- strncpy(dup, inner, len);
- dup[len] = 0;
- return dup;
- }
- }
- }
- return infer_type(ctx, node->unary.operand);
+ return left_type ? left_type : right_type;
+ }
+
+ if (node->type == NODE_MATCH) {
+ ASTNode *case_node = node->match_stmt.cases;
+ while (case_node) {
+ char *type = infer_type(ctx, case_node->match_case.body);
+ if (type && strcmp(type, "void") != 0 && strcmp(type, "unknown") != 0) {
+ return type;
+ }
+ case_node = case_node->next;
+ }
+ return NULL;
+ }
+
+ if (node->type == NODE_EXPR_INDEX) {
+ char *array_type = infer_type(ctx, node->index.array);
+ if (array_type) {
+ // If T*, returns T. If T[], returns T.
+ char *ptr = strrchr(array_type, '*');
+ if (ptr) {
+ int len = ptr - array_type;
+ char *buf = xmalloc(len + 1);
+ strncpy(buf, array_type, len);
+ buf[len] = 0;
+ return buf;
+ }
+ }
+ return "int";
+ }
+
+ if (node->type == NODE_EXPR_UNARY) {
+ if (strcmp(node->unary.op, "&") == 0) {
+ char *inner = infer_type(ctx, node->unary.operand);
+ if (inner) {
+ char *buf = xmalloc(strlen(inner) + 2);
+ sprintf(buf, "%s*", inner);
+ return buf;
+ }
+ }
+ if (strcmp(node->unary.op, "*") == 0) {
+ char *inner = infer_type(ctx, node->unary.operand);
+ if (inner) {
+ char *ptr = strchr(inner, '*');
+ if (ptr) {
+ // Return base type (naive)
+ int len = ptr - inner;
+ char *dup = xmalloc(len + 1);
+ strncpy(dup, inner, len);
+ dup[len] = 0;
+ return dup;
+ }
+ }
+ }
+ return infer_type(ctx, node->unary.operand);
+ }
+
+ if (node->type == NODE_AWAIT) {
+ // Infer underlying type T from await Async<T>
+ // If it's a direct call await foo(), we know T from foo's signature.
+ if (node->unary.operand->type == NODE_EXPR_CALL &&
+ node->unary.operand->call.callee->type == NODE_EXPR_VAR) {
+ FuncSig *sig =
+ find_func(ctx, node->unary.operand->call.callee->var_ref.name);
+ if (sig && sig->ret_type) {
+ return type_to_string(sig->ret_type);
+ }
}
- if (node->type == NODE_AWAIT)
- {
- // Infer underlying type T from await Async<T>
- // If it's a direct call await foo(), we know T from foo's signature.
- if (node->unary.operand->type == NODE_EXPR_CALL &&
- node->unary.operand->call.callee->type == NODE_EXPR_VAR)
- {
- FuncSig *sig = find_func(ctx, node->unary.operand->call.callee->var_ref.name);
- if (sig && sig->ret_type)
- {
- return type_to_string(sig->ret_type);
- }
- }
+ return "void*";
+ }
- return "void*";
- }
+ if (node->type == NODE_EXPR_CAST) {
+ return node->cast.target_type;
+ }
- if (node->type == NODE_EXPR_CAST)
- {
- return node->cast.target_type;
- }
+ if (node->type == NODE_EXPR_STRUCT_INIT) {
+ return node->struct_init.struct_name;
+ }
- if (node->type == NODE_EXPR_STRUCT_INIT)
- {
- return node->struct_init.struct_name;
+ if (node->type == NODE_EXPR_LITERAL) {
+ if (node->literal.type_kind == TOK_STRING) {
+ return "string";
}
-
- if (node->type == NODE_EXPR_LITERAL)
- {
- if (node->literal.type_kind == TOK_STRING)
- {
- return "string";
- }
- if (node->literal.type_kind == TOK_CHAR)
- {
- return "char";
- }
- if (node->literal.type_kind == 1)
- {
- return "double";
- }
- return "int";
+ if (node->literal.type_kind == TOK_CHAR) {
+ return "char";
+ }
+ if (node->literal.type_kind == 1) {
+ return "double";
}
+ return "int";
+ }
- return NULL;
+ return NULL;
}
// Extract variable names from argument string.
-char *extract_call_args(const char *args)
-{
- if (!args || strlen(args) == 0)
- {
- return xstrdup("");
+char *extract_call_args(const char *args) {
+ if (!args || strlen(args) == 0) {
+ return xstrdup("");
+ }
+ char *out = xmalloc(strlen(args) + 1);
+ out[0] = 0;
+
+ char *dup = xstrdup(args);
+ char *p = strtok(dup, ",");
+ while (p) {
+ while (*p == ' ') {
+ p++;
}
- char *out = xmalloc(strlen(args) + 1);
- out[0] = 0;
-
- char *dup = xstrdup(args);
- char *p = strtok(dup, ",");
- while (p)
- {
- while (*p == ' ')
- {
- p++;
- }
- char *last_space = strrchr(p, ' ');
- char *ptr_star = strrchr(p, '*');
-
- char *name = p;
- if (last_space)
- {
- name = last_space + 1;
- }
- if (ptr_star && ptr_star > last_space)
- {
- name = ptr_star + 1;
- }
+ char *last_space = strrchr(p, ' ');
+ char *ptr_star = strrchr(p, '*');
- if (strlen(out) > 0)
- {
- strcat(out, ", ");
- }
- strcat(out, name);
+ char *name = p;
+ if (last_space) {
+ name = last_space + 1;
+ }
+ if (ptr_star && ptr_star > last_space) {
+ name = ptr_star + 1;
+ }
- p = strtok(NULL, ",");
+ if (strlen(out) > 0) {
+ strcat(out, ", ");
}
- free(dup);
- return out;
+ strcat(out, name);
+
+ p = strtok(NULL, ",");
+ }
+ free(dup);
+ return out;
}
// Parse original method name from mangled name.
-const char *parse_original_method_name(const char *mangled)
-{
- const char *last = strrchr(mangled, '_');
- return last ? last + 1 : mangled;
+const char *parse_original_method_name(const char *mangled) {
+ const char *last = strrchr(mangled, '_');
+ return last ? last + 1 : mangled;
}
// Replace string type in arguments.
-char *replace_string_type(const char *args)
-{
- if (!args)
- {
- return NULL;
- }
- char *res = xmalloc(strlen(args) * 2 + 1);
- res[0] = 0;
- const char *p = args;
- while (*p)
- {
- const char *match = strstr(p, "string ");
- if (match)
- {
- if (match > args && (isalnum(*(match - 1)) || *(match - 1) == '_'))
- {
- strncat(res, p, match - p + 6);
- p = match + 6;
- }
- else
- {
- strncat(res, p, match - p);
- strcat(res, "const char* ");
- p = match + 7;
- }
- }
- else
- {
- strcat(res, p);
- break;
- }
+char *replace_string_type(const char *args) {
+ if (!args) {
+ return NULL;
+ }
+ char *res = xmalloc(strlen(args) * 2 + 1);
+ res[0] = 0;
+ const char *p = args;
+ while (*p) {
+ const char *match = strstr(p, "string ");
+ if (match) {
+ if (match > args && (isalnum(*(match - 1)) || *(match - 1) == '_')) {
+ strncat(res, p, match - p + 6);
+ p = match + 6;
+ } else {
+ strncat(res, p, match - p);
+ strcat(res, "const char* ");
+ p = match + 7;
+ }
+ } else {
+ strcat(res, p);
+ break;
}
- return res;
+ }
+ return res;
}
// Helper to emit auto type or fallback.
-void emit_auto_type(ParserContext *ctx, ASTNode *init_expr, Token t, FILE *out)
-{
- char *inferred = NULL;
- if (init_expr)
- {
- inferred = infer_type(ctx, init_expr);
- }
-
- if (inferred && strcmp(inferred, "__auto_type") != 0 && strcmp(inferred, "unknown") != 0)
- {
- fprintf(out, "%s", inferred);
- }
- else
- {
- if (strstr(g_config.cc, "tcc"))
- {
- zpanic_with_suggestion(t,
- "Type inference failed for variable initialization and TCC does "
- "not support __auto_type",
- "Please specify the type explicitly: 'var x: Type = ...'");
- }
- else
- {
- fprintf(out, "__auto_type");
- }
+void emit_auto_type(ParserContext *ctx, ASTNode *init_expr, Token t,
+ FILE *out) {
+ char *inferred = NULL;
+ if (init_expr) {
+ inferred = infer_type(ctx, init_expr);
+ }
+
+ if (inferred && strcmp(inferred, "__auto_type") != 0 &&
+ strcmp(inferred, "unknown") != 0) {
+ fprintf(out, "%s", inferred);
+ } else {
+ if (strstr(g_config.cc, "tcc")) {
+ zpanic_with_suggestion(
+ t,
+ "Type inference failed for variable initialization and TCC does "
+ "not support __auto_type",
+ "Please specify the type explicitly: 'var x: Type = ...'");
+ } else {
+ fprintf(out, "__auto_type");
}
+ }
}