diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-08-24 17:13:48 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-08-24 17:13:48 -0400 |
| commit | 2245c883680ccfbe545f230d6b68c38ce54bceb6 (patch) | |
| tree | 2a861d7482bcf0f30c07483e6adc287f83e8090a /src | |
| parent | 476bacc27671de92e8fdbc5b2a904bbf8bc80377 (diff) | |
Shift some code around.
Diffstat (limited to 'src')
| -rw-r--r-- | src/compile.c | 272 | ||||
| -rw-r--r-- | src/compile.h | 4 | ||||
| -rw-r--r-- | src/compile/files.c | 274 | ||||
| -rw-r--r-- | src/compile/files.h | 3 | ||||
| -rw-r--r-- | src/compile/statements.c | 7 | ||||
| -rw-r--r-- | src/compile/statements.h | 1 | ||||
| -rw-r--r-- | src/compile/types.c | 5 |
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) { |
