Skip to content

Commit 8a3bd91

Browse files
gh-121: Fix module aliasing.
1 parent d72c3af commit 8a3bd91

3 files changed

Lines changed: 66 additions & 8 deletions

File tree

src/builtins.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6245,16 +6245,33 @@ static Value builtin_export(Interpreter* interp, Value* args, int argc, Expr** a
62456245
RUNTIME_ERROR(interp, "EXPORT failed to assign into module", line, col);
62466246
}
62476247

6248-
// Also create qualified name in caller env: module.symbol
6249-
size_t len = strlen(module) + 1 + strlen(sym) + 1;
6250-
char* qualified = malloc(len);
6251-
if (!qualified) RUNTIME_ERROR(interp, "Out of memory", line, col);
6252-
snprintf(qualified, len, "%s.%s", module, sym);
6253-
if (!env_assign(env, qualified, entry->value, entry->decl_type, true)) {
6248+
/* Materialize qualified bindings for every registered alias that
6249+
references the same module environment. This ensures EXPORT updates
6250+
sibling aliases that point at the same module (per spec). */
6251+
size_t alias_count = 0;
6252+
char** aliases = module_list_aliases(interp, mod_env, &alias_count);
6253+
if (aliases) {
6254+
for (size_t ai = 0; ai < alias_count; ai++) {
6255+
if (module_export_bindings(interp, env, mod_env, aliases[ai], line, col, "EXPORT failed to assign qualified name") != 0) {
6256+
for (size_t j = 0; j < alias_count; j++) free(aliases[j]);
6257+
free(aliases);
6258+
RUNTIME_ERROR(interp, "EXPORT failed to assign qualified name", line, col);
6259+
}
6260+
free(aliases[ai]);
6261+
}
6262+
free(aliases);
6263+
} else {
6264+
/* Fallback to previous behavior if alias enumeration fails */
6265+
size_t len = strlen(module) + 1 + strlen(sym) + 1;
6266+
char* qualified = malloc(len);
6267+
if (!qualified) RUNTIME_ERROR(interp, "Out of memory", line, col);
6268+
snprintf(qualified, len, "%s.%s", module, sym);
6269+
if (!env_assign(env, qualified, entry->value, entry->decl_type, true)) {
6270+
free(qualified);
6271+
RUNTIME_ERROR(interp, "EXPORT failed to assign qualified name", line, col);
6272+
}
62546273
free(qualified);
6255-
RUNTIME_ERROR(interp, "EXPORT failed to assign qualified name", line, col);
62566274
}
6257-
free(qualified);
62586275

62596276
return value_bool(false);
62606277
}
@@ -7487,6 +7504,12 @@ static Value builtin_import(Interpreter* interp, Value* args, int argc, Expr** a
74877504
if (found_path && strcmp(found_path, cache_key) != 0) {
74887505
(void)module_register_alias(interp, found_path, mod_env);
74897506
}
7507+
/* Also register the caller-provided alias (if different) so callers can
7508+
refer to the module by that identifier. IMPORT_PATH does this earlier;
7509+
ensure builtin IMPORT behaves the same. */
7510+
if (alias && strcmp(alias, cache_key) != 0) {
7511+
(void)module_register_alias(interp, alias, mod_env);
7512+
}
74907513

74917514
EnvEntry* scope_entry = env_get_entry(mod_env, "__MODULE_SCOPE__");
74927515
if (!scope_entry || !scope_entry->initialized || scope_entry->value.type != VAL_STR) {

src/interpreter.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,37 @@ Env* module_env_lookup(Interpreter* interp, const char* name) {
724724
return NULL;
725725
}
726726

727+
char** module_list_aliases(Interpreter* interp, Env* env, size_t* out_count) {
728+
if (out_count) *out_count = 0;
729+
if (!interp || !env) return NULL;
730+
size_t count = 0;
731+
ModuleEntry* e = interp->modules;
732+
while (e) {
733+
if (e->env == env) count++;
734+
e = e->next;
735+
}
736+
if (count == 0) return NULL;
737+
char** arr = malloc(sizeof(char*) * count);
738+
if (!arr) return NULL;
739+
e = interp->modules;
740+
size_t idx = 0;
741+
while (e) {
742+
if (e->env == env) {
743+
arr[idx] = strdup(e->name);
744+
if (!arr[idx]) {
745+
for (size_t j = 0; j < idx; j++) free(arr[j]);
746+
free(arr);
747+
if (out_count) *out_count = 0;
748+
return NULL;
749+
}
750+
idx++;
751+
}
752+
e = e->next;
753+
}
754+
if (out_count) *out_count = idx;
755+
return arr;
756+
}
757+
727758
// ============ Value truthiness ============
728759

729760
int value_truthiness(Value v) {

src/interpreter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,9 @@ int module_register(Interpreter* interp, const char* name);
150150
int module_register_alias(Interpreter* interp, const char* name, Env* env);
151151
// Lookup a module's Env by name; returns NULL if not found.
152152
Env* module_env_lookup(Interpreter* interp, const char* name);
153+
// Return a newly-allocated array of alias names (caller must free each string
154+
// and the returned array) for the given module Env. `out_count` receives the
155+
// number of aliases. Returns NULL when there are no aliases or on error.
156+
char** module_list_aliases(Interpreter* interp, Env* env, size_t* out_count);
153157

154158
#endif // INTERPRETER_H

0 commit comments

Comments
 (0)