From c735d4b45f2db336e2aff8d94da7a08bb1fad68f Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Fri, 23 Jan 2026 15:55:02 +0000 Subject: Update for tuples. --- src/codegen/codegen.c | 20 +++++++- src/parser/parser_expr.c | 125 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 137 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 22cbc15..95e0ccd 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -603,7 +603,15 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *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); + char *field = node->member.field; + if (field && field[0] >= '0' && field[0] <= '9') + { + fprintf(out, "); _t ? _t->v%s : 0; })", field); + } + else + { + fprintf(out, "); _t ? _t->%s : 0; })", field); + } } else { @@ -619,7 +627,15 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) { free(lt); } - fprintf(out, "%s%s", actually_ptr ? "->" : ".", node->member.field); + char *field = node->member.field; + if (field && field[0] >= '0' && field[0] <= '9') + { + fprintf(out, "%sv%s", actually_ptr ? "->" : ".", field); + } + else + { + fprintf(out, "%s%s", actually_ptr ? "->" : ".", field); + } } break; case NODE_EXPR_INDEX: diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c index bfbdb28..990942d 100644 --- a/src/parser/parser_expr.c +++ b/src/parser/parser_expr.c @@ -20,6 +20,7 @@ int is_struct_type(ParserContext *ctx, const char *type_name) } Type *get_field_type(ParserContext *ctx, Type *struct_type, const char *field_name); +char *infer_type(ParserContext *ctx, ASTNode *node); // from codegen int is_type_copy(ParserContext *ctx, Type *t) { @@ -2387,11 +2388,123 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) l->pos = saved; // Reset if not a cast ASTNode *expr = parse_expression(ctx, l); - if (lexer_next(l).type != TOK_RPAREN) + + // Check for tuple literal: (expr, expr, ...) + if (lexer_peek(l).type == TOK_COMMA) + { + // This is a tuple literal - collect all elements and infer types + ASTNode **elements = xmalloc(sizeof(ASTNode *) * 16); + char **type_strs = xmalloc(sizeof(char *) * 16); + int count = 0; + + // First element + elements[count] = expr; + char *t1 = infer_type(ctx, expr); + type_strs[count] = t1 ? t1 : xstrdup("int"); + count++; + + // Parse remaining elements + while (lexer_peek(l).type == TOK_COMMA) + { + lexer_next(l); // eat comma + ASTNode *elem = parse_expression(ctx, l); + elements[count] = elem; + char *ti = infer_type(ctx, elem); + type_strs[count] = ti ? ti : xstrdup("int"); + count++; + } + + if (lexer_next(l).type != TOK_RPAREN) + { + zpanic_at(lexer_peek(l), "Expected ) after tuple"); + } + + // Build tuple signature + char sig[512]; + sig[0] = 0; + for (int i = 0; i < count; i++) + { + if (i > 0) + { + strcat(sig, "_"); + } + strcat(sig, type_strs[i]); + } + + register_tuple(ctx, sig); + + char tuple_name[256]; + sprintf(tuple_name, "Tuple_%s", sig); + + char *code = xmalloc(4096); + sprintf(code, "(%s){", tuple_name); + + for (int i = 0; i < count; i++) + { + if (i > 0) + { + strcat(code, ", "); + } + + if (elements[i]->type == NODE_EXPR_LITERAL) + { + char buf[256]; + if (elements[i]->literal.type_kind == 0) // int + { + sprintf(buf, "%lld", elements[i]->literal.int_val); + } + else if (elements[i]->literal.type_kind == 1) // float + { + sprintf(buf, "%f", elements[i]->literal.float_val); + } + else if (elements[i]->literal.type_kind == 2) // string + { + sprintf(buf, "\"%s\"", elements[i]->literal.string_val); + } + else + { + sprintf(buf, "0"); + } + strcat(code, buf); + } + else if (elements[i]->type == NODE_EXPR_VAR) + { + strcat(code, elements[i]->var_ref.name); + } + else + { + // For complex expressions, we need a different approach + // For now, just put a placeholder - this won't work for all cases + // So it's a TODO... + strcat(code, "/* complex expr */0"); + } + } + strcat(code, "}"); + + node = ast_create(NODE_RAW_STMT); + node->raw_stmt.content = code; + + // Set type info + Type *tuple_type = type_new(TYPE_STRUCT); + tuple_type->name = xstrdup(tuple_name); + node->type_info = tuple_type; + + // Cleanup + free(elements); + for (int i = 0; i < count; i++) + { + free(type_strs[i]); + } + free(type_strs); + } + else { - zpanic_at(lexer_peek(l), "Expected )"); + if (lexer_next(l).type != TOK_RPAREN) + { + zpanic_at(lexer_peek(l), "Expected )"); + } + node = expr; } - node = expr; } else if (t.type == TOK_LBRACKET) @@ -3488,7 +3601,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) { lexer_next(l); Token field = lexer_next(l); - if (field.type != TOK_IDENT) + if (field.type != TOK_IDENT && field.type != TOK_INT) { zpanic_at(field, "Expected field name after ->"); break; @@ -3517,7 +3630,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) { lexer_next(l); Token field = lexer_next(l); - if (field.type != TOK_IDENT) + if (field.type != TOK_IDENT && field.type != TOK_INT) { zpanic_at(field, "Expected field name after ?."); break; @@ -4080,7 +4193,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) if (op.type == TOK_OP && is_token(op, ".")) { Token field = lexer_next(l); - if (field.type != TOK_IDENT) + if (field.type != TOK_IDENT && field.type != TOK_INT) { zpanic_at(field, "Expected field name after ."); break; -- cgit v1.2.3