summaryrefslogtreecommitdiff
path: root/src/parser
diff options
context:
space:
mode:
authorczjstmax <maxwasmailed@proton.me>2026-01-31 20:09:51 +0100
committerGitHub <noreply@github.com>2026-01-31 20:09:51 +0100
commit5f283b75488e89d2c4f261ae83e0424daec29554 (patch)
treeba1637d3885213095b312f81a477c33b1ebca6aa /src/parser
parentd2e2617dec584884b92eb452f377b20c0bf8f321 (diff)
parent13af49ba93d653fb6306604889c4ef66e9018873 (diff)
Merge branch 'z-libs:main' into main
Diffstat (limited to 'src/parser')
-rw-r--r--src/parser/parser_expr.c10
-rw-r--r--src/parser/parser_stmt.c114
-rw-r--r--src/parser/parser_struct.c115
3 files changed, 239 insertions, 0 deletions
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index 28dc465..7c53d96 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -5644,7 +5644,17 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
char *t1 = type_to_string(lhs->type_info);
char *t2 = type_to_string(rhs->type_info);
// Skip type check if either operand is void* (escape hatch type)
+ // or if either operand is a generic type parameter (T, K, V, etc.)
int skip_check = (strcmp(t1, "void*") == 0 || strcmp(t2, "void*") == 0);
+ if (lhs->type_info->kind == TYPE_GENERIC || rhs->type_info->kind == TYPE_GENERIC)
+ {
+ skip_check = 1;
+ }
+ // Also check if type name is a single uppercase letter (common generic param)
+ if ((strlen(t1) == 1 && isupper(t1[0])) || (strlen(t2) == 1 && isupper(t2[0])))
+ {
+ skip_check = 1;
+ }
// Allow comparing pointers/strings with integer literal 0 (NULL)
if (!skip_check)
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index 7758ae3..0677cf5 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -14,6 +14,118 @@
char *curr_func_ret = NULL;
char *run_comptime_block(ParserContext *ctx, Lexer *l);
+extern char *g_current_filename;
+
+/**
+ * @brief Auto-imports std/slice.zc if not already imported.
+ *
+ * This is called when array iteration is detected in for-in loops,
+ * to ensure the Slice<T>, SliceIter<T>, and Option<T> templates are available.
+ */
+static void auto_import_std_slice(ParserContext *ctx)
+{
+ // Check if already imported via templates
+ GenericTemplate *t = ctx->templates;
+ while (t)
+ {
+ if (strcmp(t->name, "Slice") == 0)
+ {
+ return; // Already have the Slice template
+ }
+ t = t->next;
+ }
+
+ // Try to find and import std/slice.zc
+ static const char *std_paths[] = {"std/slice.zc", "./std/slice.zc", NULL};
+ static const char *system_paths[] = {"/usr/local/share/zenc", "/usr/share/zenc", NULL};
+
+ char resolved_path[1024];
+ int found = 0;
+
+ // First, try relative to current file
+ if (g_current_filename)
+ {
+ char *current_dir = xstrdup(g_current_filename);
+ char *last_slash = strrchr(current_dir, '/');
+ if (last_slash)
+ {
+ *last_slash = 0;
+ snprintf(resolved_path, sizeof(resolved_path), "%s/std/slice.zc", current_dir);
+ if (access(resolved_path, R_OK) == 0)
+ {
+ found = 1;
+ }
+ }
+ free(current_dir);
+ }
+
+ // Try relative paths
+ if (!found)
+ {
+ for (int i = 0; std_paths[i] && !found; i++)
+ {
+ if (access(std_paths[i], R_OK) == 0)
+ {
+ strncpy(resolved_path, std_paths[i], sizeof(resolved_path) - 1);
+ resolved_path[sizeof(resolved_path) - 1] = '\0';
+ found = 1;
+ }
+ }
+ }
+
+ // Try system paths
+ if (!found)
+ {
+ for (int i = 0; system_paths[i] && !found; i++)
+ {
+ snprintf(resolved_path, sizeof(resolved_path), "%s/std/slice.zc", system_paths[i]);
+ if (access(resolved_path, R_OK) == 0)
+ {
+ found = 1;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return; // Could not find std/slice.zc, instantiate_generic will error
+ }
+
+ // Canonicalize path
+ char *real_fn = realpath(resolved_path, NULL);
+ if (real_fn)
+ {
+ strncpy(resolved_path, real_fn, sizeof(resolved_path) - 1);
+ resolved_path[sizeof(resolved_path) - 1] = '\0';
+ free(real_fn);
+ }
+
+ // Check if already imported
+ if (is_file_imported(ctx, resolved_path))
+ {
+ return;
+ }
+ mark_file_imported(ctx, resolved_path);
+
+ // Load and parse the file
+ char *src = load_file(resolved_path);
+ if (!src)
+ {
+ return; // Could not load file
+ }
+
+ Lexer i;
+ lexer_init(&i, src);
+
+ // Save and restore filename context
+ char *saved_fn = g_current_filename;
+ g_current_filename = resolved_path;
+
+ // Parse the slice module contents
+ parse_program_nodes(ctx, &i);
+
+ g_current_filename = saved_fn;
+}
static void check_assignment_condition(ASTNode *cond)
{
@@ -1193,6 +1305,8 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
// Manually trigger generic instantiation for Slice<T>
// This ensures that Slice_int, Slice_float, etc. structures are generated
+ // First, ensure std/slice.zc is imported (auto-import if needed)
+ auto_import_std_slice(ctx);
Token dummy_tok = {0};
instantiate_generic(ctx, "Slice", elem_type_str, elem_type_str, dummy_tok);
diff --git a/src/parser/parser_struct.c b/src/parser/parser_struct.c
index 109eeee..e53b56c 100644
--- a/src/parser/parser_struct.c
+++ b/src/parser/parser_struct.c
@@ -12,6 +12,114 @@
#include "zprep_plugin.h"
#include "../codegen/codegen.h"
+extern char *g_current_filename;
+
+/**
+ * @brief Auto-imports std/mem.zc if not already imported.
+ *
+ * This is called when the Drop trait is used (impl Drop for X).
+ */
+static void auto_import_std_mem(ParserContext *ctx)
+{
+ // Check if Drop trait is already registered (means mem.zc was imported)
+ if (check_impl(ctx, "Drop", "__trait_marker__"))
+ {
+ // Check_impl returns 0 if not found, but we need a different check
+ // Let's check if we can find any indicator that mem.zc was loaded
+ }
+
+ // Try to find and import std/mem.zc
+ static const char *std_paths[] = {"std/mem.zc", "./std/mem.zc", NULL};
+ static const char *system_paths[] = {"/usr/local/share/zenc", "/usr/share/zenc", NULL};
+
+ char resolved_path[1024];
+ int found = 0;
+
+ // First, try relative to current file
+ if (g_current_filename)
+ {
+ char *current_dir = xstrdup(g_current_filename);
+ char *last_slash = strrchr(current_dir, '/');
+ if (last_slash)
+ {
+ *last_slash = 0;
+ snprintf(resolved_path, sizeof(resolved_path), "%s/std/mem.zc", current_dir);
+ if (access(resolved_path, R_OK) == 0)
+ {
+ found = 1;
+ }
+ }
+ free(current_dir);
+ }
+
+ // Try relative paths
+ if (!found)
+ {
+ for (int i = 0; std_paths[i] && !found; i++)
+ {
+ if (access(std_paths[i], R_OK) == 0)
+ {
+ strncpy(resolved_path, std_paths[i], sizeof(resolved_path) - 1);
+ resolved_path[sizeof(resolved_path) - 1] = '\0';
+ found = 1;
+ }
+ }
+ }
+
+ // Try system paths
+ if (!found)
+ {
+ for (int i = 0; system_paths[i] && !found; i++)
+ {
+ snprintf(resolved_path, sizeof(resolved_path), "%s/std/mem.zc", system_paths[i]);
+ if (access(resolved_path, R_OK) == 0)
+ {
+ found = 1;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return; // Could not find std/mem.zc
+ }
+
+ // Canonicalize path
+ char *real_fn = realpath(resolved_path, NULL);
+ if (real_fn)
+ {
+ strncpy(resolved_path, real_fn, sizeof(resolved_path) - 1);
+ resolved_path[sizeof(resolved_path) - 1] = '\0';
+ free(real_fn);
+ }
+
+ // Check if already imported
+ if (is_file_imported(ctx, resolved_path))
+ {
+ return;
+ }
+ mark_file_imported(ctx, resolved_path);
+
+ // Load and parse the file
+ char *src = load_file(resolved_path);
+ if (!src)
+ {
+ return; // Could not load file
+ }
+
+ Lexer i;
+ lexer_init(&i, src);
+
+ // Save and restore filename context
+ char *saved_fn = g_current_filename;
+ g_current_filename = resolved_path;
+
+ // Parse the mem module contents
+ parse_program_nodes(ctx, &i);
+
+ g_current_filename = saved_fn;
+}
+
// Trait Parsing
ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
{
@@ -149,6 +257,7 @@ ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
}
register_trait(name);
+ add_to_global_list(ctx, n_node); // Track for codegen (VTable emission)
return n_node;
}
@@ -206,6 +315,12 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
register_generic(ctx, target_gen_param);
}
+ // Auto-import std/mem.zc if implementing Drop, Copy, or Clone traits
+ if (strcmp(name1, "Drop") == 0 || strcmp(name1, "Copy") == 0 || strcmp(name1, "Clone") == 0)
+ {
+ auto_import_std_mem(ctx);
+ }
+
register_impl(ctx, name1, name2);
// RAII: Check for "Drop" trait implementation