aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-03-19 14:22:03 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-03-19 14:22:03 -0400
commitadbb07fdc27af677923fb5453b845c7cd7b135a7 (patch)
tree490caac013b97a49545487c956b8586b82ceeb9c
parent7b444cd8249c933fb24e5195d9c511156f8b22f4 (diff)
Module imports
-rw-r--r--builtins/files.c18
-rw-r--r--builtins/files.h2
-rw-r--r--compile.c43
-rw-r--r--compile.h2
-rw-r--r--environment.c1
-rw-r--r--environment.h2
-rw-r--r--parse.c2
-rw-r--r--tomo.c8
-rw-r--r--typecheck.c29
-rw-r--r--types.c5
-rw-r--r--types.h4
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))
diff --git a/compile.c b/compile.c
index f7664519..5eb5e7cf 100644
--- a/compile.c
+++ b/compile.c
@@ -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",
diff --git a/compile.h b/compile.h
index 49e41fbc..6be4a997 100644
--- a/compile.h
+++ b/compile.h
@@ -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;
diff --git a/parse.c b/parse.c
index c39532c9..426f5cae 100644
--- a/parse.c
+++ b/parse.c
@@ -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)
diff --git a/tomo.c b/tomo.c
index a6e2f63e..f19c4abe 100644
--- a/tomo.c
+++ b/tomo.c
@@ -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);
diff --git a/types.c b/types.c
index e37a3b90..4bc7e85b 100644
--- a/types.c
+++ b/types.c
@@ -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");
}
diff --git a/types.h b/types.h
index d502b726..17c778fa 100644
--- a/types.h
+++ b/types.h
@@ -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;
};