summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.c79
-rw-r--r--src/ast/ast.h17
-rw-r--r--src/codegen/codegen.c180
-rw-r--r--src/codegen/codegen.h3
-rw-r--r--src/codegen/codegen_decl.c22
-rw-r--r--src/codegen/codegen_stmt.c249
-rw-r--r--src/codegen/codegen_utils.c178
-rw-r--r--src/main.c5
-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
-rw-r--r--src/zen/zen_facts.c4
-rw-r--r--src/zprep.h1
18 files changed, 1273 insertions, 278 deletions
diff --git a/src/ast/ast.c b/src/ast/ast.c
index 78d7efb..0799845 100644
--- a/src/ast/ast.c
+++ b/src/ast/ast.c
@@ -59,6 +59,8 @@ Type *type_new(TypeKind kind)
t->args = NULL;
t->arg_count = 0;
t->is_const = 0;
+ t->is_explicit_struct = 0;
+ t->is_raw = 0;
t->array_size = 0;
return t;
}
@@ -129,6 +131,11 @@ int type_eq(Type *a, Type *b)
return 1;
}
+ if (a->kind == TYPE_UNKNOWN || b->kind == TYPE_UNKNOWN)
+ {
+ return 1;
+ }
+
// Lax integer matching (bool == int, char == i8, etc.).
if (is_integer_type(a) && is_integer_type(b))
{
@@ -278,6 +285,36 @@ static char *type_to_string_impl(Type *t)
}
case TYPE_FUNCTION:
+ if (t->is_raw)
+ {
+ // fn*(Args)->Ret
+ char *ret = type_to_string(t->inner);
+ char *res = xmalloc(strlen(ret) + 64);
+ sprintf(res, "fn*(");
+
+ for (int i = 0; i < t->arg_count; i++)
+ {
+ if (i > 0)
+ {
+ char *tmp = xmalloc(strlen(res) + 3);
+ sprintf(tmp, "%s, ", res);
+ free(res);
+ res = tmp;
+ }
+ char *arg = type_to_string(t->args[i]);
+ char *tmp = xmalloc(strlen(res) + strlen(arg) + 1);
+ sprintf(tmp, "%s%s", res, arg);
+ free(res);
+ res = tmp;
+ free(arg);
+ }
+ char *tmp = xmalloc(strlen(res) + strlen(ret) + 5); // ) -> Ret
+ sprintf(tmp, "%s) -> %s", res, ret);
+ free(res);
+ res = tmp;
+ free(ret);
+ return res;
+ }
if (t->inner)
{
free(type_to_string(t->inner));
@@ -405,6 +442,19 @@ static char *type_to_c_string_impl(Type *t)
case TYPE_POINTER:
{
char *inner = type_to_c_string(t->inner);
+ char *ptr_token = strstr(inner, "(*");
+ if (ptr_token)
+ {
+ long prefix_len = ptr_token - inner + 2; // "void (*"
+ char *res = xmalloc(strlen(inner) + 2);
+ strncpy(res, inner, prefix_len);
+ res[prefix_len] = 0;
+ strcat(res, "*");
+ strcat(res, ptr_token + 2);
+ free(inner);
+ return res;
+ }
+
if (t->is_restrict)
{
char *res = xmalloc(strlen(inner) + 16);
@@ -436,6 +486,35 @@ static char *type_to_c_string_impl(Type *t)
}
case TYPE_FUNCTION:
+ if (t->is_raw)
+ {
+ char *ret = type_to_c_string(t->inner);
+ char *res = xmalloc(strlen(ret) + 64); // heuristic start buffer
+ sprintf(res, "%s (*)(", ret);
+
+ for (int i = 0; i < t->arg_count; i++)
+ {
+ if (i > 0)
+ {
+ char *tmp = xmalloc(strlen(res) + 3);
+ sprintf(tmp, "%s, ", res);
+ free(res);
+ res = tmp;
+ }
+ char *arg = type_to_c_string(t->args[i]);
+ char *tmp = xmalloc(strlen(res) + strlen(arg) + 1);
+ sprintf(tmp, "%s%s", res, arg);
+ free(res);
+ res = tmp;
+ free(arg);
+ }
+ char *tmp = xmalloc(strlen(res) + 2);
+ sprintf(tmp, "%s)", res);
+ free(res);
+ res = tmp;
+ free(ret);
+ return res;
+ }
if (t->inner)
{
free(type_to_c_string(t->inner));
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 6ef5d7a..12d8f2b 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -11,6 +11,15 @@ typedef struct ASTNode ASTNode;
// ** Formal Type System **
// Used for Generics, Type Inference, and robust pointer handling.
+
+typedef enum
+{
+ LITERAL_INT = 0,
+ LITERAL_FLOAT = 1,
+ LITERAL_STRING = 2,
+ LITERAL_CHAR = 3
+} LiteralKind;
+
typedef enum
{
TYPE_VOID,
@@ -55,6 +64,7 @@ typedef struct Type
int arg_count;
int is_const;
int is_explicit_struct; // for example, "struct Foo" vs "Foo"
+ int is_raw; // Raw function pointer (fn*)
union
{
int array_size; // For fixed-size arrays [T; N].
@@ -306,9 +316,10 @@ struct ASTNode
struct
{
char *pattern;
- char *binding_name;
+ char **binding_names; // Multiple bindings
+ int binding_count; // Count
+ int *binding_refs; // Ref flags per binding
int is_destructuring;
- int is_ref; // New: Supports 'ref' binding (Some(ref x))
ASTNode *guard;
ASTNode *body;
int is_default;
@@ -329,7 +340,7 @@ struct ASTNode
struct
{
- int type_kind;
+ LiteralKind type_kind;
unsigned long long int_val;
double float_val;
char *string_val;
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c
index 706d613..7c58943 100644
--- a/src/codegen/codegen.c
+++ b/src/codegen/codegen.c
@@ -14,19 +14,19 @@
// Emit literal expression (int, float, string, char)
static void codegen_literal_expr(ASTNode *node, FILE *out)
{
- if (node->literal.type_kind == TOK_STRING)
+ if (node->literal.type_kind == LITERAL_STRING)
{
fprintf(out, "\"%s\"", node->literal.string_val);
}
- else if (node->literal.type_kind == TOK_CHAR)
+ else if (node->literal.type_kind == LITERAL_CHAR)
{
fprintf(out, "%s", node->literal.string_val);
}
- else if (node->literal.type_kind == 1) // float
+ else if (node->literal.type_kind == LITERAL_FLOAT)
{
fprintf(out, "%f", node->literal.float_val);
}
- else // int
+ else // LITERAL_INT
{
if (node->literal.int_val > 9223372036854775807ULL)
{
@@ -34,7 +34,7 @@ static void codegen_literal_expr(ASTNode *node, FILE *out)
}
else
{
- fprintf(out, "%llu", (unsigned long long)node->literal.int_val);
+ fprintf(out, "%lld", (long long)node->literal.int_val);
}
}
}
@@ -56,7 +56,7 @@ static void codegen_var_expr(ParserContext *ctx, ASTNode *node, FILE *out)
if (node->resolved_type && strcmp(node->resolved_type, "unknown") == 0)
{
- if (node->var_ref.suggestion)
+ if (node->var_ref.suggestion && !ctx->silent_warnings)
{
char msg[256];
sprintf(msg, "Undefined variable '%s'", node->var_ref.name);
@@ -289,9 +289,22 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
else
{
fprintf(out, "(");
- codegen_expression(ctx, node->binary.left, out);
+ int is_assignment =
+ (node->binary.op[strlen(node->binary.op) - 1] == '=' &&
+ strcmp(node->binary.op, "==") != 0 && strcmp(node->binary.op, "!=") != 0 &&
+ strcmp(node->binary.op, "<=") != 0 && strcmp(node->binary.op, ">=") != 0);
+
+ if (is_assignment)
+ {
+ codegen_expression(ctx, node->binary.left, out);
+ }
+ else
+ {
+ codegen_expression_with_move(ctx, node->binary.left, out);
+ }
+
fprintf(out, " %s ", node->binary.op);
- codegen_expression(ctx, node->binary.right, out);
+ codegen_expression_with_move(ctx, node->binary.right, out);
fprintf(out, ")");
}
break;
@@ -328,6 +341,61 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
}
+ // Check for Static Enum Variant Call: Enum.Variant(...)
+ if (target->type == NODE_EXPR_VAR)
+ {
+ ASTNode *def = find_struct_def(ctx, target->var_ref.name);
+ if (def && def->type == NODE_ENUM)
+ {
+ char mangled[256];
+ sprintf(mangled, "%s_%s", target->var_ref.name, method);
+ FuncSig *sig = find_func(ctx, mangled);
+ if (sig)
+ {
+ fprintf(out, "%s(", mangled);
+ ASTNode *arg = node->call.args;
+ int arg_idx = 0;
+ while (arg)
+ {
+ if (arg_idx > 0 && arg)
+ {
+ fprintf(out, ", ");
+ }
+
+ Type *param_t =
+ (arg_idx < sig->total_args) ? sig->arg_types[arg_idx] : NULL;
+
+ // Tuple Packing Logic
+ if (param_t && param_t->kind == TYPE_STRUCT &&
+ strncmp(param_t->name, "Tuple_", 6) == 0 && sig->total_args == 1 &&
+ node->call.arg_count > 1)
+ {
+ fprintf(out, "(%s){", param_t->name);
+ int first = 1;
+ while (arg)
+ {
+ if (!first)
+ {
+ fprintf(out, ", ");
+ }
+ first = 0;
+ codegen_expression(ctx, arg, out);
+ arg = arg->next;
+ }
+ fprintf(out, "}");
+ break; // All args consumed
+ }
+
+ codegen_expression(ctx, arg, out);
+ arg = arg->next;
+ arg_idx++;
+ }
+ fprintf(out, ")");
+ return;
+ }
+ }
+ }
+
char *type = infer_type(ctx, target);
if (type)
{
@@ -353,7 +421,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
while (arg)
{
fprintf(out, ", ");
- codegen_expression(ctx, arg, out);
+ codegen_expression_with_move(ctx, arg, out);
arg = arg->next;
}
fprintf(out, "); })");
@@ -396,6 +464,32 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
ref = ref->next;
}
+ if (!resolved_method_suffix)
+ {
+ GenericImplTemplate *it = ctx->impl_templates;
+ while (it)
+ {
+ 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 trait_mangled[512];
+ sprintf(trait_mangled, "%s__%s_%s", base, tname, method);
+ if (find_func(ctx, trait_mangled))
+ {
+ char *suffix = xmalloc(strlen(tname) + strlen(method) + 2);
+ sprintf(suffix, "%s_%s", tname, method);
+ resolved_method_suffix = suffix;
+ break;
+ }
+ }
+ it = it->next;
+ }
+ }
+
if (resolved_method_suffix)
{
method = resolved_method_suffix;
@@ -436,7 +530,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
while (arg)
{
fprintf(out, ", ");
- codegen_expression(ctx, arg, out);
+ codegen_expression_with_move(ctx, arg, out);
arg = arg->next;
}
fprintf(out, ")");
@@ -455,7 +549,8 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
}
- if (node->call.callee->type_info && node->call.callee->type_info->kind == TYPE_FUNCTION)
+ if (node->call.callee->type_info && node->call.callee->type_info->kind == TYPE_FUNCTION &&
+ !node->call.callee->type_info->is_raw)
{
fprintf(out, "({ z_closure_T _c = ");
codegen_expression(ctx, node->call.callee, out);
@@ -486,7 +581,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
while (arg)
{
fprintf(out, ", ");
- codegen_expression(ctx, arg, out);
+ codegen_expression_with_move(ctx, arg, out);
arg = arg->next;
}
fprintf(out, "); })");
@@ -528,7 +623,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
fprintf(out, ", ");
}
first = 0;
- codegen_expression(ctx, arg, out);
+ codegen_expression_with_move(ctx, arg, out);
arg = arg->next;
}
}
@@ -561,18 +656,55 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
free(inner);
handled = 1;
}
+ else if (param_t && param_t->kind == TYPE_STRUCT &&
+ strncmp(param_t->name, "Tuple_", 6) == 0 && sig->total_args == 1 &&
+ node->call.arg_count > 1)
+ {
+ // Implicit Tuple Packing:
+ // Function expects 1 Tuple argument, but call has multiple args -> Pack
+ // them
+ fprintf(out, "(%s){", param_t->name);
+
+ ASTNode *curr = arg;
+ int first_field = 1;
+ while (curr)
+ {
+ if (!first_field)
+ {
+ fprintf(out, ", ");
+ }
+ first_field = 0;
+ codegen_expression_with_move(ctx, curr, out);
+ curr = curr->next;
+ }
+ fprintf(out, "}");
+ handled = 1;
+
+ // Advance main loop iterator to end
+ arg = NULL;
+ }
}
- if (!handled)
+ if (handled)
{
- codegen_expression(ctx, arg, out);
+ if (arg == NULL)
+ {
+ break; // Tuple packed all args
+ }
+ }
+ else
+ {
+ codegen_expression_with_move(ctx, arg, out);
}
- if (arg->next)
+ if (arg && arg->next)
{
fprintf(out, ", ");
}
- arg = arg->next;
+ if (arg)
+ {
+ arg = arg->next;
+ }
arg_idx++;
}
}
@@ -1033,6 +1165,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
int is_zen_struct = 0;
+ int is_union = 0;
StructRef *sr = ctx->parsed_structs_list;
while (sr)
{
@@ -1040,6 +1173,10 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
strcmp(sr->node->strct.name, struct_name) == 0)
{
is_zen_struct = 1;
+ if (sr->node->strct.is_union)
+ {
+ is_union = 1;
+ }
break;
}
sr = sr->next;
@@ -1047,7 +1184,14 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
if (is_zen_struct)
{
- fprintf(out, "(struct %s){", struct_name);
+ if (is_union)
+ {
+ fprintf(out, "(union %s){", struct_name);
+ }
+ else
+ {
+ fprintf(out, "(struct %s){", struct_name);
+ }
}
else
{
diff --git a/src/codegen/codegen.h b/src/codegen/codegen.h
index d27356a..942de41 100644
--- a/src/codegen/codegen.h
+++ b/src/codegen/codegen.h
@@ -26,6 +26,9 @@ void emit_auto_type(ParserContext *ctx, ASTNode *init_expr, Token t, FILE *out);
char *codegen_type_to_string(Type *t);
void emit_func_signature(FILE *out, ASTNode *func, const char *name_override);
char *strip_template_suffix(const char *name);
+char *strip_template_suffix(const char *name);
+int emit_move_invalidation(ParserContext *ctx, ASTNode *node, FILE *out);
+void codegen_expression_with_move(ParserContext *ctx, ASTNode *node, FILE *out);
// Declaration emission (codegen_decl.c).
void emit_preamble(ParserContext *ctx, FILE *out);
diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c
index 18d81f5..d525963 100644
--- a/src/codegen/codegen_decl.c
+++ b/src/codegen/codegen_decl.c
@@ -953,7 +953,20 @@ void emit_impl_vtables(ParserContext *ctx, FILE *out)
ASTNode *m = node->impl_trait.methods;
while (m)
{
- const char *orig = parse_original_method_name(m->func.name);
+ // Calculate expected prefix: Struct__Trait_
+ char prefix[256];
+ sprintf(prefix, "%s__%s_", strct, trait);
+ const char *orig = m->func.name;
+ if (strncmp(orig, prefix, strlen(prefix)) == 0)
+ {
+ orig += strlen(prefix);
+ }
+ else
+ {
+ // Fallback if mangling schema differs (shouldn't happen)
+ orig = parse_original_method_name(m->func.name);
+ }
+
fprintf(out, ".%s = (__typeof__(((%s_VTable*)0)->%s))%s__%s_%s", orig, trait, orig,
strct, trait, orig);
if (m->next)
@@ -978,7 +991,14 @@ int emit_tests_and_runner(ParserContext *ctx, ASTNode *node, FILE *out)
if (cur->type == NODE_TEST)
{
fprintf(out, "static void _z_test_%d() {\n", test_count);
+ int saved = defer_count;
codegen_walker(ctx, cur->test_stmt.body, out);
+ // Run defers
+ for (int i = defer_count - 1; i >= saved; i--)
+ {
+ codegen_node_single(ctx, defer_stack[i], out);
+ }
+ defer_count = saved;
fprintf(out, "}\n");
test_count++;
}
diff --git a/src/codegen/codegen_stmt.c b/src/codegen/codegen_stmt.c
index 54c6a14..ff8ea46 100644
--- a/src/codegen/codegen_stmt.c
+++ b/src/codegen/codegen_stmt.c
@@ -177,9 +177,19 @@ void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, int us
ASTNode *ref_check = node->match_stmt.cases;
while (ref_check)
{
- if (ref_check->match_case.is_ref)
+ if (ref_check->match_case.binding_refs)
+ {
+ for (int i = 0; i < ref_check->match_case.binding_count; i++)
+ {
+ if (ref_check->match_case.binding_refs[i])
+ {
+ has_ref_binding = 1;
+ break;
+ }
+ }
+ }
+ if (has_ref_binding)
{
- has_ref_binding = 1;
break;
}
ref_check = ref_check->next;
@@ -325,157 +335,131 @@ void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, int us
emit_pattern_condition(ctx, c->match_case.pattern, id, has_ref_binding, out);
}
fprintf(out, ") { ");
- if (c->match_case.binding_name)
+ if (c->match_case.binding_count > 0)
{
- if (is_option)
+ for (int i = 0; i < c->match_case.binding_count; i++)
{
- if (strstr(g_config.cc, "tcc"))
+ char *bname = c->match_case.binding_names[i];
+ int is_r = c->match_case.binding_refs ? c->match_case.binding_refs[i] : 0;
+
+ if (is_option)
{
- if (c->match_case.is_ref)
+ if (strstr(g_config.cc, "tcc"))
{
- fprintf(out, "__typeof__(&_m_%d.val) %s = &_m_%d.val; ", id,
- c->match_case.binding_name, id);
+ if (is_r)
+ {
+ fprintf(out, "__typeof__(&_m_%d.val) %s = &_m_%d.val; ", id, bname, id);
+ }
+ else
+ {
+ fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id, bname, id);
+ }
}
else
{
- fprintf(out, "__typeof__(_m_%d.val) %s = _m_%d.val; ", id,
- c->match_case.binding_name, id);
+ if (is_r)
+ {
+ fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", bname, id);
+ }
+ else if (has_ref_binding)
+ {
+ fprintf(out, "ZC_AUTO %s = _m_%d->val; ", bname, id);
+ }
+ else
+ {
+ fprintf(out, "ZC_AUTO %s = _m_%d.val; ", bname, id);
+ }
}
}
- else
+ else if (is_result)
{
- if (c->match_case.is_ref)
- {
- // _m is pointer when has_ref_binding, use ->
- fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", c->match_case.binding_name, id);
- }
- else if (has_ref_binding)
+ char *field = "val";
+ if (strcmp(c->match_case.pattern, "Err") == 0)
{
- // _m is pointer, use -> but don't take address
- fprintf(out, "ZC_AUTO %s = _m_%d->val; ", c->match_case.binding_name, id);
+ field = "err";
}
- else
- {
- // _m is value, use .
- fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name, id);
- }
- }
- }
- else if (is_result) // FIX: Changed 'if' to 'else if' to match original logic structure
- // if needed, but original code had implicit fallthrough checks? No,
- // checks match pattern.
- {
- if (strcmp(c->match_case.pattern, "Ok") == 0)
- {
+
if (strstr(g_config.cc, "tcc"))
{
- if (c->match_case.is_ref)
+ if (is_r)
{
- fprintf(out, "__typeof__(&_m_%d->val) %s = &_m_%d->val; ", id,
- c->match_case.binding_name, id);
+ fprintf(out, "__typeof__(&_m_%d->%s) %s = &_m_%d->%s; ", id, field,
+ bname, id, field);
}
else
{
- fprintf(out, "__typeof__(_m_%d->val) %s = _m_%d->val; ", id,
- c->match_case.binding_name, id);
+ fprintf(out, "__typeof__(_m_%d->%s) %s = _m_%d->%s; ", id, field, bname,
+ id, field);
}
}
else
{
- if (c->match_case.is_ref)
+ if (is_r)
{
- // _m is pointer when has_ref_binding, use ->
- fprintf(out, "ZC_AUTO %s = &_m_%d->val; ", c->match_case.binding_name,
- id);
+ fprintf(out, "ZC_AUTO %s = &_m_%d->%s; ", bname, id, field);
}
else if (has_ref_binding)
{
- // _m is pointer, use -> but don't take address
- fprintf(out, "ZC_AUTO %s = _m_%d->val; ", c->match_case.binding_name,
- id);
+ fprintf(out, "ZC_AUTO %s = _m_%d->%s; ", bname, id, field);
}
else
{
- // _m is value, use .
- fprintf(out, "ZC_AUTO %s = _m_%d.val; ", c->match_case.binding_name,
- id);
+ fprintf(out, "ZC_AUTO %s = _m_%d.%s; ", bname, id, field);
}
}
}
else
{
- if (strstr(g_config.cc, "tcc"))
+ char *v = strrchr(c->match_case.pattern, '_');
+ if (v)
{
- if (c->match_case.is_ref)
+ v++;
+ }
+ else
+ {
+ v = c->match_case.pattern;
+ }
+
+ if (c->match_case.binding_count > 1)
+ {
+ // Tuple destructuring: data.Variant.vI
+ if (is_r)
+ {
+ fprintf(out, "ZC_AUTO %s = &_m_%d->data.%s.v%d; ", bname, id, v, i);
+ }
+ else if (has_ref_binding)
{
- fprintf(out, "__typeof__(&_m_%d->err) %s = &_m_%d->err; ", id,
- c->match_case.binding_name, id);
+ fprintf(out, "ZC_AUTO %s = _m_%d->data.%s.v%d; ", bname, id, v, i);
}
else
{
- fprintf(out, "__typeof__(_m_%d->err) %s = _m_%d->err; ", id,
- c->match_case.binding_name, id);
+ fprintf(out, "ZC_AUTO %s = _m_%d.data.%s.v%d; ", bname, id, v, i);
}
}
else
{
- if (c->match_case.is_ref)
+ // Single destructuring: data.Variant
+ if (is_r)
{
- // _m is pointer when has_ref_binding, use ->
- fprintf(out, "ZC_AUTO %s = &_m_%d->err; ", c->match_case.binding_name,
- id);
+ fprintf(out, "ZC_AUTO %s = &_m_%d->data.%s; ", bname, id, v);
}
else if (has_ref_binding)
{
- // _m is pointer, use -> but don't take address
- fprintf(out, "ZC_AUTO %s = _m_%d->err; ", c->match_case.binding_name,
- id);
+ fprintf(out, "ZC_AUTO %s = _m_%d->data.%s; ", bname, id, v);
}
else
{
- // _m is value, use .
- fprintf(out, "ZC_AUTO %s = _m_%d.err; ", c->match_case.binding_name,
- id);
+ fprintf(out, "ZC_AUTO %s = _m_%d.data.%s; ", bname, id, v);
}
}
}
}
- else
- {
- char *f = strrchr(c->match_case.pattern, '_');
- if (f)
- {
- f++;
- }
- else
- {
- f = c->match_case.pattern;
- }
- // Generic struct destructuring (for example, MyStruct_Variant)
- // Assuming data union or accessible field.
- if (c->match_case.is_ref)
- {
- // _m is pointer when has_ref_binding, use ->
- fprintf(out, "ZC_AUTO %s = &_m_%d->data.%s; ", c->match_case.binding_name, id,
- f);
- }
- else if (has_ref_binding)
- {
- // _m is pointer, use -> but don't take address
- fprintf(out, "ZC_AUTO %s = _m_%d->data.%s; ", c->match_case.binding_name, id,
- f);
- }
- else
- {
- // _m is value, use .
- fprintf(out, "ZC_AUTO %s = _m_%d.data.%s; ", c->match_case.binding_name, id, f);
- }
- }
}
// Check if body is a string literal (should auto-print).
ASTNode *body = c->match_case.body;
- int is_string_literal = (body->type == NODE_EXPR_LITERAL && body->literal.type_kind == 2);
+ int is_string_literal =
+ (body->type == NODE_EXPR_LITERAL && body->literal.type_kind == LITERAL_STRING);
if (is_expr)
{
@@ -514,9 +498,10 @@ void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, int us
{
if (is_string_literal)
{
- fprintf(out, "({ printf(\"%%s\", ");
- codegen_expression(ctx, body, out);
- fprintf(out, "); printf(\"\\n\"); 0; })");
+ char *inner = body->literal.string_val;
+ char *code = process_printf_sugar(ctx, inner, 1, "stdout", NULL, NULL, 0);
+ fprintf(out, "%s;", code);
+ free(code);
}
else
{
@@ -902,9 +887,27 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
ASTNode *def = find_struct_def(ctx, clean_type);
- if (def && def->type_info && def->type_info->traits.has_drop)
+ int has_drop = (def && def->type_info && def->type_info->traits.has_drop);
+
+ if (has_drop)
{
- fprintf(out, "__attribute__((cleanup(%s__Drop_glue))) ", clean_type);
+ // Drop Flag: int __z_drop_flag_name = 1;
+ fprintf(out, "int __z_drop_flag_%s = 1; ", node->var_decl.name);
+
+ // Synthesize Defer: if (__z_drop_flag_name) Name__Drop_drop(&name);
+ ASTNode *defer_node = xmalloc(sizeof(ASTNode));
+ defer_node->type = NODE_RAW_STMT;
+ char *stmt_str =
+ xmalloc(256 + strlen(node->var_decl.name) * 2 + strlen(clean_type));
+ sprintf(stmt_str, "if (__z_drop_flag_%s) %s__Drop_glue(&%s);",
+ node->var_decl.name, clean_type, node->var_decl.name);
+ defer_node->raw_stmt.content = stmt_str;
+ defer_node->line = node->line;
+
+ if (defer_count < MAX_DEFER)
+ {
+ defer_stack[defer_count++] = defer_node;
+ }
}
// Emit Variable with Type
@@ -917,6 +920,11 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
codegen_expression(ctx, node->var_decl.init_expr, out);
}
fprintf(out, ";\n");
+ if (node->var_decl.init_expr &&
+ emit_move_invalidation(ctx, node->var_decl.init_expr, out))
+ {
+ fprintf(out, ";\n");
+ }
if (node->type_info)
{
@@ -941,9 +949,29 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
ASTNode *def = find_struct_def(ctx, clean_type);
- if (def && def->type_info && def->type_info->traits.has_drop)
+ int has_drop = (def && def->type_info && def->type_info->traits.has_drop);
+
+ if (has_drop)
{
- fprintf(out, "__attribute__((cleanup(%s__Drop_glue))) ", clean_type);
+ // Drop Flag: int __z_drop_flag_name = 1;
+ fprintf(out, "int __z_drop_flag_%s = 1; ", node->var_decl.name);
+
+ // Synthesize Defer: if (__z_drop_flag_name) Name__Drop_drop(&name);
+ ASTNode *defer_node = xmalloc(sizeof(ASTNode));
+ defer_node->type = NODE_RAW_STMT;
+ // Build string
+ char *stmt_str =
+ xmalloc(256 + strlen(node->var_decl.name) * 2 + strlen(clean_type));
+ sprintf(stmt_str, "if (__z_drop_flag_%s) %s__Drop_glue(&%s);",
+ node->var_decl.name, clean_type, node->var_decl.name);
+ defer_node->raw_stmt.content = stmt_str;
+ defer_node->line = node->line;
+
+ // Push to defer stack
+ if (defer_count < MAX_DEFER)
+ {
+ defer_stack[defer_count++] = defer_node;
+ }
}
emit_var_decl_type(ctx, out, inferred, node->var_decl.name);
@@ -951,6 +979,12 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
fprintf(out, " = ");
codegen_expression(ctx, node->var_decl.init_expr, out);
fprintf(out, ";\n");
+
+ if (node->var_decl.init_expr &&
+ emit_move_invalidation(ctx, node->var_decl.init_expr, out))
+ {
+ fprintf(out, ";\n");
+ }
}
else
{
@@ -965,6 +999,11 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
fprintf(out, " = ");
codegen_expression(ctx, node->var_decl.init_expr, out);
fprintf(out, ";\n");
+ if (node->var_decl.init_expr &&
+ emit_move_invalidation(ctx, node->var_decl.init_expr, out))
+ {
+ fprintf(out, ";\n");
+ }
}
}
}
@@ -1475,6 +1514,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
case NODE_REPL_PRINT:
{
+ // Safe block for printing
fprintf(out, "{ ");
emit_auto_type(ctx, node->repl_print.expr, node->token, out);
fprintf(out, " _zval = (");
@@ -1576,7 +1616,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
case NODE_EXPR_LITERAL:
// String literal statement should auto-print
- if (node->literal.type_kind == 2 || node->literal.type_kind == TOK_STRING)
+ if (node->literal.type_kind == LITERAL_STRING)
{
fprintf(out, " printf(\"%%s\\n\", ");
codegen_expression(ctx, node, out);
@@ -1653,6 +1693,9 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
fprintf(out, ");\n");
break;
}
+ case NODE_RAW_STMT:
+ fprintf(out, " %s\n", node->raw_stmt.content);
+ break;
default:
codegen_expression(ctx, node, out);
fprintf(out, ";\n");
diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c
index fe580bf..6283bce 100644
--- a/src/codegen/codegen_utils.c
+++ b/src/codegen/codegen_utils.c
@@ -40,19 +40,33 @@ char *strip_template_suffix(const char *name)
return xstrdup(name);
}
-// Helper to emit variable declarations with array types.
-void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name)
+// Helper to emit C declaration (handle arrays, function pointers correctly)
+void emit_c_decl(FILE *out, const char *type_str, const char *name)
{
- (void)ctx;
-
char *bracket = strchr(type_str, '[');
char *generic = strchr(type_str, '<');
+ char *fn_ptr = strstr(type_str, "(*");
- if (generic && (!bracket || generic < bracket))
+ if (fn_ptr)
+ {
+ char *end_paren = strchr(fn_ptr, ')');
+ if (end_paren)
+ {
+ int prefix_len = end_paren - type_str;
+ fprintf(out, "%.*s%s%s", prefix_len, type_str, name, end_paren);
+ }
+ else
+ {
+ // Fallback if malformed (shouldn't happen)
+ int prefix_len = fn_ptr - type_str + 2;
+ fprintf(out, "%.*s%s%s", prefix_len, type_str, name, fn_ptr + 2);
+ }
+ }
+ else if (generic && (!bracket || generic < bracket))
{
// Strip generic part for C output
int base_len = generic - type_str;
- fprintf(out, "%.*s %s", base_len, type_str, var_name);
+ fprintf(out, "%.*s %s", base_len, type_str, name);
if (bracket)
{
@@ -62,14 +76,21 @@ void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, con
else if (bracket)
{
int base_len = bracket - type_str;
- fprintf(out, "%.*s %s%s", base_len, type_str, var_name, bracket);
+ fprintf(out, "%.*s %s%s", base_len, type_str, name, bracket);
}
else
{
- fprintf(out, "%s %s", type_str, var_name);
+ fprintf(out, "%s %s", type_str, name);
}
}
+// Helper to emit variable declarations with array types.
+void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name)
+{
+ (void)ctx;
+ emit_c_decl(out, type_str, var_name);
+}
+
// Find struct definition
ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name)
{
@@ -455,15 +476,15 @@ char *infer_type(ParserContext *ctx, ASTNode *node)
if (node->type == NODE_EXPR_LITERAL)
{
- if (node->literal.type_kind == TOK_STRING)
+ if (node->literal.type_kind == LITERAL_STRING)
{
- return "string";
+ return xstrdup("string");
}
- if (node->literal.type_kind == TOK_CHAR)
+ if (node->literal.type_kind == LITERAL_CHAR)
{
- return "char";
+ return xstrdup("char");
}
- if (node->literal.type_kind == 1)
+ if (node->literal.type_kind == LITERAL_FLOAT)
{
return "double";
}
@@ -519,8 +540,22 @@ char *extract_call_args(const char *args)
// Parse original method name from mangled name.
const char *parse_original_method_name(const char *mangled)
{
- const char *last = strrchr(mangled, '_');
- return last ? last + 1 : mangled;
+ const char *sep = strstr(mangled, "__");
+ if (!sep)
+ {
+ return mangled;
+ }
+
+ // Let's iterate to find the last `__`.
+ const char *last_double = NULL;
+ const char *p = mangled;
+ while ((p = strstr(p, "__")))
+ {
+ last_double = p;
+ p += 2;
+ }
+
+ return last_double ? last_double + 2 : mangled;
}
// Replace string type in arguments.
@@ -635,7 +670,20 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override)
ret_str = xstrdup("void");
}
- fprintf(out, "%s %s(", ret_str, name_override ? name_override : func->func.name);
+ char *ret_suffix = NULL;
+ char *fn_ptr = strstr(ret_str, "(*)");
+
+ if (fn_ptr)
+ {
+ int prefix_len = fn_ptr - ret_str + 2; // Include "(*"
+ fprintf(out, "%.*s%s(", prefix_len, ret_str,
+ name_override ? name_override : func->func.name);
+ ret_suffix = fn_ptr + 2;
+ }
+ else
+ {
+ fprintf(out, "%s %s(", ret_str, name_override ? name_override : func->func.name);
+ }
free(ret_str);
// Args
@@ -669,16 +717,7 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override)
}
// check if array type
- char *bracket = strchr(type_str, '[');
- if (bracket)
- {
- int base_len = bracket - type_str;
- fprintf(out, "%.*s %s%s", base_len, type_str, name, bracket);
- }
- else
- {
- fprintf(out, "%s %s", type_str, name);
- }
+ emit_c_decl(out, type_str, name);
free(type_str);
}
if (func->func.is_varargs)
@@ -691,4 +730,91 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override)
}
}
fprintf(out, ")");
+
+ if (ret_suffix)
+ {
+ fprintf(out, "%s", ret_suffix);
+ }
+}
+
+// Invalidate a moved-from variable by zeroing it out to prevent double-free
+int emit_move_invalidation(ParserContext *ctx, ASTNode *node, FILE *out)
+{
+ if (!node)
+ {
+ return 0;
+ }
+
+ // Check if it's a valid l-value we can memset
+ if (node->type != NODE_EXPR_VAR && node->type != NODE_EXPR_MEMBER)
+ {
+ return 0;
+ }
+
+ // Common logic to find type and check Drop
+ char *type_name = infer_type(ctx, node);
+ ASTNode *def = NULL;
+ if (type_name)
+ {
+ char *clean_type = type_name;
+ if (strncmp(clean_type, "struct ", 7) == 0)
+ {
+ clean_type += 7;
+ }
+ def = find_struct_def(ctx, clean_type);
+ }
+
+ if (def && def->type_info && def->type_info->traits.has_drop)
+ {
+ if (node->type == NODE_EXPR_VAR)
+ {
+ fprintf(out, "__z_drop_flag_%s = 0; ", node->var_ref.name);
+ fprintf(out, "memset(&%s, 0, sizeof(%s))", node->var_ref.name, node->var_ref.name);
+ return 1;
+ }
+ else if (node->type == NODE_EXPR_MEMBER)
+ {
+ // For members: memset(&foo.bar, 0, sizeof(foo.bar))
+ fprintf(out, "memset(&");
+ codegen_expression(ctx, node, out);
+ fprintf(out, ", 0, sizeof(");
+ codegen_expression(ctx, node, out);
+ fprintf(out, "))");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// Emits expression, wrapping it in a move-invalidation block if it's a consuming variable usage
+void codegen_expression_with_move(ParserContext *ctx, ASTNode *node, FILE *out)
+{
+ if (node && (node->type == NODE_EXPR_VAR || node->type == NODE_EXPR_MEMBER))
+ {
+ // Re-use infer logic to see if we need invalidation
+ char *type_name = infer_type(ctx, node);
+ ASTNode *def = NULL;
+ if (type_name)
+ {
+ char *clean_type = type_name;
+ if (strncmp(clean_type, "struct ", 7) == 0)
+ {
+ clean_type += 7;
+ }
+ def = find_struct_def(ctx, clean_type);
+ }
+
+ if (def && def->type_info && def->type_info->traits.has_drop)
+ {
+ fprintf(out, "({ __typeof__(");
+ codegen_expression(ctx, node, out);
+ fprintf(out, ") _mv = ");
+ codegen_expression(ctx, node, out);
+ fprintf(out, "; ");
+ emit_move_invalidation(ctx, node, out);
+ fprintf(out, "; _mv; })");
+ return;
+ }
+ }
+ codegen_expression(ctx, node, out);
}
diff --git a/src/main.c b/src/main.c
index 17cbdf6..3f6a51f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -47,6 +47,7 @@ void print_usage()
printf(" -g Debug info\n");
printf(" -v, --verbose Verbose output\n");
printf(" -q, --quiet Quiet output\n");
+ printf(" --no-zen Disable Zen facts\n");
printf(" -c Compile only (produce .o)\n");
printf(" --cpp Use C++ mode.\n");
printf(" --cuda Use CUDA mode (requires nvcc).\n");
@@ -145,6 +146,10 @@ int main(int argc, char **argv)
{
g_config.quiet = 1;
}
+ else if (strcmp(arg, "--no-zen") == 0)
+ {
+ g_config.no_zen = 1;
+ }
else if (strcmp(arg, "--freestanding") == 0)
{
g_config.is_freestanding = 1;
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);
}
diff --git a/src/zen/zen_facts.c b/src/zen/zen_facts.c
index a86e0cb..0e542b4 100644
--- a/src/zen/zen_facts.c
+++ b/src/zen/zen_facts.c
@@ -406,7 +406,7 @@ void zzen_at(Token t, const char *msg, const char *url)
int zen_trigger_at(ZenTrigger t, Token location)
{
- if (g_config.quiet)
+ if (g_config.quiet || g_config.no_zen)
{
return 0;
}
@@ -457,7 +457,7 @@ int zen_trigger_at(ZenTrigger t, Token location)
void zen_trigger_global(void)
{
- if (g_config.quiet)
+ if (g_config.quiet || g_config.no_zen)
{
return;
}
diff --git a/src/zprep.h b/src/zprep.h
index 03c17fc..ea38927 100644
--- a/src/zprep.h
+++ b/src/zprep.h
@@ -179,6 +179,7 @@ typedef struct
int emit_c; // 1 if --emit-c (keep C file).
int verbose; // 1 if --verbose.
int quiet; // 1 if --quiet.
+ int no_zen; // 1 if --no-zen (disable zen facts).
int repl_mode; // 1 if --repl (internal flag for REPL usage).
int is_freestanding; // 1 if --freestanding.
int mode_transpile; // 1 if 'transpile' command.