aboutsummaryrefslogtreecommitdiff
path: root/typecheck.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-05-14 13:30:46 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-05-14 13:30:46 -0400
commit1924f75647389003873c4532449484c65c83e79b (patch)
tree601018eb6a80e57e2dfb6623dd844812dd928394 /typecheck.c
parent31814db0a6e698e218121b12838f411358bf78a5 (diff)
Support corecursive structs
Diffstat (limited to 'typecheck.c')
-rw-r--r--typecheck.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/typecheck.c b/typecheck.c
index 87f7544c..139da0b6 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -127,12 +127,64 @@ static env_t *load_module(env_t *env, ast_t *use_ast)
if (!ast) errx(1, "Could not compile!");
for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) {
+ prebind_statement(module_env, stmt->ast);
+ }
+ for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) {
bind_statement(module_env, stmt->ast);
}
Table$str_set(env->imports, name, module_env);
return module_env;
}
+void prebind_statement(env_t *env, ast_t *statement)
+{
+ switch (statement->tag) {
+ case DocTest: {
+ prebind_statement(env, Match(statement, DocTest)->expr);
+ break;
+ }
+ case StructDef: {
+ auto def = Match(statement, StructDef);
+ if (get_binding(env, def->name))
+ code_err(statement, "A %T called '%s' has already been defined", get_binding(env, def->name)->type, def->name);
+
+ env_t *ns_env = namespace_env(env, def->name);
+ type_t *type = Type(StructType, .name=def->name, .opaque=true, .env=ns_env); // placeholder
+ Table$str_set(env->types, def->name, type);
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
+ prebind_statement(ns_env, stmt->ast);
+ }
+ break;
+ }
+ case EnumDef: {
+ auto def = Match(statement, EnumDef);
+ if (get_binding(env, def->name))
+ code_err(statement, "A %T called '%s' has already been defined", get_binding(env, def->name)->type, def->name);
+
+ env_t *ns_env = namespace_env(env, def->name);
+ type_t *type = Type(EnumType, .name=def->name, .opaque=true, .env=ns_env); // placeholder
+ Table$str_set(env->types, def->name, type);
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
+ prebind_statement(ns_env, stmt->ast);
+ }
+ break;
+ }
+ case LangDef: {
+ auto def = Match(statement, LangDef);
+ if (get_binding(env, def->name))
+ code_err(statement, "A %T called '%s' has already been defined", get_binding(env, def->name)->type, def->name);
+
+ env_t *ns_env = namespace_env(env, def->name);
+ type_t *type = Type(TextType, .lang=def->name, .env=ns_env);
+ Table$str_set(env->types, def->name, type);
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
+ prebind_statement(ns_env, stmt->ast);
+ break;
+ }
+ default: break;
+ }
+}
+
void bind_statement(env_t *env, ast_t *statement)
{
switch (statement->tag) {