diff options
Diffstat (limited to 'src/compile.c')
| -rw-r--r-- | src/compile.c | 272 |
1 files changed, 0 insertions, 272 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 |
