From 17cc0542def402f5b0788ff9e8fe0538f81d5ddf Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Sun, 25 Jan 2026 10:33:34 +0000 Subject: Fix for #114 --- src/codegen/codegen.c | 98 +++++++++++++++++++++++++++- src/codegen/codegen_stmt.c | 157 +++++++++++++++++++-------------------------- 2 files changed, 160 insertions(+), 95 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index f239bb6..b5aecfa 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -328,6 +328,61 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) } } + // Check for Static Enum Variant Call: Enum.Variant(...) + if (target->type == NODE_EXPR_VAR) + { + ASTNode *def = find_struct_def(ctx, target->var_ref.name); + if (def && def->type == NODE_ENUM) + { + char mangled[256]; + sprintf(mangled, "%s_%s", target->var_ref.name, method); + FuncSig *sig = find_func(ctx, mangled); + if (sig) + { + fprintf(out, "%s(", mangled); + ASTNode *arg = node->call.args; + int arg_idx = 0; + while (arg) + { + if (arg_idx > 0 && arg) + { + fprintf(out, ", "); + } + + Type *param_t = + (arg_idx < sig->total_args) ? sig->arg_types[arg_idx] : NULL; + + // Tuple Packing Logic + if (param_t && param_t->kind == TYPE_STRUCT && + strncmp(param_t->name, "Tuple_", 6) == 0 && sig->total_args == 1 && + node->call.arg_count > 1) + { + fprintf(out, "(%s){", param_t->name); + int first = 1; + while (arg) + { + if (!first) + { + fprintf(out, ", "); + } + first = 0; + codegen_expression(ctx, arg, out); + arg = arg->next; + } + fprintf(out, "}"); + break; // All args consumed + } + + codegen_expression(ctx, arg, out); + arg = arg->next; + arg_idx++; + } + fprintf(out, ")"); + return; + } + } + } + char *type = infer_type(ctx, target); if (type) { @@ -561,18 +616,55 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) free(inner); handled = 1; } + else if (param_t && param_t->kind == TYPE_STRUCT && + strncmp(param_t->name, "Tuple_", 6) == 0 && sig->total_args == 1 && + node->call.arg_count > 1) + { + // Implicit Tuple Packing: + // Function expects 1 Tuple argument, but call has multiple args -> Pack + // them + fprintf(out, "(%s){", param_t->name); + + ASTNode *curr = arg; + int first_field = 1; + while (curr) + { + if (!first_field) + { + fprintf(out, ", "); + } + first_field = 0; + codegen_expression(ctx, curr, out); + curr = curr->next; + } + fprintf(out, "}"); + handled = 1; + + // Advance main loop iterator to end + arg = NULL; + } } - if (!handled) + if (handled) + { + if (arg == NULL) + { + break; // Tuple packed all args + } + } + else { codegen_expression(ctx, arg, out); } - if (arg->next) + if (arg && arg->next) { fprintf(out, ", "); } - arg = arg->next; + if (arg) + { + arg = arg->next; + } arg_idx++; } } diff --git a/src/codegen/codegen_stmt.c b/src/codegen/codegen_stmt.c index 406a6e5..55a4be2 100644 --- a/src/codegen/codegen_stmt.c +++ b/src/codegen/codegen_stmt.c @@ -325,152 +325,125 @@ void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, int us emit_pattern_condition(ctx, c->match_case.pattern, id, has_ref_binding, out); } fprintf(out, ") { "); - if (c->match_case.binding_name) + if (c->match_case.binding_count > 0) { - if (is_option) + for (int i = 0; i < c->match_case.binding_count; i++) { - if (strstr(g_config.cc, "tcc")) + char *bname = c->match_case.binding_names[i]; + int is_r = c->match_case.binding_refs ? c->match_case.binding_refs[i] : 0; + + if (is_option) { - if (c->match_case.is_ref) + if (strstr(g_config.cc, "tcc")) { - fprintf(out, "__typeof__(&_m_%d.val) %s = &_m_%d.val; ", id, - c->match_case.binding_name, id); + if (is_r) + { + fprintf(out, "__typeof__(&_m_%d.val) %s = &_m_%d.val; ", id, bname, id); + } + else + { + fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id, bname, id); + } } else { - fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id, - c->match_case.binding_name, id); + if (is_r) + { + fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", bname, id); + } + else if (has_ref_binding) + { + fprintf(out, "ZC_AUTO %s = _m_%d->val; ", bname, id); + } + else + { + fprintf(out, "ZC_AUTO %s = _m_%d.val; ", bname, id); + } } } - else + else if (is_result) { - if (c->match_case.is_ref) + char *field = "val"; + if (strcmp(c->match_case.pattern, "Err") == 0) { - // _m is pointer when has_ref_binding, use -> - fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", c->match_case.binding_name, id); + field = "err"; } - else if (has_ref_binding) - { - // _m is pointer, use -> but don't take address - fprintf(out, "ZC_AUTO %s = _m_%d->val; ", c->match_case.binding_name, id); - } - else - { - // _m is value, use . - fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name, id); - } - } - } - else if (is_result) // FIX: Changed 'if' to 'else if' to match original logic structure - // if needed, but original code had implicit fallthrough checks? No, - // checks match pattern. - { - if (strcmp(c->match_case.pattern, "Ok") == 0) - { + if (strstr(g_config.cc, "tcc")) { - if (c->match_case.is_ref) + if (is_r) { - fprintf(out, "__typeof__(&_m_%d->val) %s = &_m_%d->val; ", id, - c->match_case.binding_name, id); + fprintf(out, "__typeof__(&_m_%d->%s) %s = &_m_%d->%s; ", id, field, + bname, id, field); } else { - fprintf(out, "__typeof__(_m_%d->val) %s = _m_%d->val; ", id, - c->match_case.binding_name, id); + fprintf(out, "__typeof__(_m_%d->%s) %s = _m_%d->%s; ", id, field, bname, + id, field); } } else { - if (c->match_case.is_ref) + if (is_r) { - // _m is pointer when has_ref_binding, use -> - fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", c->match_case.binding_name, - id); + fprintf(out, "ZC_AUTO %s = &_m_%d->%s; ", bname, id, field); } else if (has_ref_binding) { - // _m is pointer, use -> but don't take address - fprintf(out, "ZC_AUTO %s = _m_%d->val; ", c->match_case.binding_name, - id); + fprintf(out, "ZC_AUTO %s = _m_%d->%s; ", bname, id, field); } else { - // _m is value, use . - fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name, - id); + fprintf(out, "ZC_AUTO %s = _m_%d.%s; ", bname, id, field); } } } else { - if (strstr(g_config.cc, "tcc")) + char *v = strrchr(c->match_case.pattern, '_'); + if (v) + { + v++; + } + else + { + v = c->match_case.pattern; + } + + if (c->match_case.binding_count > 1) { - if (c->match_case.is_ref) + // Tuple destructuring: data.Variant.vI + if (is_r) { - fprintf(out, "__typeof__(&_m_%d->err) %s = &_m_%d->err; ", id, - c->match_case.binding_name, id); + fprintf(out, "ZC_AUTO %s = &_m_%d->data.%s.v%d; ", bname, id, v, i); + } + else if (has_ref_binding) + { + fprintf(out, "ZC_AUTO %s = _m_%d->data.%s.v%d; ", bname, id, v, i); } else { - fprintf(out, "__typeof__(_m_%d->err) %s = _m_%d->err; ", id, - c->match_case.binding_name, id); + fprintf(out, "ZC_AUTO %s = _m_%d.data.%s.v%d; ", bname, id, v, i); } } else { - if (c->match_case.is_ref) + // Single destructuring: data.Variant + if (is_r) { - // _m is pointer when has_ref_binding, use -> - fprintf(out, "ZC_AUTO %s = &_m_%d->err; ", c->match_case.binding_name, - id); + fprintf(out, "ZC_AUTO %s = &_m_%d->data.%s; ", bname, id, v); } else if (has_ref_binding) { - // _m is pointer, use -> but don't take address - fprintf(out, "ZC_AUTO %s = _m_%d->err; ", c->match_case.binding_name, - id); + fprintf(out, "ZC_AUTO %s = _m_%d->data.%s; ", bname, id, v); } else { - // _m is value, use . - fprintf(out, "ZC_AUTO %s = _m_%d.err; ", c->match_case.binding_name, - id); + fprintf(out, "ZC_AUTO %s = _m_%d.data.%s; ", bname, id, v); } } } } - else - { - char *f = strrchr(c->match_case.pattern, '_'); - if (f) - { - f++; - } - else - { - f = c->match_case.pattern; - } - // Generic struct destructuring (for example, MyStruct_Variant) - // Assuming data union or accessible field. - if (c->match_case.is_ref) - { - // _m is pointer when has_ref_binding, use -> - fprintf(out, "ZC_AUTO %s = &_m_%d->data.%s; ", c->match_case.binding_name, id, - f); - } - else if (has_ref_binding) - { - // _m is pointer, use -> but don't take address - fprintf(out, "ZC_AUTO %s = _m_%d->data.%s; ", c->match_case.binding_name, id, - f); - } - else - { - // _m is value, use . - fprintf(out, "ZC_AUTO %s = _m_%d.data.%s; ", c->match_case.binding_name, id, f); - } - } } // Check if body is a string literal (should auto-print). -- cgit v1.2.3