From 56959100a677369eca0261b47ec7299e9a8d1207 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 24 Aug 2025 17:56:58 -0400 Subject: Split headers into their own file --- src/compile/files.c | 227 +--------------------------------------------- src/compile/files.h | 4 - src/compile/headers.c | 243 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/compile/headers.h | 11 +++ src/tomo.c | 2 +- 5 files changed, 256 insertions(+), 231 deletions(-) create mode 100644 src/compile/headers.c create mode 100644 src/compile/headers.h (limited to 'src') diff --git a/src/compile/files.c b/src/compile/files.c index 006885e1..2cce010f 100644 --- a/src/compile/files.c +++ b/src/compile/files.c @@ -1,11 +1,9 @@ // This file defines how to compile files -#include - +#include "files.h" #include "../ast.h" #include "../config.h" #include "../environment.h" -#include "../modules.h" #include "../naming.h" #include "../stdlib/datatypes.h" #include "../stdlib/paths.h" @@ -15,12 +13,10 @@ #include "../types.h" #include "declarations.h" #include "enums.h" -#include "files.h" #include "functions.h" #include "statements.h" #include "structs.h" #include "text.h" -#include "types.h" static void initialize_vars_and_statics(env_t *env, ast_t *ast) { if (!ast) return; @@ -197,224 +193,3 @@ 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: return compile_function_declaration(env, ast); - case ConvertDef: return compile_convert_declaration(env, ast); - 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 \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 e2a6e98b..94047638 100644 --- a/src/compile/files.h +++ b/src/compile/files.h @@ -6,7 +6,3 @@ #include "../stdlib/datatypes.h" 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/headers.c b/src/compile/headers.c new file mode 100644 index 00000000..44859104 --- /dev/null +++ b/src/compile/headers.c @@ -0,0 +1,243 @@ +// This file defines how to compile files + +#include + +#include "../ast.h" +#include "../config.h" +#include "../environment.h" +#include "../modules.h" +#include "../naming.h" +#include "../stdlib/datatypes.h" +#include "../stdlib/paths.h" +#include "../stdlib/text.h" +#include "../typecheck.h" +#include "../types.h" +#include "declarations.h" +#include "enums.h" +#include "functions.h" +#include "headers.h" +#include "statements.h" +#include "structs.h" +#include "text.h" +#include "types.h" + +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: return compile_function_declaration(env, ast); + case ConvertDef: return compile_convert_declaration(env, ast); + 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 \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/headers.h b/src/compile/headers.h new file mode 100644 index 00000000..edfd4086 --- /dev/null +++ b/src/compile/headers.h @@ -0,0 +1,11 @@ +// This file defines how to compile header files +#pragma once + +#include "../ast.h" +#include "../environment.h" +#include "../stdlib/datatypes.h" + +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/tomo.c b/src/tomo.c index 6dfe687c..6f08f1ff 100644 --- a/src/tomo.c +++ b/src/tomo.c @@ -14,9 +14,9 @@ #include "ast.h" #include "changes.md.h" -#include "compile.h" #include "compile/cli.h" #include "compile/files.h" +#include "compile/headers.h" #include "config.h" #include "modules.h" #include "naming.h" -- cgit v1.2.3