diff options
| author | iryuken <eshwarsajja20@gmail.com> | 2026-01-25 23:29:00 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-25 23:29:00 +0530 |
| commit | 1c4a6e1cf58503499b1c8245c1d15bd70efe0048 (patch) | |
| tree | 71b952ad455bf17d5bdea01472f0e2297f25eabe /src/parser | |
| parent | 863118c95caac0d69a35f6ae4d2e83844734a8a1 (diff) | |
| parent | ebc8b94baa6bc694cb4829e2eb2934a1f17fa6a1 (diff) | |
Merge pull request
fix merge conflicts and #105
Diffstat (limited to 'src/parser')
| -rw-r--r-- | src/parser/parser.h | 5 | ||||
| -rw-r--r-- | src/parser/parser_core.c | 8 | ||||
| -rw-r--r-- | src/parser/parser_decl.c | 38 | ||||
| -rw-r--r-- | src/parser/parser_expr.c | 365 | ||||
| -rw-r--r-- | src/parser/parser_stmt.c | 241 | ||||
| -rw-r--r-- | src/parser/parser_struct.c | 120 | ||||
| -rw-r--r-- | src/parser/parser_type.c | 27 | ||||
| -rw-r--r-- | src/parser/parser_utils.c | 9 |
8 files changed, 688 insertions, 125 deletions
diff --git a/src/parser/parser.h b/src/parser/parser.h index 8857641..e1d6bb9 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -272,7 +272,8 @@ struct ParserContext // Type Validation struct TypeUsage *pending_type_validations; - int is_speculative; // Flag to suppress side effects during speculative parsing + int is_speculative; // Flag to suppress side effects during speculative parsing + int silent_warnings; // Suppress warnings (for example, during codegen interpolation) }; typedef struct TypeUsage @@ -433,7 +434,7 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l); ASTNode *parse_return(ParserContext *ctx, Lexer *l); char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, const char *target, - char ***used_syms, int *count); + char ***used_syms, int *count, int check_symbols); ASTNode *parse_assert(ParserContext *ctx, Lexer *l); ASTNode *parse_defer(ParserContext *ctx, Lexer *l); ASTNode *parse_asm(ParserContext *ctx, Lexer *l); diff --git a/src/parser/parser_core.c b/src/parser/parser_core.c index ff5dd1c..a02caea 100644 --- a/src/parser/parser_core.c +++ b/src/parser/parser_core.c @@ -337,18 +337,18 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l) { s = parse_import(ctx, l); } - else if (t.len == 3 && strncmp(t.start, "var", 3) == 0) + else if (t.len == 3 && strncmp(t.start, "let", 3) == 0) { s = parse_var_decl(ctx, l); } - else if (t.len == 3 && strncmp(t.start, "def", 3) == 0) + else if (t.len == 3 && strncmp(t.start, "var", 3) == 0) { - s = parse_def(ctx, l); + zpanic_at(t, "'var' is deprecated. Use 'let' instead."); } else if (t.len == 5 && strncmp(t.start, "const", 5) == 0) { zpanic_at(t, "'const' for declarations is deprecated. Use 'def' for constants or " - "'var x: const T' for read-only variables."); + "'let x: const T' for read-only variables."); } else if (t.len == 6 && strncmp(t.start, "extern", 6) == 0) { diff --git a/src/parser/parser_decl.c b/src/parser/parser_decl.c index 7e0cc5b..5d5af1e 100644 --- a/src/parser/parser_decl.c +++ b/src/parser/parser_decl.c @@ -207,17 +207,43 @@ char *patch_self_args(const char *args, const char *struct_name) { return NULL; } - char *new_args = xmalloc(strlen(args) + strlen(struct_name) + 10); + + // Sanitize struct name for C usage (Vec<T> -> Vec_T) + char *safe_name = xmalloc(strlen(struct_name) + 1); + int j = 0; + for (int i = 0; struct_name[i]; i++) + { + if (struct_name[i] == '<') + { + safe_name[j++] = '_'; + } + else if (struct_name[i] == '>') + { + // skip + } + else if (struct_name[i] == ' ') + { + // skip + } + else + { + safe_name[j++] = struct_name[i]; + } + } + safe_name[j] = 0; + + char *new_args = xmalloc(strlen(args) + strlen(safe_name) + 10); // Check if it starts with "void* self" if (strncmp(args, "void* self", 10) == 0) { - sprintf(new_args, "%s* self%s", struct_name, args + 10); + sprintf(new_args, "%s* self%s", safe_name, args + 10); } else { strcpy(new_args, args); } + free(safe_name); return new_args; } // Helper for Value-Returning Defer @@ -562,17 +588,17 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l) // Fallbacks for literals else if (init->type == NODE_EXPR_LITERAL) { - if (init->literal.type_kind == 0) + if (init->literal.type_kind == LITERAL_INT) { type = xstrdup("int"); type_obj = type_new(TYPE_INT); } - else if (init->literal.type_kind == 1) + else if (init->literal.type_kind == LITERAL_FLOAT) { type = xstrdup("float"); type_obj = type_new(TYPE_FLOAT); } - else if (init->literal.type_kind == 2) + else if (init->literal.type_kind == LITERAL_STRING) { type = xstrdup("string"); type_obj = type_new(TYPE_STRING); @@ -596,7 +622,7 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l) add_symbol_with_token(ctx, name, type, type_obj, name_tok); // NEW: Capture Const Integer Values - if (init && init->type == NODE_EXPR_LITERAL && init->literal.type_kind == 0) + if (init && init->type == NODE_EXPR_LITERAL && init->literal.type_kind == LITERAL_INT) { Symbol *s = find_symbol_entry(ctx, name); // Helper to find the struct if (s) diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c index 98b1c5d..da5379e 100644 --- a/src/parser/parser_expr.c +++ b/src/parser/parser_expr.c @@ -203,7 +203,7 @@ static void check_format_string(ASTNode *call, Token t) return; } - if (fmt_arg->type != NODE_EXPR_LITERAL || fmt_arg->literal.type_kind != TOK_STRING) + if (fmt_arg->type != NODE_EXPR_LITERAL || fmt_arg->literal.type_kind != 2) { return; } @@ -605,11 +605,17 @@ static void find_declared_vars(ASTNode *node, char ***decls, int *count) (*count)++; } - if (node->type == NODE_MATCH_CASE && node->match_case.binding_name) + if (node->type == NODE_MATCH_CASE) { - *decls = xrealloc(*decls, sizeof(char *) * (*count + 1)); - (*decls)[*count] = xstrdup(node->match_case.binding_name); - (*count)++; + if (node->match_case.binding_names) + { + for (int i = 0; i < node->match_case.binding_count; i++) + { + *decls = xrealloc(*decls, sizeof(char *) * (*count + 1)); + (*decls)[*count] = xstrdup(node->match_case.binding_names[i]); + (*count)++; + } + } } switch (node->type) @@ -783,6 +789,8 @@ ASTNode *parse_lambda(ParserContext *ctx, Lexer *l) lexer_next(l); + Type *t = type_new(TYPE_FUNCTION); + t->args = xmalloc(sizeof(Type *) * 16); char **param_names = xmalloc(sizeof(char *) * 16); char **param_types = xmalloc(sizeof(char *) * 16); int num_params = 0; @@ -814,9 +822,11 @@ ASTNode *parse_lambda(ParserContext *ctx, Lexer *l) lexer_next(l); - char *param_type_str = parse_type(ctx, l); - param_types[num_params] = param_type_str; + Type *typef = parse_type_formal(ctx, l); + t->args[t->arg_count] = typef; + param_types[num_params] = type_to_string(typef); num_params++; + t->arg_count = num_params; } lexer_next(l); @@ -824,7 +834,16 @@ ASTNode *parse_lambda(ParserContext *ctx, Lexer *l) if (lexer_peek(l).type == TOK_ARROW) { lexer_next(l); - return_type = parse_type(ctx, l); + + t->inner = parse_type_formal(ctx, l); + return_type = type_to_string(t->inner); + } + + enter_scope(ctx); + + for (int i = 0; i < num_params; i++) + { + add_symbol(ctx, param_names[i], param_types[i], t->args[i]); } ASTNode *body = NULL; @@ -845,9 +864,13 @@ ASTNode *parse_lambda(ParserContext *ctx, Lexer *l) lambda->lambda.num_params = num_params; lambda->lambda.lambda_id = ctx->lambda_counter++; lambda->lambda.is_expression = 0; + lambda->type_info = t; + lambda->resolved_type = type_to_string(t); register_lambda(ctx, lambda); analyze_lambda_captures(ctx, lambda); + exit_scope(ctx); + return lambda; } @@ -991,7 +1014,7 @@ static ASTNode *create_fstring_block(ParserContext *ctx, const char *content) char *fmt_str = xmalloc(strlen(fmt) + 3); sprintf(fmt_str, "%%%s", fmt); arg_fmt = ast_create(NODE_EXPR_LITERAL); - arg_fmt->literal.type_kind = 2; + arg_fmt->literal.type_kind = LITERAL_STRING; arg_fmt->literal.string_val = fmt_str; arg_fmt->type_info = type_new(TYPE_STRING); } @@ -1045,7 +1068,7 @@ static ASTNode *create_fstring_block(ParserContext *ctx, const char *content) static ASTNode *parse_int_literal(Token t) { ASTNode *node = ast_create(NODE_EXPR_LITERAL); - node->literal.type_kind = 0; + node->literal.type_kind = LITERAL_INT; node->type_info = type_new(TYPE_INT); char *s = token_strdup(t); unsigned long long val; @@ -1066,7 +1089,7 @@ static ASTNode *parse_int_literal(Token t) static ASTNode *parse_float_literal(Token t) { ASTNode *node = ast_create(NODE_EXPR_LITERAL); - node->literal.type_kind = 1; + node->literal.type_kind = LITERAL_FLOAT; node->literal.float_val = atof(t.start); node->type_info = type_new(TYPE_F64); return node; @@ -1076,7 +1099,7 @@ static ASTNode *parse_float_literal(Token t) static ASTNode *parse_string_literal(Token t) { ASTNode *node = ast_create(NODE_EXPR_LITERAL); - node->literal.type_kind = TOK_STRING; + node->literal.type_kind = LITERAL_STRING; node->literal.string_val = xmalloc(t.len); strncpy(node->literal.string_val, t.start + 1, t.len - 2); node->literal.string_val[t.len - 2] = 0; @@ -1099,7 +1122,7 @@ static ASTNode *parse_fstring_literal(ParserContext *ctx, Token t) static ASTNode *parse_char_literal(Token t) { ASTNode *node = ast_create(NODE_EXPR_LITERAL); - node->literal.type_kind = TOK_CHAR; + node->literal.type_kind = LITERAL_CHAR; node->literal.string_val = token_strdup(t); node->type_info = type_new(TYPE_I8); return node; @@ -1310,18 +1333,47 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) char *pattern = token_strdup(p); int is_default = (strcmp(pattern, "_") == 0); - char *binding = NULL; - int is_destructure = 0; - skip_comments(l); + // Handle Destructuring: Ok(v) or Rect(w, h) + char **bindings = NULL; + int *binding_refs = NULL; + int binding_count = 0; + int is_destructure = 0; // Initialize here + + // Assuming pattern_count is 1 for now, or needs to be determined + // For single identifier patterns, pattern_count would be 1. + // This logic needs to be adjusted if `pattern_count` is not available or needs to be + // calculated. For now, assuming `pattern_count == 1` is implicitly true for single + // token patterns. if (!is_default && lexer_peek(l).type == TOK_LPAREN) { - lexer_next(l); - Token b = lexer_next(l); - if (b.type != TOK_IDENT) + lexer_next(l); // eat ( + bindings = xmalloc(sizeof(char *) * 8); // Initial capacity + binding_refs = xmalloc(sizeof(int) * 8); // unused but consistent + + while (1) { - zpanic_at(b, "Expected binding name"); + int is_r = 0; + if (lexer_peek(l).type == TOK_IDENT && lexer_peek(l).len == 3 && + strncmp(lexer_peek(l).start, "ref", 3) == 0) + { + lexer_next(l); // eat ref + is_r = 1; + } + Token b = lexer_next(l); + if (b.type != TOK_IDENT) + { + zpanic_at(b, "Expected binding"); + } + bindings[binding_count] = token_strdup(b); + binding_refs[binding_count] = is_r; + binding_count++; + if (lexer_peek(l).type == TOK_COMMA) + { + lexer_next(l); + continue; + } + break; } - binding = token_strdup(b); if (lexer_next(l).type != TOK_RPAREN) { zpanic_at(lexer_peek(l), "Expected )"); @@ -1343,6 +1395,17 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) zpanic_at(lexer_peek(l), "Expected '=>'"); } + // Create scope for the case to hold the binding + enter_scope(ctx); + if (binding_count > 0) + { + for (int i = 0; i < binding_count; i++) + { + add_symbol(ctx, bindings[i], NULL, + NULL); // Let inference handle it or default to void*? + } + } + ASTNode *body; skip_comments(l); Token pk = lexer_peek(l); @@ -1364,9 +1427,13 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) body = parse_expression(ctx, l); } + exit_scope(ctx); + ASTNode *c = ast_create(NODE_MATCH_CASE); c->match_case.pattern = pattern; - c->match_case.binding_name = binding; + c->match_case.binding_names = bindings; // New multi-binding field + c->match_case.binding_count = binding_count; // New binding count field + c->match_case.binding_refs = binding_refs; c->match_case.is_destructuring = is_destructure; c->match_case.guard = guard; c->match_case.body = body; @@ -1579,13 +1646,59 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) v = v->next; } } + int resolved = 0; if (is_variant) { sprintf(tmp, "%s_%.*s", acc, suffix.len, suffix.start); + resolved = 1; } else { - sprintf(tmp, "%s__%.*s", acc, suffix.len, suffix.start); + char inherent_name[256]; + sprintf(inherent_name, "%s__%.*s", acc, suffix.len, + suffix.start); + + if (find_func(ctx, inherent_name)) + { + strcpy(tmp, inherent_name); + resolved = 1; + } + else + { + GenericImplTemplate *it = ctx->impl_templates; + while (it) + { + if (strcmp(it->struct_name, gname) == 0) + { + char *tname = NULL; + if (it->impl_node && + it->impl_node->type == NODE_IMPL_TRAIT) + { + tname = it->impl_node->impl_trait + .trait_name; + } + if (tname) + { + char cand[512]; + sprintf(cand, "%s__%s_%.*s", acc, tname, + suffix.len, suffix.start); + + if (find_func(ctx, cand)) + { + strcpy(tmp, cand); + resolved = 1; + break; + } + } + } + it = it->next; + } + } + if (!resolved) + { + sprintf(tmp, "%s__%.*s", acc, suffix.len, + suffix.start); + } } handled_as_generic = 1; break; // Found and handled @@ -2046,7 +2159,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) node->type_info = type_new(TYPE_INT); // Returns count ASTNode *fmt_node = ast_create(NODE_EXPR_LITERAL); - fmt_node->literal.type_kind = 2; // string + fmt_node->literal.type_kind = LITERAL_STRING; // string fmt_node->literal.string_val = xstrdup(fmt); ASTNode *head = fmt_node, *tail = fmt_node; @@ -2540,7 +2653,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) // Constant Folding for 'def', emits literal node = ast_create(NODE_EXPR_LITERAL); node->token = t; - node->literal.type_kind = 0; // INT (assumed for now from const_int_val) + node->literal.type_kind = LITERAL_INT; // INT (assumed for now from const_int_val) node->literal.int_val = sym->const_int_val; node->type_info = type_new(TYPE_INT); // No need for resolution @@ -2740,15 +2853,15 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) if (elements[i]->type == NODE_EXPR_LITERAL) { char buf[256]; - if (elements[i]->literal.type_kind == 0) // int + if (elements[i]->literal.type_kind == LITERAL_INT) // int { sprintf(buf, "%lld", elements[i]->literal.int_val); } - else if (elements[i]->literal.type_kind == 1) // float + else if (elements[i]->literal.type_kind == LITERAL_FLOAT) // float { sprintf(buf, "%f", elements[i]->literal.float_val); } - else if (elements[i]->literal.type_kind == 2) // string + else if (elements[i]->literal.type_kind == LITERAL_STRING) // string { sprintf(buf, "\"%s\"", elements[i]->literal.string_val); } @@ -2969,7 +3082,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) if (node->type_info && node->type_info->kind == TYPE_ARRAY && node->type_info->array_size > 0) { - if (index->type == NODE_EXPR_LITERAL && index->literal.type_kind == 0) + if (index->type == NODE_EXPR_LITERAL && index->literal.type_kind == LITERAL_INT) { int idx = index->literal.int_val; if (idx < 0 || idx >= node->type_info->array_size) @@ -3403,7 +3516,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) } // Reuse printf sugar to generate the prompt print - char *print_code = process_printf_sugar(ctx, inner, 0, "stdout", NULL, NULL); + char *print_code = process_printf_sugar(ctx, inner, 0, "stdout", NULL, NULL, 1); free(inner); // Checks for (args...) suffix for SCAN mode @@ -3498,7 +3611,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) call->type_info = type_new(TYPE_INT); ASTNode *fmt_node = ast_create(NODE_EXPR_LITERAL); - fmt_node->literal.type_kind = TOK_STRING; + fmt_node->literal.type_kind = LITERAL_STRING; fmt_node->literal.string_val = xstrdup(fmt); ASTNode *head = fmt_node, *tail = fmt_node; @@ -3532,7 +3645,10 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) free(print_code); ASTNode *n = ast_create(NODE_RAW_STMT); - n->raw_stmt.content = final_code; + char *stmt_code = xmalloc(strlen(final_code) + 2); + sprintf(stmt_code, "%s;", final_code); + free(final_code); + n->raw_stmt.content = stmt_code; return n; } } @@ -3568,11 +3684,14 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) newline = 0; } - char *code = process_printf_sugar(ctx, inner, newline, "stderr", NULL, NULL); + char *code = process_printf_sugar(ctx, inner, newline, "stderr", NULL, NULL, 1); free(inner); ASTNode *n = ast_create(NODE_RAW_STMT); - n->raw_stmt.content = code; + char *stmt_code = xmalloc(strlen(code) + 2); + sprintf(stmt_code, "%s;", code); + free(code); + n->raw_stmt.content = stmt_code; return n; } } @@ -4441,7 +4560,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) if (lhs->type_info && lhs->type_info->kind == TYPE_ARRAY && lhs->type_info->array_size > 0) { - if (start->type == NODE_EXPR_LITERAL && start->literal.type_kind == 0) + if (start->type == NODE_EXPR_LITERAL && start->literal.type_kind == LITERAL_INT) { int idx = start->literal.int_val; if (idx < 0 || idx >= lhs->type_info->array_size) @@ -4564,7 +4683,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) if (find_func(ctx, trait_mangled)) { strcpy(mangled, trait_mangled); // Update mangled name - sig = find_func(ctx, mangled); + sig = find_func(ctx, trait_mangled); break; } } @@ -4819,7 +4938,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) if (strcmp(bin->binary.op, "/") == 0 || strcmp(bin->binary.op, "%") == 0) { - if (rhs->type == NODE_EXPR_LITERAL && rhs->literal.type_kind == 0 && + if (rhs->type == NODE_EXPR_LITERAL && rhs->literal.type_kind == LITERAL_INT && rhs->literal.int_val == 0) { warn_division_by_zero(op); @@ -4845,8 +4964,8 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) } } } - else if (lhs->type == NODE_EXPR_LITERAL && lhs->literal.type_kind == 0 && - rhs->type == NODE_EXPR_LITERAL && rhs->literal.type_kind == 0) + else if (lhs->type == NODE_EXPR_LITERAL && lhs->literal.type_kind == LITERAL_INT && + rhs->type == NODE_EXPR_LITERAL && rhs->literal.type_kind == LITERAL_INT) { // Check if literals make sense (e.g. 5 > 5) if (lhs->literal.int_val == rhs->literal.int_val) @@ -4865,7 +4984,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) if (lhs->type_info && type_is_unsigned(lhs->type_info)) { - if (rhs->type == NODE_EXPR_LITERAL && rhs->literal.type_kind == 0 && + if (rhs->type == NODE_EXPR_LITERAL && rhs->literal.type_kind == LITERAL_INT && rhs->literal.int_val == 0) { if (strcmp(bin->binary.op, ">=") == 0) @@ -5245,6 +5364,63 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) // Standard Type Checking (if no overload found) if (lhs->type_info && rhs->type_info) { + // Ensure type_info is set for variables (critical for inference) + if (lhs->type == NODE_EXPR_VAR && !lhs->type_info) + { + Symbol *s = find_symbol_entry(ctx, lhs->var_ref.name); + if (s) + { + lhs->type_info = s->type_info; + } + } + if (rhs->type == NODE_EXPR_VAR && !rhs->type_info) + { + Symbol *s = find_symbol_entry(ctx, rhs->var_ref.name); + if (s) + { + rhs->type_info = s->type_info; + } + } + + // Backward Inference for Lambda Params + // LHS is Unknown Var, RHS is Known + if (lhs->type == NODE_EXPR_VAR && lhs->type_info && + lhs->type_info->kind == TYPE_UNKNOWN && rhs->type_info && + rhs->type_info->kind != TYPE_UNKNOWN) + { + // Infer LHS type from RHS + Symbol *sym = find_symbol_entry(ctx, lhs->var_ref.name); + if (sym) + { + // Update Symbol + sym->type_info = rhs->type_info; + sym->type_name = type_to_string(rhs->type_info); + + // Update AST Node + lhs->type_info = rhs->type_info; + lhs->resolved_type = xstrdup(sym->type_name); + } + } + + // RHS is Unknown Var, LHS is Known + if (rhs->type == NODE_EXPR_VAR && rhs->type_info && + rhs->type_info->kind == TYPE_UNKNOWN && lhs->type_info && + lhs->type_info->kind != TYPE_UNKNOWN) + { + // Infer RHS type from LHS + Symbol *sym = find_symbol_entry(ctx, rhs->var_ref.name); + if (sym) + { + // Update Symbol + sym->type_info = lhs->type_info; + sym->type_name = type_to_string(lhs->type_info); + + // Update AST Node + rhs->type_info = lhs->type_info; + rhs->resolved_type = xstrdup(sym->type_name); + } + } + if (is_comparison_op(bin->binary.op)) { bin->type_info = type_new(TYPE_INT); // bool @@ -5366,6 +5542,51 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) if (!is_ptr_arith && !alias_match) { + // ** Backward Inference for Binary Ops ** + // Case 1: LHS is Unknown Var, RHS is Known + if (lhs->type == NODE_EXPR_VAR && lhs->type_info && + lhs->type_info->kind == TYPE_UNKNOWN && rhs->type_info && + rhs->type_info->kind != TYPE_UNKNOWN) + { + // Infer LHS type from RHS + Symbol *sym = find_symbol_entry(ctx, lhs->var_ref.name); + if (sym) + { + // Update Symbol + sym->type_info = rhs->type_info; + sym->type_name = type_to_string(rhs->type_info); + + // Update AST Node + lhs->type_info = rhs->type_info; + lhs->resolved_type = xstrdup(sym->type_name); + + bin->type_info = rhs->type_info; + goto bin_inference_success; + } + } + + // Case 2: RHS is Unknown Var, LHS is Known + if (rhs->type == NODE_EXPR_VAR && rhs->type_info && + rhs->type_info->kind == TYPE_UNKNOWN && lhs->type_info && + lhs->type_info->kind != TYPE_UNKNOWN) + { + // Infer RHS type from LHS + Symbol *sym = find_symbol_entry(ctx, rhs->var_ref.name); + if (sym) + { + // Update Symbol + sym->type_info = lhs->type_info; + sym->type_name = type_to_string(lhs->type_info); + + // Update AST Node + rhs->type_info = lhs->type_info; + rhs->resolved_type = xstrdup(sym->type_name); + + bin->type_info = lhs->type_info; + goto bin_inference_success; + } + } + // Allow assigning 0 to pointer (NULL) int is_null_assign = 0; if (strcmp(bin->binary.op, "=") == 0) @@ -5452,6 +5673,8 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec) zpanic_with_suggestion(op, msg, suggestion); } } + + bin_inference_success:; } } } @@ -5469,21 +5692,21 @@ ASTNode *parse_arrow_lambda_single(ParserContext *ctx, Lexer *l, char *param_nam lambda->lambda.param_names[0] = param_name; lambda->lambda.num_params = 1; - // Default param type: int + // Default param type: unknown (to be inferred) lambda->lambda.param_types = xmalloc(sizeof(char *)); - lambda->lambda.param_types[0] = xstrdup("int"); + lambda->lambda.param_types[0] = NULL; - // Create Type Info: int -> int + // Create Type Info: unknown -> unknown Type *t = type_new(TYPE_FUNCTION); - t->inner = type_new(TYPE_INT); // Return + t->inner = type_new(TYPE_INT); // Return (default to int) t->args = xmalloc(sizeof(Type *)); - t->args[0] = type_new(TYPE_INT); // Arg + t->args[0] = type_new(TYPE_UNKNOWN); // Arg t->arg_count = 1; lambda->type_info = t; // Register parameter in scope for body parsing enter_scope(ctx); - add_symbol(ctx, param_name, "int", type_new(TYPE_INT)); + add_symbol(ctx, param_name, NULL, t->args[0]); // Body parsing... ASTNode *body_block = NULL; @@ -5500,7 +5723,55 @@ ASTNode *parse_arrow_lambda_single(ParserContext *ctx, Lexer *l, char *param_nam body_block->block.statements = ret; } lambda->lambda.body = body_block; - lambda->lambda.return_type = xstrdup("int"); + + // Attempt to infer return type from body if it's a simple return + if (lambda->lambda.body->block.statements && + lambda->lambda.body->block.statements->type == NODE_RETURN && + !lambda->lambda.body->block.statements->next) + { + ASTNode *ret_val = lambda->lambda.body->block.statements->ret.value; + if (ret_val->type_info && ret_val->type_info->kind != TYPE_UNKNOWN) + { + if (param_name[0] == 'x') + { + // fprintf(stderr, "DEBUG: Updating return type to %d\n", ret_val->type_info->kind); + } + // Update return type + if (t->inner) + { + free(t->inner); + } + t->inner = ret_val->type_info; + } + } + + // Update parameter types from symbol table (in case inference happened) + Symbol *sym = find_symbol_entry(ctx, param_name); + if (sym && sym->type_info && sym->type_info->kind != TYPE_UNKNOWN) + { + free(lambda->lambda.param_types[0]); + lambda->lambda.param_types[0] = type_to_string(sym->type_info); + t->args[0] = sym->type_info; + } + else + { + // Fallback to int if still unknown + if (lambda->lambda.param_types[0]) + { + free(lambda->lambda.param_types[0]); + } + lambda->lambda.param_types[0] = xstrdup("int"); + t->args[0] = type_new(TYPE_INT); // FIX: Update AST type info too! + + // Update symbol to match fallback + if (sym) + { + sym->type_name = xstrdup("int"); + sym->type_info = type_new(TYPE_INT); + } + } + + lambda->lambda.return_type = type_to_string(t->inner); lambda->lambda.lambda_id = ctx->lambda_counter++; lambda->lambda.is_expression = 1; register_lambda(ctx, lambda); diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c index 73ae249..0c3885a 100644 --- a/src/parser/parser_stmt.c +++ b/src/parser/parser_stmt.c @@ -133,32 +133,48 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l) char *pattern = xstrdup(patterns_buf); int is_default = (strcmp(pattern, "_") == 0); - - char *binding = NULL; int is_destructure = 0; - int is_ref = 0; + // Handle Destructuring: Ok(v) or Rect(w, h) + char **bindings = NULL; + int *binding_refs = NULL; + int binding_count = 0; - // Handle Destructuring: Ok(v) - // (Only allowed if we matched a single pattern, e.g. "Result::Ok(val)") if (!is_default && pattern_count == 1 && lexer_peek(l).type == TOK_LPAREN) { lexer_next(l); // eat ( - // Check for 'ref' keyword - if (lexer_peek(l).type == TOK_IDENT && lexer_peek(l).len == 3 && - strncmp(lexer_peek(l).start, "ref", 3) == 0) - { - lexer_next(l); // eat 'ref' - is_ref = 1; - } + bindings = xmalloc(sizeof(char *) * 8); // hardcap at 8 for now or realloc + binding_refs = xmalloc(sizeof(int) * 8); - Token b = lexer_next(l); - if (b.type != TOK_IDENT) + while (1) { - zpanic_at(b, "Expected variable name in pattern"); + int is_r = 0; + // Check for 'ref' keyword + if (lexer_peek(l).type == TOK_IDENT && lexer_peek(l).len == 3 && + strncmp(lexer_peek(l).start, "ref", 3) == 0) + { + lexer_next(l); // eat 'ref' + is_r = 1; + } + + Token b = lexer_next(l); + if (b.type != TOK_IDENT) + { + zpanic_at(b, "Expected variable name in pattern"); + } + bindings[binding_count] = token_strdup(b); + binding_refs[binding_count] = is_r; + binding_count++; + + if (lexer_peek(l).type == TOK_COMMA) + { + lexer_next(l); + continue; + } + break; } - binding = token_strdup(b); + if (lexer_next(l).type != TOK_RPAREN) { zpanic_at(lexer_peek(l), "Expected )"); @@ -166,7 +182,7 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l) is_destructure = 1; } - // --- 3. Parse Guard (if condition) --- + // Parse Guard (if condition) ASTNode *guard = NULL; if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "if", 2) == 0) { @@ -182,18 +198,21 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l) // Create scope for the case to hold the binding enter_scope(ctx); - if (binding) + if (binding_count > 0) { // Try to infer binding type from enum variant payload - char *binding_type = is_ref ? "void*" : "unknown"; - Type *binding_type_info = NULL; - // Look up the enum variant to get its payload type EnumVariantReg *vreg = find_enum_variant(ctx, pattern); + + ASTNode *payload_node_field = NULL; + int is_tuple_payload = 0; + Type *payload_type = NULL; + ASTNode *enum_def = NULL; + if (vreg) { // Find the enum definition - ASTNode *enum_def = find_struct_def(ctx, vreg->enum_name); + enum_def = find_struct_def(ctx, vreg->enum_name); if (enum_def && enum_def->type == NODE_ENUM) { // Find the specific variant @@ -207,25 +226,107 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l) if (strcmp(v_full, pattern) == 0 && v->variant.payload) { // Found the variant, extract payload type - binding_type_info = v->variant.payload; - binding_type = type_to_string(v->variant.payload); - if (is_ref) + payload_type = v->variant.payload; + if (payload_type && payload_type->kind == TYPE_STRUCT && + strncmp(payload_type->name, "Tuple_", 6) == 0) { - // For ref bindings, make it a pointer to the payload type - char *ptr_type = xmalloc(strlen(binding_type) + 2); - sprintf(ptr_type, "%s*", binding_type); - binding_type = ptr_type; + is_tuple_payload = 1; + ASTNode *tuple_def = find_struct_def(ctx, payload_type->name); + if (tuple_def) + { + payload_node_field = tuple_def->strct.fields; + } } free(v_full); break; } - free(v_full); v = v->next; } } } - add_symbol(ctx, binding, binding_type, binding_type_info); + for (int i = 0; i < binding_count; i++) + { + char *binding = bindings[i]; + int is_ref = binding_refs[i]; + char *binding_type = is_ref ? "void*" : "unknown"; + Type *binding_type_info = NULL; // Default unknown + + if (payload_type) + { + if (binding_count == 1 && !is_tuple_payload) + { + binding_type = type_to_string(payload_type); + binding_type_info = payload_type; + } + else if (binding_count == 1 && is_tuple_payload) + { + binding_type = type_to_string(payload_type); + binding_type_info = payload_type; + } + else if (binding_count > 1 && is_tuple_payload) + { + if (payload_node_field) + { + Lexer tmp; + lexer_init(&tmp, payload_node_field->field.type); + binding_type_info = parse_type_formal(ctx, &tmp); + binding_type = type_to_string(binding_type_info); + payload_node_field = payload_node_field->next; + } + } + } + + if (is_ref && binding_type_info) + { + Type *ptr = type_new(TYPE_POINTER); + ptr->inner = binding_type_info; + binding_type_info = ptr; + + char *ptr_s = xmalloc(strlen(binding_type) + 2); + sprintf(ptr_s, "%s*", binding_type); + binding_type = ptr_s; + } + + int is_generic_unresolved = 0; + + if (enum_def) + { + if (enum_def->enm.generic_param) + { + char *param = enum_def->enm.generic_param; + if (strstr(binding_type, param)) + { + is_generic_unresolved = 1; + } + } + } + + if (!is_generic_unresolved && + (strcmp(binding_type, "T") == 0 || strcmp(binding_type, "T*") == 0)) + { + is_generic_unresolved = 1; + } + + if (is_generic_unresolved) + { + if (is_ref) + { + binding_type = "unknown*"; + Type *u = type_new(TYPE_UNKNOWN); + Type *p = type_new(TYPE_POINTER); + p->inner = u; + binding_type_info = p; + } + else + { + binding_type = "unknown"; + binding_type_info = type_new(TYPE_UNKNOWN); + } + } + + add_symbol(ctx, binding, binding_type, binding_type_info); + } } ASTNode *body; @@ -252,9 +353,10 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l) ASTNode *c = ast_create(NODE_MATCH_CASE); c->match_case.pattern = pattern; - c->match_case.binding_name = binding; + c->match_case.binding_names = bindings; + c->match_case.binding_count = binding_count; + c->match_case.binding_refs = binding_refs; c->match_case.is_destructuring = is_destructure; - c->match_case.is_ref = is_ref; // Store is_ref flag c->match_case.guard = guard; c->match_case.body = body; c->match_case.is_default = is_default; @@ -917,8 +1019,8 @@ ASTNode *parse_while(ParserContext *ctx, Lexer *l) check_assignment_condition(cond); // Zen: While(true) - if ((cond->type == NODE_EXPR_LITERAL && cond->literal.type_kind == TOK_INT && - strcmp(cond->literal.string_val, "1") == 0) || + if ((cond->type == NODE_EXPR_LITERAL && cond->literal.type_kind == LITERAL_INT && + cond->literal.int_val == 1) || (cond->type == NODE_EXPR_VAR && strcmp(cond->var_ref.name, "true") == 0)) { zen_trigger_at(TRIGGER_WHILE_TRUE, cond->token); @@ -1060,7 +1162,7 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) // while(true) ASTNode *while_loop = ast_create(NODE_WHILE); ASTNode *true_lit = ast_create(NODE_EXPR_LITERAL); - true_lit->literal.type_kind = TOK_INT; // Treated as bool in conditions + true_lit->literal.type_kind = LITERAL_INT; // Treated as bool in conditions true_lit->literal.int_val = 1; true_lit->literal.string_val = xstrdup("1"); while_loop->while_stmt.condition = true_lit; @@ -1176,10 +1278,14 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) ASTNode *init = NULL; if (lexer_peek(l).type != TOK_SEMICOLON) { - if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "var", 3) == 0) + if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "let", 3) == 0) { init = parse_var_decl(ctx, l); } + else if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "var", 3) == 0) + { + zpanic_at(lexer_peek(l), "'var' is deprecated. Use 'let' instead."); + } else { init = parse_expression(ctx, l); @@ -1203,7 +1309,7 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) { // Empty condition = true ASTNode *true_lit = ast_create(NODE_EXPR_LITERAL); - true_lit->literal.type_kind = 0; + true_lit->literal.type_kind = LITERAL_INT; true_lit->literal.int_val = 1; cond = true_lit; } @@ -1243,8 +1349,10 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) } char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, const char *target, - char ***used_syms, int *count) + char ***used_syms, int *count, int check_symbols) { + int saved_silent = ctx->silent_warnings; + ctx->silent_warnings = !check_symbols; char *gen = xmalloc(8192); strcpy(gen, "({ "); @@ -1345,7 +1453,7 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, // Analyze usage & Type Check for to_string() char *final_expr = xstrdup(clean_expr); - // Use final_expr in usage analysis if needed, but mainly for symbol tracking + if (check_symbols) { Lexer lex; lexer_init(&lex, clean_expr); // Scan original for symbols @@ -1381,6 +1489,7 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, // Parse expression fully Lexer lex; lexer_init(&lex, clean_expr); + ASTNode *expr_node = parse_expression(ctx, &lex); char *rw_expr = NULL; @@ -1413,10 +1522,15 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, { char *inner_c = NULL; size_t len = 0; - FILE *ms = open_memstream(&inner_c, &len); + FILE *ms = tmpfile(); if (ms) { codegen_expression(ctx, expr_node, ms); + len = ftell(ms); + fseek(ms, 0, SEEK_SET); + inner_c = xmalloc(len + 1); + fread(inner_c, 1, len, ms); + inner_c[len] = 0; fclose(ms); } @@ -1443,10 +1557,15 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, { char *buf = NULL; size_t len = 0; - FILE *ms = open_memstream(&buf, &len); + FILE *ms = tmpfile(); if (ms) { codegen_expression(ctx, expr_node, ms); + len = ftell(ms); + fseek(ms, 0, SEEK_SET); + buf = xmalloc(len + 1); + fread(buf, 1, len, ms); + buf[len] = 0; fclose(ms); rw_expr = buf; used_codegen = 1; @@ -1584,6 +1703,7 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline, strcat(gen, "0; })"); free(s); + ctx->silent_warnings = saved_silent; return gen; } @@ -1759,7 +1879,8 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) int is_ln = (next_type == TOK_SEMICOLON); char **used_syms = NULL; int used_count = 0; - char *code = process_printf_sugar(ctx, inner, is_ln, "stdout", &used_syms, &used_count); + char *code = + process_printf_sugar(ctx, inner, is_ln, "stdout", &used_syms, &used_count, 1); if (next_type == TOK_SEMICOLON) { @@ -1775,7 +1896,11 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) } ASTNode *n = ast_create(NODE_RAW_STMT); - n->raw_stmt.content = code; + // Append semicolon to Statement Expression to make it a valid statement + char *stmt_code = xmalloc(strlen(code) + 2); + sprintf(stmt_code, "%s;", code); + free(code); + n->raw_stmt.content = stmt_code; n->raw_stmt.used_symbols = used_syms; n->raw_stmt.used_symbol_count = used_count; free(inner); @@ -1801,9 +1926,9 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) if (tk.type == TOK_AUTOFREE) { lexer_next(l); - if (lexer_peek(l).type != TOK_IDENT || strncmp(lexer_peek(l).start, "var", 3) != 0) + if (lexer_peek(l).type != TOK_IDENT || strncmp(lexer_peek(l).start, "let", 3) != 0) { - zpanic_at(lexer_peek(l), "Expected 'var' after autofree"); + zpanic_at(lexer_peek(l), "Expected 'let' after autofree"); } s = parse_var_decl(ctx, l); s->var_decl.is_autofree = 1; @@ -1942,28 +2067,33 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) return parse_plugin(ctx, l); } - if (strncmp(tk.start, "var", 3) == 0 && tk.len == 3) + if (strncmp(tk.start, "let", 3) == 0 && tk.len == 3) { return parse_var_decl(ctx, l); } - // Static local variable: static var x = 0; + if (strncmp(tk.start, "var", 3) == 0 && tk.len == 3) + { + zpanic_at(tk, "'var' is deprecated. Use 'let' instead."); + } + + // Static local variable: static let x = 0; if (strncmp(tk.start, "static", 6) == 0 && tk.len == 6) { lexer_next(l); // eat 'static' Token next = lexer_peek(l); - if (strncmp(next.start, "var", 3) == 0 && next.len == 3) + if (strncmp(next.start, "let", 3) == 0 && next.len == 3) { ASTNode *v = parse_var_decl(ctx, l); v->var_decl.is_static = 1; return v; } - zpanic_at(next, "Expected 'var' after 'static'"); + zpanic_at(next, "Expected 'let' after 'static'"); } if (strncmp(tk.start, "const", 5) == 0 && tk.len == 5) { - zpanic_at(tk, "'const' for declarations is deprecated. Use 'def' for constants or 'var " + zpanic_at(tk, "'const' for declarations is deprecated. Use 'def' for constants or 'let " "x: const T' for read-only variables."); } if (strncmp(tk.start, "return", 6) == 0 && tk.len == 6) @@ -2312,7 +2442,8 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) char **used_syms = NULL; int used_count = 0; - char *code = process_printf_sugar(ctx, inner, is_ln, target, &used_syms, &used_count); + char *code = + process_printf_sugar(ctx, inner, is_ln, target, &used_syms, &used_count, 1); free(inner); if (lexer_peek(l).type == TOK_SEMICOLON) @@ -2321,7 +2452,11 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) } ASTNode *n = ast_create(NODE_RAW_STMT); - n->raw_stmt.content = code; + // Append semicolon to Statement Expression to make it a valid statement + char *stmt_code = xmalloc(strlen(code) + 2); + sprintf(stmt_code, "%s;", code); + free(code); + n->raw_stmt.content = stmt_code; n->raw_stmt.used_symbols = used_syms; n->raw_stmt.used_symbol_count = used_count; return n; diff --git a/src/parser/parser_struct.c b/src/parser/parser_struct.c index 7dea30c..cbe34c0 100644 --- a/src/parser/parser_struct.c +++ b/src/parser/parser_struct.c @@ -187,6 +187,19 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) Token t2 = lexer_next(l); char *name2 = token_strdup(t2); + char *target_gen_param = NULL; + if (lexer_peek(l).type == TOK_LANGLE) + { + lexer_next(l); // eat < + Token gt = lexer_next(l); + target_gen_param = token_strdup(gt); + if (lexer_next(l).type != TOK_RANGLE) + { + zpanic_at(lexer_peek(l), "Expected > in impl struct generic"); + } + register_generic(ctx, target_gen_param); + } + register_impl(ctx, name1, name2); // RAII: Check for "Drop" trait implementation @@ -231,6 +244,18 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) lexer_next(l); // eat { ASTNode *h = 0, *tl = 0; + + char *full_target_name = name2; + if (target_gen_param) + { + full_target_name = xmalloc(strlen(name2) + strlen(target_gen_param) + 3); + sprintf(full_target_name, "%s<%s>", name2, target_gen_param); + } + else + { + full_target_name = xstrdup(name2); + } + while (1) { skip_comments(l); @@ -247,7 +272,9 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) sprintf(mangled, "%s__%s_%s", name2, name1, f->func.name); free(f->func.name); f->func.name = mangled; - char *na = patch_self_args(f->func.args, name2); + + // Use full_target_name (Vec<T>) for self patching + char *na = patch_self_args(f->func.args, full_target_name); free(f->func.args); f->func.args = na; @@ -286,7 +313,8 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) sprintf(mangled, "%s__%s_%s", name2, name1, f->func.name); free(f->func.name); f->func.name = mangled; - char *na = patch_self_args(f->func.args, name2); + + char *na = patch_self_args(f->func.args, full_target_name); free(f->func.args); f->func.args = na; @@ -322,6 +350,16 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) lexer_next(l); } } + + if (target_gen_param) + { + free(full_target_name); + } + else + { + free(full_target_name); // It was strdup/ref. Wait, xstrdup needs free. + } + ctx->current_impl_struct = NULL; // Restore context ASTNode *n = ast_create(NODE_IMPL_TRAIT); n->impl_trait.trait_name = name1; @@ -331,11 +369,15 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) // If target struct is generic, register this impl as a template ASTNode *def = find_struct_def(ctx, name2); - if (def && ((def->type == NODE_STRUCT && def->strct.is_template) || - (def->type == NODE_ENUM && def->enm.is_template))) + if (target_gen_param || (def && ((def->type == NODE_STRUCT && def->strct.is_template) || + (def->type == NODE_ENUM && def->enm.is_template)))) { const char *gp = "T"; - if (def->type == NODE_STRUCT && def->strct.generic_param_count > 0) + if (target_gen_param) + { + gp = target_gen_param; + } + else if (def && def->type == NODE_STRUCT && def->strct.generic_param_count > 0) { gp = def->strct.generic_params[0]; } @@ -347,6 +389,10 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) { ctx->known_generics_count--; } + if (target_gen_param) + { + ctx->known_generics_count--; + } return n; } else @@ -935,8 +981,50 @@ ASTNode *parse_enum(ParserContext *ctx, Lexer *l) Type *payload = NULL; if (lexer_peek(l).type == TOK_LPAREN) { - lexer_next(l); - payload = parse_type_obj(ctx, l); + lexer_next(l); // eat ( + Type *first_t = parse_type_obj(ctx, l); + + if (lexer_peek(l).type == TOK_COMMA) + { + // Multi-arg variant -> Tuple + char sig[512]; + sig[0] = 0; + + char *s = type_to_string(first_t); + if (strlen(s) > 250) + { // Safety check + zpanic_at(lexer_peek(l), "Type name too long for tuple generation"); + } + strcpy(sig, s); + free(s); + + while (lexer_peek(l).type == TOK_COMMA) + { + lexer_next(l); // eat , + strcat(sig, "_"); + Type *next_t = parse_type_obj(ctx, l); + char *ns = type_to_string(next_t); + if (strlen(sig) + strlen(ns) + 2 > 510) + { + zpanic_at(lexer_peek(l), "Tuple signature too long"); + } + strcat(sig, ns); + free(ns); + } + + register_tuple(ctx, sig); + + char *tuple_name = xmalloc(strlen(sig) + 7); + sprintf(tuple_name, "Tuple_%s", sig); + + payload = type_new(TYPE_STRUCT); + payload->name = tuple_name; + } + else + { + payload = first_t; + } + if (lexer_next(l).type != TOK_RPAREN) { zpanic_at(lexer_peek(l), "Expected )"); @@ -953,6 +1041,24 @@ ASTNode *parse_enum(ParserContext *ctx, Lexer *l) sprintf(mangled, "%s_%s", ename, vname); register_enum_variant(ctx, ename, mangled, va->variant.tag_id); + // Register Constructor Function Signature + if (payload && !gp) // Only for non-generic enums for now + { + Type **at = xmalloc(sizeof(Type *)); + at[0] = payload; + Type *ret_t = type_new(TYPE_ENUM); + ret_t->name = xstrdup(ename); + + register_func(ctx, mangled, 1, NULL, at, ret_t, 0, 0, vt); + } + else if (!gp) + { + // No payload: fn Name() -> Enum + Type *ret_t = type_new(TYPE_ENUM); + ret_t->name = xstrdup(ename); + register_func(ctx, mangled, 0, NULL, NULL, ret_t, 0, 0, vt); + } + // Handle explicit assignment: Ok = 5 if (lexer_peek(l).type == TOK_OP && *lexer_peek(l).start == '=') { diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c index 5774571..0585baa 100644 --- a/src/parser/parser_type.c +++ b/src/parser/parser_type.c @@ -751,14 +751,31 @@ Type *parse_type_formal(ParserContext *ctx, Lexer *l) } } + Type *t = NULL; + // Example: fn(int, int) -> int if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0 && lexer_peek(l).len == 2) { lexer_next(l); // eat 'fn' + + int star_count = 0; + while (lexer_peek(l).type == TOK_OP && strncmp(lexer_peek(l).start, "*", 1) == 0) + { + lexer_next(l); + star_count++; + } + Type *fn_type = type_new(TYPE_FUNCTION); + fn_type->is_raw = (star_count > 0); fn_type->is_varargs = 0; + Type *wrapped = fn_type; + for (int i = 1; i < star_count; i++) + { + wrapped = type_new_ptr(wrapped); + } + expect(l, TOK_LPAREN, "Expected '(' for function type"); // Parse Arguments @@ -794,11 +811,13 @@ Type *parse_type_formal(ParserContext *ctx, Lexer *l) fn_type->inner = type_new(TYPE_VOID); } - return fn_type; + t = wrapped; + } + else + { + // Handles: int, Struct, Generic<T>, [Slice], (Tuple) + t = parse_type_base(ctx, l); } - - // Handles: int, Struct, Generic<T>, [Slice], (Tuple) - Type *t = parse_type_base(ctx, l); // Handles: T*, T**, etc. while (lexer_peek(l).type == TOK_OP && *lexer_peek(l).start == '*') diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c index ae5adcd..eec8faa 100644 --- a/src/parser/parser_utils.c +++ b/src/parser/parser_utils.c @@ -1624,7 +1624,7 @@ ASTNode *copy_ast_replacing(ASTNode *n, const char *p, const char *c, const char new_node->field.type = replace_type_str(n->field.type, p, c, os, ns); break; case NODE_EXPR_LITERAL: - if (n->literal.type_kind == 2) + if (n->literal.type_kind == LITERAL_STRING) { new_node->literal.string_val = xstrdup(n->literal.string_val); } @@ -2236,10 +2236,15 @@ char *process_fstring(ParserContext *ctx, const char *content, char ***used_syms // Codegen expression to temporary buffer char *code_buffer = NULL; size_t code_len = 0; - FILE *mem_stream = open_memstream(&code_buffer, &code_len); + FILE *mem_stream = tmpfile(); if (mem_stream) { codegen_expression(ctx, expr_node, mem_stream); + code_len = ftell(mem_stream); + code_buffer = xmalloc(code_len + 1); + fseek(mem_stream, 0, SEEK_SET); + fread(code_buffer, 1, code_len, mem_stream); + code_buffer[code_len] = 0; fclose(mem_stream); } |
