summaryrefslogtreecommitdiff
path: root/src/parser
diff options
context:
space:
mode:
authoriryuken <eshwarsajja20@gmail.com>2026-01-25 23:29:00 +0530
committerGitHub <noreply@github.com>2026-01-25 23:29:00 +0530
commit1c4a6e1cf58503499b1c8245c1d15bd70efe0048 (patch)
tree71b952ad455bf17d5bdea01472f0e2297f25eabe /src/parser
parent863118c95caac0d69a35f6ae4d2e83844734a8a1 (diff)
parentebc8b94baa6bc694cb4829e2eb2934a1f17fa6a1 (diff)
Merge pull request
fix merge conflicts and #105
Diffstat (limited to 'src/parser')
-rw-r--r--src/parser/parser.h5
-rw-r--r--src/parser/parser_core.c8
-rw-r--r--src/parser/parser_decl.c38
-rw-r--r--src/parser/parser_expr.c365
-rw-r--r--src/parser/parser_stmt.c241
-rw-r--r--src/parser/parser_struct.c120
-rw-r--r--src/parser/parser_type.c27
-rw-r--r--src/parser/parser_utils.c9
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);
}