diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-03-19 14:22:03 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-03-19 14:22:03 -0400 |
| commit | adbb07fdc27af677923fb5453b845c7cd7b135a7 (patch) | |
| tree | 490caac013b97a49545487c956b8586b82ceeb9c | |
| parent | 7b444cd8249c933fb24e5195d9c511156f8b22f4 (diff) | |
Module imports
| -rw-r--r-- | builtins/files.c | 18 | ||||
| -rw-r--r-- | builtins/files.h | 2 | ||||
| -rw-r--r-- | compile.c | 43 | ||||
| -rw-r--r-- | compile.h | 2 | ||||
| -rw-r--r-- | environment.c | 1 | ||||
| -rw-r--r-- | environment.h | 2 | ||||
| -rw-r--r-- | parse.c | 2 | ||||
| -rw-r--r-- | tomo.c | 8 | ||||
| -rw-r--r-- | typecheck.c | 29 | ||||
| -rw-r--r-- | types.c | 5 | ||||
| -rw-r--r-- | types.h | 4 |
11 files changed, 89 insertions, 27 deletions
diff --git a/builtins/files.c b/builtins/files.c index 1622e0a0..ca917b9a 100644 --- a/builtins/files.c +++ b/builtins/files.c @@ -2,6 +2,7 @@ // files.c - Implementation of some file loading functionality. // +#include <ctype.h> #include <err.h> #include <fcntl.h> #include <gc.h> @@ -64,6 +65,23 @@ public char *resolve_path(const char *path, const char *relative_to, const char return NULL; } +public char *file_base_name(const char *path) +{ + const char *slash = strrchr(path, '/'); + if (slash) path = slash + 1; + assert(!isdigit(*path)); + const char *end = strchrnul(path, '.'); + size_t len = (size_t)(end - path); + char *buf = GC_MALLOC_ATOMIC(len+1); + strncpy(buf, path, len); + buf[len] = '\0'; + for (char *p = buf; *p; p++) { + if (!isalnum(*p)) + *p = '_'; + } + return buf; +} + static file_t *_load_file(const char* filename, FILE *file) { if (!file) return NULL; diff --git a/builtins/files.h b/builtins/files.h index 79dd48cd..1b490594 100644 --- a/builtins/files.h +++ b/builtins/files.h @@ -23,6 +23,8 @@ typedef struct { } file_t; char *resolve_path(const char *path, const char *relative_to, const char *system_path); +__attribute__((pure, nonnull)) +char *file_base_name(const char *path); __attribute__((nonnull)) file_t *load_file(const char *filename); __attribute__((nonnull, returns_nonnull)) @@ -244,10 +244,19 @@ CORD compile_statement(env_t *env, ast_t *ast) } case Declare: { auto decl = Match(ast, Declare); - type_t *t = get_type(env, decl->value); - if (t->tag == AbortType || t->tag == VoidType) - code_err(ast, "You can't declare a variable with a %T value", t); - return CORD_all(compile_declaration(env, t, Match(decl->var, Var)->name), " = ", compile(env, decl->value), ";"); + if (decl->value->tag == Use) { + auto use = Match(decl->value, Use); + const char *path = use->path; // TODO: make relative to current file! + env->code->imports = CORD_all(env->code->imports, "#include \"", path, ".h\"\n"); + env->code->object_files = CORD_all(env->code->object_files, "'", path, ".o' "); + const char *name = file_base_name(path); + return CORD_all(name, "$use();\n"); + } else { + type_t *t = get_type(env, decl->value); + if (t->tag == AbortType || t->tag == VoidType) + code_err(ast, "You can't declare a variable with a %T value", t); + return CORD_all(compile_declaration(env, t, Match(decl->var, Var)->name), " = ", compile(env, decl->value), ";"); + } } case Assign: { auto assign = Match(ast, Assign); @@ -1613,8 +1622,13 @@ CORD compile(env_t *env, ast_t *ast) } code_err(ast, "There is no '%s' field on tables", f->field); } + case ModuleType: { + const char *name = Match(value_t, ModuleType)->name; + env_t *module_env = Table_str_get(*env->imports, name); + return compile(module_env, WrapAST(ast, Var, f->field)); + } default: - code_err(ast, "Field accesses are only supported on struct and enum values"); + code_err(ast, "Field accesses are not supported on %T values", fielded_t); } } case Index: { @@ -1752,11 +1766,8 @@ module_code_t compile_file(ast_t *ast) { env_t *env = new_compilation_unit(); - const char *prefix = strrchr(ast->file->filename, '/'); - if (prefix) ++prefix; - else prefix = ast->file->filename; - prefix = heap_strf("%.*s$", strspn(prefix, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789"), prefix); - env->file_prefix = prefix; + const char *name = file_base_name(ast->file->filename); + env->file_prefix = heap_strf("%s$", name); CORD_appendf(&env->code->imports, "#include <tomo/tomo.h>\n"); @@ -1767,17 +1778,9 @@ module_code_t compile_file(ast_t *ast) CORD_appendf(&env->code->main, "%r\n", code); } - const char *slash = strrchr(ast->file->filename, '/'); - const char *name = slash ? slash+1 : ast->file->filename; - size_t name_len = 0; - while (name[name_len] && (isalnum(name[name_len]) || name[name_len] == '_')) - ++name_len; - if (name_len == 0) - errx(1, "No module name found for: %s", ast->file->filename); - const char *module_name = heap_strn(name, name_len); - return (module_code_t){ - .module_name=module_name, + .module_name=name, + .object_files=env->code->object_files, .header=CORD_all( // CORD_asprintf("#line 0 %r\n", Text__quoted(ast->file->filename, false)), env->code->imports, "\n", @@ -11,7 +11,7 @@ typedef struct { const char *module_name; - CORD header, c_file; + CORD header, c_file, object_files; } module_code_t; CORD expr_as_text(env_t *env, CORD expr, type_t *t, CORD color); diff --git a/environment.c b/environment.c index 38b21d23..af875e88 100644 --- a/environment.c +++ b/environment.c @@ -17,6 +17,7 @@ env_t *new_compilation_unit(void) env->type_namespaces = new(table_t); env->globals = new(table_t); env->locals = new(table_t, .fallback=env->globals); + env->imports = new(table_t); struct { const char *name; diff --git a/environment.h b/environment.h index dc94df23..43f6b0ff 100644 --- a/environment.h +++ b/environment.h @@ -16,6 +16,7 @@ typedef struct { CORD funcs; CORD typeinfos; CORD main; + CORD object_files; } compilation_unit_t; typedef struct { @@ -32,6 +33,7 @@ typedef struct loop_ctx_s { typedef struct { table_t *types, *globals, *locals; + table_t *imports; // Map of 'use' name -> env_t* table_t *type_namespaces; // Map of type name -> namespace table compilation_unit_t *code; fn_ctx_t *fn_ctx; @@ -1869,7 +1869,7 @@ PARSER(parse_use) { size_t path_len = strcspn(pos, " \t\r\n;"); if (path_len < 1) parser_err(ctx, start, pos, "There is no filename here to use"); - char *path = heap_strf("%.*s.nl", (int)path_len, pos); + char *path = heap_strf("%.*s.tm", (int)path_len, pos); pos += path_len; char *resolved_path = resolve_path(path, ctx->file->filename, getenv("USE_PATH")); if (!resolved_path) @@ -94,6 +94,8 @@ int main(int argc, char *argv[]) const char *cc = getenv("CC"); if (!cc) cc = "tcc"; + const char *object_files = CORD_to_const_char_star(module.object_files); + switch (mode) { case MODE_COMPILE: { FILE *prog = popen(heap_strf("%s > %s.h", autofmt, f->filename), "w"); @@ -123,8 +125,10 @@ int main(int argc, char *argv[]) return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE; } case MODE_RUN: { - const char *run = streq(cc, "tcc") ? heap_strf("%s | tcc -run %s %s %s -", autofmt, cflags, ldflags, ldlibs) - : heap_strf("%s | gcc -x c %s %s %s - -o program && ./program", autofmt, cflags, ldflags, ldlibs); + const char *run = streq(cc, "tcc") ? heap_strf("%s | tcc %s %s %s %s -run -", autofmt, cflags, ldflags, ldlibs, object_files) + : heap_strf("%s | gcc %s %s %s %s -x c - -o program && ./program", autofmt, cflags, ldflags, ldlibs, object_files); + if (verbose) + printf("%s\n", run); FILE *runner = popen(run, "w"); CORD program = CORD_all( diff --git a/typecheck.c b/typecheck.c index a48fa8ee..eacf4264 100644 --- a/typecheck.c +++ b/typecheck.c @@ -98,6 +98,7 @@ void bind_statement(env_t *env, ast_t *statement) } case Declare: { auto decl = Match(statement, Declare); + bind_statement(env, decl->value); type_t *type = get_type(env, decl->value); const char *name = Match(decl->var, Var)->name; CORD code = CORD_cat(env->scope_prefix, name); @@ -108,7 +109,7 @@ void bind_statement(env_t *env, ast_t *statement) auto def = Match(statement, FunctionDef); type_t *type = get_function_def_type(env, statement); const char *name = Match(def->name, Var)->name; - CORD code = CORD_all(env->scope_prefix, name); + CORD code = CORD_all(env->file_prefix, env->scope_prefix, name); set_binding(env, name, new(binding_t, .type=type, .code=code)); break; } @@ -204,6 +205,24 @@ void bind_statement(env_t *env, ast_t *statement) Table_str_set(env->globals, def->name, new(binding_t, .type=typeinfo_type)); break; } + case Use: { + auto use = Match(statement, Use); + const char *name = file_base_name(use->path); + env_t *module_env = new_compilation_unit(); + module_env->file_prefix = heap_strf("%s$", name); + + file_t *f = load_file(use->path); + if (!f) errx(1, "No such file: %s", use->path); + + ast_t *ast = parse_file(f, NULL); + if (!ast) errx(1, "Could not compile!"); + + 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); + break; + } default: break; } } @@ -392,7 +411,11 @@ type_t *get_type(env_t *env, ast_t *ast) case FieldAccess: { auto access = Match(ast, FieldAccess); type_t *fielded_t = get_type(env, access->fielded); - if (fielded_t->tag == TypeInfoType) { + if (fielded_t->tag == ModuleType) { + const char *name = Match(fielded_t, ModuleType)->name; + env_t *module_env = Table_str_get(*env->imports, name); + return get_type(module_env, WrapAST(ast, Var, access->field)); + } else if (fielded_t->tag == TypeInfoType) { auto info = Match(fielded_t, TypeInfoType); table_t *namespace = Table_str_get(*env->type_namespaces, info->name); if (!namespace) code_err(access->fielded, "I couldn't find a namespace for this type"); @@ -522,7 +545,7 @@ type_t *get_type(env_t *env, ast_t *ast) } case Use: { const char *path = Match(ast, Use)->path; - return Type(PointerType, .pointed=get_file_type(env, path)); + return Type(ModuleType, file_base_name(path)); } case Return: case Stop: case Skip: { return Type(AbortType); @@ -58,6 +58,9 @@ CORD type_to_cord(type_t *t) { case TypeInfoType: { return CORD_all("TypeInfo(", Match(t, TypeInfoType)->name, ")"); } + case ModuleType: { + return CORD_all("Module(", Match(t, ModuleType)->name, ")"); + } default: { raise(SIGABRT); return CORD_asprintf("Unknown type: %d", t->tag); @@ -410,6 +413,7 @@ size_t type_size(type_t *t) return size; } case TypeInfoType: return sizeof(TypeInfo); + case ModuleType: return 0; } errx(1, "This should not be reachable"); } @@ -445,6 +449,7 @@ size_t type_align(type_t *t) return align; } case TypeInfoType: return __alignof__(TypeInfo); + case ModuleType: return 0; } errx(1, "This should not be reachable"); } @@ -53,6 +53,7 @@ struct type_s { StructType, EnumType, TypeInfoType, + ModuleType, } tag; union { @@ -98,6 +99,9 @@ struct type_s { const char *name; type_t *type; } TypeInfoType; + struct { + const char *name; + } ModuleType; } __data; }; |
