aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-08-24 17:13:48 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-08-24 17:13:48 -0400
commit2245c883680ccfbe545f230d6b68c38ce54bceb6 (patch)
tree2a861d7482bcf0f30c07483e6adc287f83e8090a
parent476bacc27671de92e8fdbc5b2a904bbf8bc80377 (diff)
Shift some code around.
-rw-r--r--src/compile.c272
-rw-r--r--src/compile.h4
-rw-r--r--src/compile/files.c274
-rw-r--r--src/compile/files.h3
-rw-r--r--src/compile/statements.c7
-rw-r--r--src/compile/statements.h1
-rw-r--r--src/compile/types.c5
7 files changed, 282 insertions, 284 deletions
diff --git a/src/compile.c b/src/compile.c
index 6cecc10a..6e53acb4 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -1,7 +1,5 @@
// Compilation logic
#include <gc.h>
-#include <glob.h>
-#include <gmp.h>
#include <stdio.h>
#include <uninorm.h>
@@ -23,10 +21,7 @@
#include "compile/types.h"
#include "config.h"
#include "environment.h"
-#include "modules.h"
-#include "naming.h"
#include "stdlib/integers.h"
-#include "stdlib/paths.h"
#include "stdlib/tables.h"
#include "stdlib/text.h"
#include "stdlib/util.h"
@@ -35,13 +30,6 @@
static Text_t compile_unsigned_type(type_t *t);
public
-Text_t with_source_info(env_t *env, ast_t *ast, Text_t code) {
- if (code.length == 0 || !ast || !ast->file || !env->do_source_mapping) return code;
- int64_t line = get_line_number(ast->file, ast->start);
- return Texts("\n#line ", String(line), "\n", code);
-}
-
-public
Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t) {
if (is_idempotent(ast) && can_be_mutated(env, ast)) {
if (t->tag == ListType) return Texts("LIST_COPY(", compile_to_type(env, ast, t), ")");
@@ -1184,264 +1172,4 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c
return code;
}
-Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast) {
- switch (ast->tag) {
- case Use: {
- DeclareMatch(use, ast, Use);
- Path_t source_path = Path$from_str(ast->file->filename);
- Path_t source_dir = Path$parent(source_path);
- Path_t build_dir = Path$resolved(Path$parent(header_path), Path$current_dir());
- switch (use->what) {
- case USE_MODULE: {
- module_info_t mod = get_module_info(ast);
- glob_t tm_files;
- const char *folder = mod.version ? String(mod.name, "_", mod.version) : mod.name;
- if (glob(String(TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE,
- NULL, &tm_files)
- != 0) {
- if (!try_install_module(mod)) code_err(ast, "Could not find library");
- }
-
- Text_t includes = EMPTY_TEXT;
- for (size_t i = 0; i < tm_files.gl_pathc; i++) {
- const char *filename = tm_files.gl_pathv[i];
- Path_t tm_file = Path$from_str(filename);
- Path_t lib_build_dir = Path$sibling(tm_file, Text(".build"));
- Path_t header = Path$child(lib_build_dir, Texts(Path$base_name(tm_file), Text(".h")));
- includes = Texts(includes, "#include \"", Path$as_c_string(header), "\"\n");
- }
- globfree(&tm_files);
- return with_source_info(env, ast, includes);
- }
- case USE_LOCAL: {
- Path_t used_path = Path$resolved(Path$from_str(use->path), source_dir);
- Path_t used_build_dir = Path$sibling(used_path, Text(".build"));
- Path_t used_header_path = Path$child(used_build_dir, Texts(Path$base_name(used_path), Text(".h")));
- return Texts("#include \"", Path$as_c_string(Path$relative_to(used_header_path, build_dir)), "\"\n");
- }
- case USE_HEADER:
- if (use->path[0] == '<') {
- return Texts("#include ", use->path, "\n");
- } else {
- Path_t used_path = Path$resolved(Path$from_str(use->path), source_dir);
- return Texts("#include \"", Path$as_c_string(Path$relative_to(used_path, build_dir)), "\"\n");
- }
- default: return EMPTY_TEXT;
- }
- }
- case StructDef: {
- return compile_struct_header(env, ast);
- }
- case EnumDef: {
- return compile_enum_header(env, ast);
- }
- case LangDef: {
- DeclareMatch(def, ast, LangDef);
- return Texts(
- // Constructor macro:
- "#define ", namespace_name(env, env->namespace, Text$from_str(def->name)), "(text) ((",
- namespace_name(env, env->namespace, Texts(def->name, "$$type")),
- "){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" "
- "text})\n"
- "#define ",
- namespace_name(env, env->namespace, Text$from_str(def->name)), "s(...) ((",
- namespace_name(env, env->namespace, Texts(def->name, "$$type")),
- ")Texts(__VA_ARGS__))\n"
- "extern const TypeInfo_t ",
- namespace_name(env, env->namespace, Texts(def->name, Text("$$info"))), ";\n");
- }
- case Extend: {
- return EMPTY_TEXT;
- }
- default: return EMPTY_TEXT;
- }
-}
-
-Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast) {
- env_t *ns_env = NULL;
- ast_t *block = NULL;
- switch (ast->tag) {
- case LangDef: {
- DeclareMatch(def, ast, LangDef);
- ns_env = namespace_env(env, def->name);
- block = def->namespace;
- break;
- }
- case Extend: {
- DeclareMatch(extend, ast, Extend);
- 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->id_suffix = env->id_suffix;
- ns_env = extended;
-
- block = extend->body;
- break;
- }
- case StructDef: {
- DeclareMatch(def, ast, StructDef);
- ns_env = namespace_env(env, def->name);
- block = def->namespace;
- break;
- }
- case EnumDef: {
- DeclareMatch(def, ast, EnumDef);
- ns_env = namespace_env(env, def->name);
- block = def->namespace;
- break;
- }
- case Extern: {
- DeclareMatch(ext, ast, Extern);
- type_t *t = parse_type_ast(env, ext->type);
- Text_t decl;
- if (t->tag == ClosureType) {
- t = Match(t, ClosureType)->fn;
- DeclareMatch(fn, t, FunctionType);
- decl = Texts(compile_type(fn->ret), " ", ext->name, "(");
- for (arg_t *arg = fn->args; arg; arg = arg->next) {
- decl = Texts(decl, compile_type(arg->type));
- if (arg->next) decl = Texts(decl, ", ");
- }
- decl = Texts(decl, ")");
- } else {
- decl = compile_declaration(t, Text$from_str(ext->name));
- }
- return Texts("extern ", decl, ";\n");
- }
- case Declare: {
- DeclareMatch(decl, ast, Declare);
- const char *decl_name = Match(decl->var, Var)->name;
- bool is_private = (decl_name[0] == '_');
- if (is_private) return EMPTY_TEXT;
-
- type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
- if (t->tag == FunctionType) t = Type(ClosureType, t);
- assert(t->tag != ModuleType);
- if (t->tag == AbortType || t->tag == VoidType || t->tag == ReturnType)
- code_err(ast, "You can't declare a variable with a ", type_to_str(t), " value");
-
- return Texts(decl->value ? compile_statement_type_header(env, header_path, decl->value) : EMPTY_TEXT, "extern ",
- compile_declaration(t, namespace_name(env, env->namespace, Text$from_str(decl_name))), ";\n");
- }
- case FunctionDef: {
- DeclareMatch(fndef, ast, FunctionDef);
- const char *decl_name = Match(fndef->name, Var)->name;
- bool is_private = decl_name[0] == '_';
- if (is_private) return EMPTY_TEXT;
- Text_t arg_signature = Text("(");
- for (arg_ast_t *arg = fndef->args; arg; arg = arg->next) {
- type_t *arg_type = get_arg_ast_type(env, arg);
- arg_signature = Texts(arg_signature, compile_declaration(arg_type, Texts("_$", arg->name)));
- if (arg->next) arg_signature = Texts(arg_signature, ", ");
- }
- arg_signature = Texts(arg_signature, ")");
-
- type_t *ret_t = fndef->ret_type ? parse_type_ast(env, fndef->ret_type) : Type(VoidType);
- Text_t ret_type_code = compile_type(ret_t);
- if (ret_t->tag == AbortType) ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code);
- Text_t name = namespace_name(env, env->namespace, Text$from_str(decl_name));
- if (env->namespace && env->namespace->parent && env->namespace->name && streq(decl_name, env->namespace->name))
- name = namespace_name(env, env->namespace, Text$from_str(String(get_line_number(ast->file, ast->start))));
- return Texts(ret_type_code, " ", name, arg_signature, ";\n");
- }
- case ConvertDef: {
- DeclareMatch(def, ast, ConvertDef);
-
- Text_t arg_signature = Text("(");
- for (arg_ast_t *arg = def->args; arg; arg = arg->next) {
- type_t *arg_type = get_arg_ast_type(env, arg);
- arg_signature = Texts(arg_signature, compile_declaration(arg_type, Texts("_$", arg->name)));
- if (arg->next) arg_signature = Texts(arg_signature, ", ");
- }
- arg_signature = Texts(arg_signature, ")");
-
- type_t *ret_t = def->ret_type ? parse_type_ast(env, def->ret_type) : Type(VoidType);
- Text_t ret_type_code = compile_type(ret_t);
- Text_t name = Text$from_str(get_type_name(ret_t));
- if (name.length == 0)
- code_err(ast,
- "Conversions are only supported for text, struct, and enum "
- "types, not ",
- type_to_str(ret_t));
- Text_t name_code =
- namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start))));
- return Texts(ret_type_code, " ", name_code, arg_signature, ";\n");
- }
- default: return EMPTY_TEXT;
- }
- assert(ns_env);
- Text_t header = EMPTY_TEXT;
- for (ast_list_t *stmt = block ? Match(block, Block)->statements : NULL; stmt; stmt = stmt->next) {
- header = Texts(header, compile_statement_namespace_header(ns_env, header_path, stmt->ast));
- }
- return header;
-}
-
-typedef struct {
- env_t *env;
- Text_t *header;
- Path_t header_path;
-} compile_typedef_info_t;
-
-static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast) {
- if (ast->tag == StructDef) {
- DeclareMatch(def, ast, StructDef);
- if (def->external) return;
- Text_t struct_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$struct"));
- Text_t type_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type"));
- *info->header = Texts(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n");
- } else if (ast->tag == EnumDef) {
- DeclareMatch(def, ast, EnumDef);
- bool has_any_tags_with_fields = false;
- for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
- has_any_tags_with_fields = has_any_tags_with_fields || (tag->fields != NULL);
- }
-
- if (has_any_tags_with_fields) {
- Text_t struct_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$struct"));
- Text_t type_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type"));
- *info->header = Texts(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n");
-
- for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
- if (!tag->fields) continue;
- Text_t tag_struct =
- namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$struct"));
- Text_t tag_type =
- namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$type"));
- *info->header = Texts(*info->header, "typedef struct ", tag_struct, " ", tag_type, ";\n");
- }
- } else {
- Text_t enum_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$enum"));
- Text_t type_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type"));
- *info->header = Texts(*info->header, "typedef enum ", enum_name, " ", type_name, ";\n");
- }
- } else if (ast->tag == LangDef) {
- DeclareMatch(def, ast, LangDef);
- *info->header = Texts(*info->header, "typedef Text_t ",
- namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type")), ";\n");
- }
-}
-
-static void _define_types_and_funcs(compile_typedef_info_t *info, ast_t *ast) {
- *info->header = Texts(*info->header, compile_statement_type_header(info->env, info->header_path, ast),
- compile_statement_namespace_header(info->env, info->header_path, ast));
-}
-
-Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast) {
- Text_t header =
- Texts("#pragma once\n",
- env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT,
- "#include <tomo_" TOMO_VERSION "/tomo.h>\n");
-
- compile_typedef_info_t info = {.env = env, .header = &header, .header_path = header_path};
- visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn = (void *)_make_typedefs, &info});
- visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn = (void *)_define_types_and_funcs, &info});
-
- header = Texts(header, "void ", namespace_name(env, env->namespace, Text("$initialize")), "(void);\n");
- return header;
-}
-
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/compile.h b/src/compile.h
index e0447e2e..361acbb6 100644
--- a/src/compile.h
+++ b/src/compile.h
@@ -11,9 +11,5 @@ Text_t compile(env_t *env, ast_t *ast);
Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version);
Text_t compile_empty(type_t *t);
Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t);
-Text_t compile_namespace_header(env_t *env, const char *ns_name, ast_t *block);
-Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast);
-Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast);
-Text_t with_source_info(env_t *env, ast_t *ast, Text_t code);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/compile/files.c b/src/compile/files.c
index d9f4052a..9a4ff434 100644
--- a/src/compile/files.c
+++ b/src/compile/files.c
@@ -1,6 +1,10 @@
+#include <glob.h>
+
#include "../ast.h"
#include "../compile.h"
+#include "../config.h"
#include "../environment.h"
+#include "../modules.h"
#include "../naming.h"
#include "../stdlib/datatypes.h"
#include "../stdlib/paths.h"
@@ -10,15 +14,13 @@
#include "../types.h"
#include "assignments.h"
#include "enums.h"
+#include "files.h"
#include "functions.h"
#include "statements.h"
#include "structs.h"
+#include "text.h"
#include "types.h"
-static Text_t quoted_str(const char *str) { return Text$quoted(Text$from_str(str), false, Text("\"")); }
-
-static inline Text_t quoted_text(Text_t text) { return Text$quoted(text, false, Text("\"")); }
-
static void initialize_vars_and_statics(env_t *env, ast_t *ast) {
if (!ast) return;
@@ -162,6 +164,7 @@ static Text_t compile_top_level_code(env_t *env, ast_t *ast) {
}
}
+public
Text_t compile_file(env_t *env, ast_t *ast) {
Text_t top_level_code = compile_top_level_code(env, ast);
Text_t includes = EMPTY_TEXT;
@@ -193,3 +196,266 @@ Text_t compile_file(env_t *env, ast_t *ast) {
"static bool initialized = false;\n", "if (initialized) return;\n", "initialized = true;\n",
use_imports, env->code->variable_initializers, "}\n");
}
+
+public
+Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast) {
+ env_t *ns_env = NULL;
+ ast_t *block = NULL;
+ switch (ast->tag) {
+ case LangDef: {
+ DeclareMatch(def, ast, LangDef);
+ ns_env = namespace_env(env, def->name);
+ block = def->namespace;
+ break;
+ }
+ case Extend: {
+ DeclareMatch(extend, ast, Extend);
+ 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->id_suffix = env->id_suffix;
+ ns_env = extended;
+
+ block = extend->body;
+ break;
+ }
+ case StructDef: {
+ DeclareMatch(def, ast, StructDef);
+ ns_env = namespace_env(env, def->name);
+ block = def->namespace;
+ break;
+ }
+ case EnumDef: {
+ DeclareMatch(def, ast, EnumDef);
+ ns_env = namespace_env(env, def->name);
+ block = def->namespace;
+ break;
+ }
+ case Extern: {
+ DeclareMatch(ext, ast, Extern);
+ type_t *t = parse_type_ast(env, ext->type);
+ Text_t decl;
+ if (t->tag == ClosureType) {
+ t = Match(t, ClosureType)->fn;
+ DeclareMatch(fn, t, FunctionType);
+ decl = Texts(compile_type(fn->ret), " ", ext->name, "(");
+ for (arg_t *arg = fn->args; arg; arg = arg->next) {
+ decl = Texts(decl, compile_type(arg->type));
+ if (arg->next) decl = Texts(decl, ", ");
+ }
+ decl = Texts(decl, ")");
+ } else {
+ decl = compile_declaration(t, Text$from_str(ext->name));
+ }
+ return Texts("extern ", decl, ";\n");
+ }
+ case Declare: {
+ DeclareMatch(decl, ast, Declare);
+ const char *decl_name = Match(decl->var, Var)->name;
+ bool is_private = (decl_name[0] == '_');
+ if (is_private) return EMPTY_TEXT;
+
+ type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
+ if (t->tag == FunctionType) t = Type(ClosureType, t);
+ assert(t->tag != ModuleType);
+ if (t->tag == AbortType || t->tag == VoidType || t->tag == ReturnType)
+ code_err(ast, "You can't declare a variable with a ", type_to_str(t), " value");
+
+ return Texts(decl->value ? compile_statement_type_header(env, header_path, decl->value) : EMPTY_TEXT, "extern ",
+ compile_declaration(t, namespace_name(env, env->namespace, Text$from_str(decl_name))), ";\n");
+ }
+ case FunctionDef: {
+ DeclareMatch(fndef, ast, FunctionDef);
+ const char *decl_name = Match(fndef->name, Var)->name;
+ bool is_private = decl_name[0] == '_';
+ if (is_private) return EMPTY_TEXT;
+ Text_t arg_signature = Text("(");
+ for (arg_ast_t *arg = fndef->args; arg; arg = arg->next) {
+ type_t *arg_type = get_arg_ast_type(env, arg);
+ arg_signature = Texts(arg_signature, compile_declaration(arg_type, Texts("_$", arg->name)));
+ if (arg->next) arg_signature = Texts(arg_signature, ", ");
+ }
+ arg_signature = Texts(arg_signature, ")");
+
+ type_t *ret_t = fndef->ret_type ? parse_type_ast(env, fndef->ret_type) : Type(VoidType);
+ Text_t ret_type_code = compile_type(ret_t);
+ if (ret_t->tag == AbortType) ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code);
+ Text_t name = namespace_name(env, env->namespace, Text$from_str(decl_name));
+ if (env->namespace && env->namespace->parent && env->namespace->name && streq(decl_name, env->namespace->name))
+ name = namespace_name(env, env->namespace, Text$from_str(String(get_line_number(ast->file, ast->start))));
+ return Texts(ret_type_code, " ", name, arg_signature, ";\n");
+ }
+ case ConvertDef: {
+ DeclareMatch(def, ast, ConvertDef);
+
+ Text_t arg_signature = Text("(");
+ for (arg_ast_t *arg = def->args; arg; arg = arg->next) {
+ type_t *arg_type = get_arg_ast_type(env, arg);
+ arg_signature = Texts(arg_signature, compile_declaration(arg_type, Texts("_$", arg->name)));
+ if (arg->next) arg_signature = Texts(arg_signature, ", ");
+ }
+ arg_signature = Texts(arg_signature, ")");
+
+ type_t *ret_t = def->ret_type ? parse_type_ast(env, def->ret_type) : Type(VoidType);
+ Text_t ret_type_code = compile_type(ret_t);
+ Text_t name = Text$from_str(get_type_name(ret_t));
+ if (name.length == 0)
+ code_err(ast,
+ "Conversions are only supported for text, struct, and enum "
+ "types, not ",
+ type_to_str(ret_t));
+ Text_t name_code =
+ namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start))));
+ return Texts(ret_type_code, " ", name_code, arg_signature, ";\n");
+ }
+ default: return EMPTY_TEXT;
+ }
+ assert(ns_env);
+ Text_t header = EMPTY_TEXT;
+ for (ast_list_t *stmt = block ? Match(block, Block)->statements : NULL; stmt; stmt = stmt->next) {
+ header = Texts(header, compile_statement_namespace_header(ns_env, header_path, stmt->ast));
+ }
+ return header;
+}
+
+typedef struct {
+ env_t *env;
+ Text_t *header;
+ Path_t header_path;
+} compile_typedef_info_t;
+
+static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast) {
+ if (ast->tag == StructDef) {
+ DeclareMatch(def, ast, StructDef);
+ if (def->external) return;
+ Text_t struct_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$struct"));
+ Text_t type_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type"));
+ *info->header = Texts(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n");
+ } else if (ast->tag == EnumDef) {
+ DeclareMatch(def, ast, EnumDef);
+ bool has_any_tags_with_fields = false;
+ for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
+ has_any_tags_with_fields = has_any_tags_with_fields || (tag->fields != NULL);
+ }
+
+ if (has_any_tags_with_fields) {
+ Text_t struct_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$struct"));
+ Text_t type_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type"));
+ *info->header = Texts(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n");
+
+ for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
+ if (!tag->fields) continue;
+ Text_t tag_struct =
+ namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$struct"));
+ Text_t tag_type =
+ namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$type"));
+ *info->header = Texts(*info->header, "typedef struct ", tag_struct, " ", tag_type, ";\n");
+ }
+ } else {
+ Text_t enum_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$enum"));
+ Text_t type_name = namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type"));
+ *info->header = Texts(*info->header, "typedef enum ", enum_name, " ", type_name, ";\n");
+ }
+ } else if (ast->tag == LangDef) {
+ DeclareMatch(def, ast, LangDef);
+ *info->header = Texts(*info->header, "typedef Text_t ",
+ namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type")), ";\n");
+ }
+}
+
+static void _define_types_and_funcs(compile_typedef_info_t *info, ast_t *ast) {
+ *info->header = Texts(*info->header, compile_statement_type_header(info->env, info->header_path, ast),
+ compile_statement_namespace_header(info->env, info->header_path, ast));
+}
+
+public
+Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast) {
+ Text_t header =
+ Texts("#pragma once\n",
+ env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT,
+ "#include <tomo_" TOMO_VERSION "/tomo.h>\n");
+
+ compile_typedef_info_t info = {.env = env, .header = &header, .header_path = header_path};
+ visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn = (void *)_make_typedefs, &info});
+ visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn = (void *)_define_types_and_funcs, &info});
+
+ header = Texts(header, "void ", namespace_name(env, env->namespace, Text("$initialize")), "(void);\n");
+ return header;
+}
+
+public
+Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast) {
+ switch (ast->tag) {
+ case Use: {
+ DeclareMatch(use, ast, Use);
+ Path_t source_path = Path$from_str(ast->file->filename);
+ Path_t source_dir = Path$parent(source_path);
+ Path_t build_dir = Path$resolved(Path$parent(header_path), Path$current_dir());
+ switch (use->what) {
+ case USE_MODULE: {
+ module_info_t mod = get_module_info(ast);
+ glob_t tm_files;
+ const char *folder = mod.version ? String(mod.name, "_", mod.version) : mod.name;
+ if (glob(String(TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE,
+ NULL, &tm_files)
+ != 0) {
+ if (!try_install_module(mod)) code_err(ast, "Could not find library");
+ }
+
+ Text_t includes = EMPTY_TEXT;
+ for (size_t i = 0; i < tm_files.gl_pathc; i++) {
+ const char *filename = tm_files.gl_pathv[i];
+ Path_t tm_file = Path$from_str(filename);
+ Path_t lib_build_dir = Path$sibling(tm_file, Text(".build"));
+ Path_t header = Path$child(lib_build_dir, Texts(Path$base_name(tm_file), Text(".h")));
+ includes = Texts(includes, "#include \"", Path$as_c_string(header), "\"\n");
+ }
+ globfree(&tm_files);
+ return with_source_info(env, ast, includes);
+ }
+ case USE_LOCAL: {
+ Path_t used_path = Path$resolved(Path$from_str(use->path), source_dir);
+ Path_t used_build_dir = Path$sibling(used_path, Text(".build"));
+ Path_t used_header_path = Path$child(used_build_dir, Texts(Path$base_name(used_path), Text(".h")));
+ return Texts("#include \"", Path$as_c_string(Path$relative_to(used_header_path, build_dir)), "\"\n");
+ }
+ case USE_HEADER:
+ if (use->path[0] == '<') {
+ return Texts("#include ", use->path, "\n");
+ } else {
+ Path_t used_path = Path$resolved(Path$from_str(use->path), source_dir);
+ return Texts("#include \"", Path$as_c_string(Path$relative_to(used_path, build_dir)), "\"\n");
+ }
+ default: return EMPTY_TEXT;
+ }
+ }
+ case StructDef: {
+ return compile_struct_header(env, ast);
+ }
+ case EnumDef: {
+ return compile_enum_header(env, ast);
+ }
+ case LangDef: {
+ DeclareMatch(def, ast, LangDef);
+ return Texts(
+ // Constructor macro:
+ "#define ", namespace_name(env, env->namespace, Text$from_str(def->name)), "(text) ((",
+ namespace_name(env, env->namespace, Texts(def->name, "$$type")),
+ "){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" "
+ "text})\n"
+ "#define ",
+ namespace_name(env, env->namespace, Text$from_str(def->name)), "s(...) ((",
+ namespace_name(env, env->namespace, Texts(def->name, "$$type")),
+ ")Texts(__VA_ARGS__))\n"
+ "extern const TypeInfo_t ",
+ namespace_name(env, env->namespace, Texts(def->name, Text("$$info"))), ";\n");
+ }
+ case Extend: {
+ return EMPTY_TEXT;
+ }
+ default: return EMPTY_TEXT;
+ }
+}
diff --git a/src/compile/files.h b/src/compile/files.h
index 8b8b4012..c9086f53 100644
--- a/src/compile/files.h
+++ b/src/compile/files.h
@@ -4,3 +4,6 @@
Text_t compile_file(env_t *env, ast_t *ast);
Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast);
+Text_t compile_namespace_header(env_t *env, const char *ns_name, ast_t *block);
+Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast);
+Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast);
diff --git a/src/compile/statements.c b/src/compile/statements.c
index 8649b978..ee70fdea 100644
--- a/src/compile/statements.c
+++ b/src/compile/statements.c
@@ -23,6 +23,13 @@
typedef ast_t *(*comprehension_body_t)(ast_t *, ast_t *);
public
+Text_t with_source_info(env_t *env, ast_t *ast, Text_t code) {
+ if (code.length == 0 || !ast || !ast->file || !env->do_source_mapping) return code;
+ int64_t line = get_line_number(ast->file, ast->start);
+ return Texts("\n#line ", String(line), "\n", code);
+}
+
+public
Text_t compile_inline_block(env_t *env, ast_t *ast) {
if (ast->tag != Block) return compile_statement(env, ast);
diff --git a/src/compile/statements.h b/src/compile/statements.h
index abe34a09..8c8956e7 100644
--- a/src/compile/statements.h
+++ b/src/compile/statements.h
@@ -5,3 +5,4 @@
Text_t compile_condition(env_t *env, ast_t *ast);
Text_t compile_inline_block(env_t *env, ast_t *ast);
Text_t compile_statement(env_t *env, ast_t *ast);
+Text_t with_source_info(env_t *env, ast_t *ast, Text_t code);
diff --git a/src/compile/types.c b/src/compile/types.c
index 9b7cf4df..e3786c99 100644
--- a/src/compile/types.c
+++ b/src/compile/types.c
@@ -5,10 +5,7 @@
#include "../stdlib/datatypes.h"
#include "../stdlib/text.h"
#include "../stdlib/util.h"
-
-static Text_t quoted_str(const char *str) { return Text$quoted(Text$from_str(str), false, Text("\"")); }
-
-static inline Text_t quoted_text(Text_t text) { return Text$quoted(text, false, Text("\"")); }
+#include "text.h"
public
Text_t compile_type(type_t *t) {