diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-04-01 15:15:28 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-04-01 15:15:28 -0400 |
| commit | d888bec4095170d159c488292ba098b243c0a44e (patch) | |
| tree | 0d0ff7c2e2c4ed75519ee32ec6482e04b1e68b3d /src | |
| parent | 354ed77535d17f2fc71780f1aaeb7ebfb80307d4 (diff) | |
Clean up and improve patterns
Diffstat (limited to 'src')
| -rw-r--r-- | src/compile.c | 28 | ||||
| -rw-r--r-- | src/typecheck.c | 36 |
2 files changed, 52 insertions, 12 deletions
diff --git a/src/compile.c b/src/compile.c index 2cc20f39..43b9ef1e 100644 --- a/src/compile.c +++ b/src/compile.c @@ -4200,8 +4200,12 @@ CORD compile_top_level_code(env_t *env, ast_t *ast) case Extend: { auto extend = Match(ast, Extend); env_t *ns_env = namespace_env(env, extend->name); - ns_env->libname = env->libname; - return compile_top_level_code(ns_env, extend->body); + env_t *extended = new(env_t); + *extended = *ns_env; + extended->locals = new(Table_t, .fallback=env->locals); + extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings); + extended->libname = env->libname; + return compile_top_level_code(extended, extend->body); } case Extern: return CORD_EMPTY; case Block: { @@ -4358,30 +4362,38 @@ CORD compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast) CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast) { - const char *ns_name = NULL; + env_t *ns_env = NULL; ast_t *block = NULL; switch (ast->tag) { case LangDef: { auto def = Match(ast, LangDef); - ns_name = def->name; + ns_env = namespace_env(env, def->name); block = def->namespace; break; } case Extend: { auto extend = Match(ast, Extend); - ns_name = extend->name; + ns_env = namespace_env(env, extend->name); + + env_t *extended = new(env_t); + *extended = *ns_env; + extended->locals = new(Table_t, .fallback=env->locals); + extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings); + extended->libname = env->libname; + ns_env = extended; + block = extend->body; break; } case StructDef: { auto def = Match(ast, StructDef); - ns_name = def->name; + ns_env = namespace_env(env, def->name); block = def->namespace; break; } case EnumDef: { auto def = Match(ast, EnumDef); - ns_name = def->name; + ns_env = namespace_env(env, def->name); block = def->namespace; break; } @@ -4465,7 +4477,7 @@ CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *a } default: return CORD_EMPTY; } - env_t *ns_env = namespace_env(env, ns_name); + assert(ns_env); CORD header = CORD_EMPTY; for (ast_list_t *stmt = block ? Match(block, Block)->statements : NULL; stmt; stmt = stmt->next) { header = CORD_all(header, compile_statement_namespace_header(ns_env, header_path, stmt->ast)); diff --git a/src/typecheck.c b/src/typecheck.c index ff609435..648ffbc8 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -274,9 +274,23 @@ void prebind_statement(env_t *env, ast_t *statement) case Extend: { auto extend = Match(statement, Extend); env_t *ns_env = namespace_env(env, extend->name); - ns_env->libname = env->libname; + env_t *extended = new(env_t); + *extended = *ns_env; + extended->locals = new(Table_t, .fallback=env->locals); + extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings); + extended->libname = env->libname; for (ast_list_t *stmt = extend->body ? Match(extend->body, Block)->statements : NULL; stmt; stmt = stmt->next) - prebind_statement(ns_env, stmt->ast); + prebind_statement(extended, stmt->ast); + Array_t new_bindings = extended->locals->entries; + for (int64_t i = 0; i < new_bindings.length; i++) { + struct { const char *name; binding_t *binding; } *entry = new_bindings.data + i*new_bindings.stride; + binding_t *clobbered = Table$str_get(*ns_env->locals, entry->name); + if (clobbered && !type_eq(clobbered->type, entry->binding->type)) + code_err(statement, "This `extend` block overwrites the binding for ", quoted(entry->name), + " in the original namespace (with type ", type_to_str(clobbered->type), ") with a new binding with type ", + type_to_str(entry->binding->type)); + Table$str_set(ns_env->locals, entry->name, entry->binding); + } break; } default: break; @@ -448,9 +462,23 @@ void bind_statement(env_t *env, ast_t *statement) case Extend: { auto extend = Match(statement, Extend); env_t *ns_env = namespace_env(env, extend->name); - ns_env->libname = env->libname; + env_t *extended = new(env_t); + *extended = *ns_env; + extended->locals = new(Table_t, .fallback=env->locals); + extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings); + extended->libname = env->libname; for (ast_list_t *stmt = extend->body ? Match(extend->body, Block)->statements : NULL; stmt; stmt = stmt->next) - bind_statement(ns_env, stmt->ast); + bind_statement(extended, stmt->ast); + Array_t new_bindings = extended->locals->entries; + for (int64_t i = 0; i < new_bindings.length; i++) { + struct { const char *name; binding_t *binding; } *entry = new_bindings.data + i*new_bindings.stride; + binding_t *clobbered = Table$str_get(*ns_env->locals, entry->name); + if (clobbered && !type_eq(clobbered->type, entry->binding->type)) + code_err(statement, "This `extend` block overwrites the binding for ", quoted(entry->name), + " in the original namespace (with type ", type_to_str(clobbered->type), ") with a new binding with type ", + type_to_str(entry->binding->type)); + Table$str_set(ns_env->locals, entry->name, entry->binding); + } break; } case Use: { |
