From 70144b6829c3ca8ff8b46e40b358cc711db85efb Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Tue, 27 Jan 2026 22:11:50 +0000 Subject: Solving C++ interop bug --- src/codegen/codegen_stmt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/codegen/codegen_stmt.c') diff --git a/src/codegen/codegen_stmt.c b/src/codegen/codegen_stmt.c index bd0c816..70fb297 100644 --- a/src/codegen/codegen_stmt.c +++ b/src/codegen/codegen_stmt.c @@ -884,7 +884,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) } else { - fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[0], id, + fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[0], id, check); } } @@ -903,7 +903,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) } else { - fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[i], + fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[i], id, field); } } @@ -916,7 +916,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) } else { - fprintf(out, " __auto_type %s = _tmp_%d.v%d;\n", node->destruct.names[i], + fprintf(out, " ZC_AUTO %s = _tmp_%d.v%d;\n", node->destruct.names[i], id, i); } } @@ -1528,7 +1528,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) } else { - fprintf(out, "__auto_type"); + fprintf(out, "ZC_AUTO"); } fprintf(out, " _z_ret_mv = "); codegen_expression(ctx, node->ret.value, out); -- cgit v1.2.3 From da12345b6e3c297e530764c4424b7d9e6a1cb65e Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Wed, 28 Jan 2026 01:19:20 +0000 Subject: Fix for #141 --- src/codegen/codegen_stmt.c | 11 +++++----- src/lexer/token.c | 8 +++++++ src/parser/parser_core.c | 2 +- src/parser/parser_expr.c | 37 +++++++++++++++++++++++++++++++-- src/parser/parser_stmt.c | 6 +++--- tests/features/test_implicit_fstring.zc | 19 +++++++++++++++++ tests/features/test_traits_suite.zc | 2 +- 7 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 tests/features/test_implicit_fstring.zc (limited to 'src/codegen/codegen_stmt.c') diff --git a/src/codegen/codegen_stmt.c b/src/codegen/codegen_stmt.c index 70fb297..2f9a2ba 100644 --- a/src/codegen/codegen_stmt.c +++ b/src/codegen/codegen_stmt.c @@ -884,8 +884,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) } else { - fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[0], id, - check); + fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[0], id, check); } } else @@ -903,8 +902,8 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) } else { - fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[i], - id, field); + fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[i], id, + field); } } else @@ -916,8 +915,8 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) } else { - fprintf(out, " ZC_AUTO %s = _tmp_%d.v%d;\n", node->destruct.names[i], - id, i); + fprintf(out, " ZC_AUTO %s = _tmp_%d.v%d;\n", node->destruct.names[i], id, + i); } } } diff --git a/src/lexer/token.c b/src/lexer/token.c index decabbe..6696a5c 100644 --- a/src/lexer/token.c +++ b/src/lexer/token.c @@ -149,6 +149,14 @@ Token lexer_next(Lexer *l) { return (Token){TOK_DEF, s, 3, start_line, start_col}; } + if (len == 5 && strncmp(s, "trait", 5) == 0) + { + return (Token){TOK_TRAIT, s, 5, start_line, start_col}; + } + if (len == 4 && strncmp(s, "impl", 4) == 0) + { + return (Token){TOK_IMPL, s, 4, start_line, start_col}; + } if (len == 8 && strncmp(s, "autofree", 8) == 0) { return (Token){TOK_AUTOFREE, s, 8, start_line, start_col}; diff --git a/src/parser/parser_core.c b/src/parser/parser_core.c index e9a418e..ba6f2fe 100644 --- a/src/parser/parser_core.c +++ b/src/parser/parser_core.c @@ -700,7 +700,7 @@ static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char * { // Simplistic Debug for now, I know. code = xmalloc(1024); - sprintf(code, "impl %s { fn to_string(self) -> char* { return \"%s { ... }\"; } }", + sprintf(code, "impl %s { fn to_string(self) -> char* { return \"%s {{ ... }}\"; } }", name, name); } else if (0 == strcmp(trait, "Copy")) diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c index df2dcf6..332d9c3 100644 --- a/src/parser/parser_expr.c +++ b/src/parser/parser_expr.c @@ -935,6 +935,17 @@ static ASTNode *create_fstring_block(ParserContext *ctx, const char *content) free(txt); } + // Handle escape {{ + if (brace[1] == '{') + { + ASTNode *cat = ast_create(NODE_RAW_STMT); + cat->raw_stmt.content = xstrdup("strcat(_b, \"{\");"); + tail->next = cat; + tail = cat; + cur = brace + 2; + continue; + } + char *end_brace = strchr(brace, '}'); if (!end_brace) { @@ -1100,8 +1111,30 @@ static ASTNode *parse_float_literal(Token t) } // Parse string literal -static ASTNode *parse_string_literal(Token t) +static ASTNode *parse_string_literal(ParserContext *ctx, Token t) { + // Check for implicit interpolation + int has_interpolation = 0; + for (int i = 1; i < t.len - 1; i++) + { + if (t.start[i] == '{') + { + has_interpolation = 1; + break; + } + } + + if (has_interpolation) + { + + char *inner = xmalloc(t.len); + strncpy(inner, t.start + 1, t.len - 2); + inner[t.len - 2] = 0; + ASTNode *node = create_fstring_block(ctx, inner); + free(inner); + return node; + } + ASTNode *node = ast_create(NODE_EXPR_LITERAL); node->literal.type_kind = LITERAL_STRING; node->literal.string_val = xmalloc(t.len); @@ -1276,7 +1309,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) } else if (t.type == TOK_STRING) { - node = parse_string_literal(t); + node = parse_string_literal(ctx, t); } else if (t.type == TOK_FSTRING) { diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c index ab5b89c..85e9825 100644 --- a/src/parser/parser_stmt.c +++ b/src/parser/parser_stmt.c @@ -1877,7 +1877,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) lexer_next(&lookahead); TokenType next_type = lexer_peek(&lookahead).type; - if (next_type == TOK_SEMICOLON || next_type == TOK_DOTDOT) + if (next_type == TOK_SEMICOLON || next_type == TOK_DOTDOT || next_type == TOK_RBRACE) { Token t = lexer_next(l); // consume string @@ -1894,8 +1894,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) inner[t.len - 2] = 0; } - // ; means println (end of line), .. means print (continuation) - int is_ln = (next_type == TOK_SEMICOLON); + int is_ln = (next_type == TOK_SEMICOLON || next_type == TOK_RBRACE); char **used_syms = NULL; int used_count = 0; char *code = @@ -1913,6 +1912,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) lexer_next(l); // consume optional ; } } + // If TOK_RBRACE, do not consume it, so parse_block can see it and terminate loop. ASTNode *n = ast_create(NODE_RAW_STMT); // Append semicolon to Statement Expression to make it a valid statement diff --git a/tests/features/test_implicit_fstring.zc b/tests/features/test_implicit_fstring.zc new file mode 100644 index 0000000..85a6c86 --- /dev/null +++ b/tests/features/test_implicit_fstring.zc @@ -0,0 +1,19 @@ + +test "implicit_fstring_interpolation" { + let result = 123; + let s = "{result}"; + // Should be "123" + assert(strcmp(s, "123") == 0, "Implicit f-string failed"); +} + +test "implicit_fstring_complex" { + let a = 10; + let b = 20; + let s = "Sum: {a + b}"; + assert(strcmp(s, "Sum: 30") == 0, "Complex implicit f-string failed"); +} + +test "no_interpolation" { + let s = "Hello World"; + assert(strcmp(s, "Hello World") == 0, "Plain string failed"); +} diff --git a/tests/features/test_traits_suite.zc b/tests/features/test_traits_suite.zc index 205bdf6..2ff8378 100644 --- a/tests/features/test_traits_suite.zc +++ b/tests/features/test_traits_suite.zc @@ -90,7 +90,7 @@ test "test_derive" { // Debug let s = p1.to_string(); - assert(strcmp(s, "Point { ... }") == 0, "Debug string matches"); + assert(strcmp(s, "Point {{ ... }}") == 0, "Debug string matches"); // Clone let p2 = p1.clone(); -- cgit v1.2.3 From 4acbcb77483ff8fc127dca261864877675fa3b5a Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Sat, 31 Jan 2026 01:30:34 +0000 Subject: Update codegen for robustness --- src/codegen/codegen.h | 4 ++-- src/codegen/codegen_decl.c | 6 +++--- src/codegen/codegen_main.c | 2 +- src/codegen/codegen_stmt.c | 2 +- src/codegen/codegen_utils.c | 49 +++++++++++++++++++++------------------------ 5 files changed, 30 insertions(+), 33 deletions(-) (limited to 'src/codegen/codegen_stmt.c') diff --git a/src/codegen/codegen.h b/src/codegen/codegen.h index b3e971d..89614f7 100644 --- a/src/codegen/codegen.h +++ b/src/codegen/codegen.h @@ -48,7 +48,7 @@ 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); char *codegen_type_to_string(Type *t); -void emit_func_signature(FILE *out, ASTNode *func, const char *name_override); +void emit_func_signature(ParserContext *ctx, FILE *out, ASTNode *func, const char *name_override); char *strip_template_suffix(const char *name); int emit_move_invalidation(ParserContext *ctx, ASTNode *node, FILE *out); void codegen_expression_with_move(ParserContext *ctx, ASTNode *node, FILE *out); @@ -66,7 +66,7 @@ void emit_trait_defs(ASTNode *node, FILE *out); void emit_enum_protos(ASTNode *node, FILE *out); void emit_globals(ParserContext *ctx, ASTNode *node, FILE *out); void emit_lambda_defs(ParserContext *ctx, FILE *out); -void emit_protos(ASTNode *node, FILE *out); +void emit_protos(ParserContext *ctx, ASTNode *node, FILE *out); void emit_impl_vtables(ParserContext *ctx, FILE *out); /** diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c index 0b78676..9d23617 100644 --- a/src/codegen/codegen_decl.c +++ b/src/codegen/codegen_decl.c @@ -698,7 +698,7 @@ void emit_globals(ParserContext *ctx, ASTNode *node, FILE *out) } // Emit function prototypes -void emit_protos(ASTNode *node, FILE *out) +void emit_protos(ParserContext *ctx, ASTNode *node, FILE *out) { ASTNode *f = node; while (f) @@ -721,7 +721,7 @@ void emit_protos(ASTNode *node, FILE *out) } else { - emit_func_signature(out, f, NULL); + emit_func_signature(ctx, out, f, NULL); fprintf(out, ";\n"); } } @@ -799,7 +799,7 @@ void emit_protos(ASTNode *node, FILE *out) } else { - emit_func_signature(out, m, proto); + emit_func_signature(ctx, out, m, proto); fprintf(out, ";\n"); } diff --git a/src/codegen/codegen_main.c b/src/codegen/codegen_main.c index a140070..b298700 100644 --- a/src/codegen/codegen_main.c +++ b/src/codegen/codegen_main.c @@ -616,7 +616,7 @@ void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out) } } - emit_protos(merged_funcs, out); + emit_protos(ctx, merged_funcs, out); emit_impl_vtables(ctx, out); diff --git a/src/codegen/codegen_stmt.c b/src/codegen/codegen_stmt.c index 2f9a2ba..7828ecf 100644 --- a/src/codegen/codegen_stmt.c +++ b/src/codegen/codegen_stmt.c @@ -750,7 +750,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out) { fprintf(out, "inline "); } - emit_func_signature(out, node, NULL); + emit_func_signature(ctx, out, node, NULL); fprintf(out, "\n"); fprintf(out, "{\n"); char *prev_ret = g_current_func_ret_type; diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c index 39d1861..08707cc 100644 --- a/src/codegen/codegen_utils.c +++ b/src/codegen/codegen_utils.c @@ -41,7 +41,7 @@ char *strip_template_suffix(const char *name) } // Helper to emit C declaration (handle arrays, function pointers correctly) -void emit_c_decl(FILE *out, const char *type_str, const char *name) +void emit_c_decl(ParserContext *ctx, FILE *out, const char *type_str, const char *name) { char *bracket = strchr(type_str, '['); char *generic = strchr(type_str, '<'); @@ -64,40 +64,38 @@ void emit_c_decl(FILE *out, const char *type_str, const char *name) } else if (generic && (!bracket || generic < bracket)) { - // Special case: Async should NOT be mangled to Async_T - // because it compiles to the opaque struct 'Async' (defined in codegen_decl) - if (strncmp(type_str, "Async<", 6) == 0) - { - fprintf(out, "Async %s", name); - if (bracket) - { - fprintf(out, "%s", bracket); - } - return; - } - + char mangled_candidate[256]; char *gt = strchr(generic, '>'); + int success = 0; + if (gt) { int base_len = generic - type_str; int arg_len = gt - generic - 1; - fprintf(out, "%.*s_%.*s %s", base_len, type_str, arg_len, generic + 1, name); - - if (bracket) + // Limit check + if (base_len + arg_len + 2 < 256) { - fprintf(out, "%s", bracket); + snprintf(mangled_candidate, 256, "%.*s_%.*s", base_len, type_str, arg_len, + generic + 1); + + if (find_struct_def_codegen(ctx, mangled_candidate)) + { + fprintf(out, "%s %s", mangled_candidate, name); + success = 1; + } } } - else + + if (!success) { int base_len = generic - type_str; fprintf(out, "%.*s %s", base_len, type_str, name); + } - if (bracket) - { - fprintf(out, "%s", bracket); - } + if (bracket) + { + fprintf(out, "%s", bracket); } } else if (bracket) @@ -114,8 +112,7 @@ void emit_c_decl(FILE *out, const char *type_str, const char *name) // 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; - emit_c_decl(out, type_str, var_name); + emit_c_decl(ctx, out, type_str, var_name); } // Find struct definition @@ -671,7 +668,7 @@ char *codegen_type_to_string(Type *t) } // Emit function signature using Type info for correct C codegen -void emit_func_signature(FILE *out, ASTNode *func, const char *name_override) +void emit_func_signature(ParserContext *ctx, FILE *out, ASTNode *func, const char *name_override) { if (!func || func->type != NODE_FUNCTION) { @@ -763,7 +760,7 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override) } // check if array type - emit_c_decl(out, type_str, name); + emit_c_decl(ctx, out, type_str, name); free(type_str); } if (func->func.is_varargs) -- cgit v1.2.3