kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

c.c (5341B)


      1 #include "c.h"
      2 
      3 #include "decl/decl.h"
      4 #include "lex/lex.h"
      5 #include "parse/parse.h"
      6 #include "pp/pp.h"
      7 
      8 static SrcLoc c_no_loc(void) {
      9   SrcLoc loc;
     10   loc.file_id = 0;
     11   loc.line = 0;
     12   loc.col = 0;
     13   return loc;
     14 }
     15 
     16 static _Noreturn void c_bad_options(Compiler* c, const char* msg) {
     17   compiler_panic(c, c_no_loc(), "bad C frontend options: %.*s",
     18                  KIT_SLICE_ARG(kit_slice_cstr(msg)));
     19 }
     20 
     21 static void c_apply_pp_options(Pp* pp, const KitPreprocessOptions* opts) {
     22   u32 i;
     23 
     24   for (i = 0; i < opts->ninclude_dirs; ++i) {
     25     pp_add_include_dir(pp, opts->include_dirs[i], 0);
     26   }
     27   for (i = 0; i < opts->nsystem_include_dirs; ++i) {
     28     pp_add_include_dir(pp, opts->system_include_dirs[i], 1);
     29   }
     30   for (i = 0; i < opts->ndefines; ++i) {
     31     const char* body =
     32         opts->defines[i].body.len ? opts->defines[i].body.s : "1";
     33     pp_define(pp, opts->defines[i].name.s, body);
     34   }
     35   for (i = 0; i < opts->nundefines; ++i) {
     36     pp_undef(pp, opts->undefines[i].s);
     37   }
     38 }
     39 
     40 typedef struct CFrontend {
     41   KitCompiler* c;
     42 } CFrontend;
     43 
     44 static KitFrontendState* c_frontend_new(KitCompiler* c) {
     45   KitHeap* h;
     46   CFrontend* fe;
     47   if (!c) return NULL;
     48   h = kit_compiler_context(c)->heap;
     49   fe = (CFrontend*)h->alloc(h, sizeof(*fe), _Alignof(CFrontend));
     50   if (!fe) return NULL;
     51   fe->c = c;
     52   return (KitFrontendState*)fe;
     53 }
     54 
     55 static KitStatus c_frontend_compile_cg(KitFrontendState* frontend,
     56                                        const KitFrontendCompileOptions* fe_opts,
     57                                        const KitSourceInput* input, KitCg* cg) {
     58   CFrontend* fe = (CFrontend*)frontend;
     59   KitCompiler* c;
     60   /* Code, diagnostics, and preprocessor settings all arrive on the common
     61    * KitFrontendCompileOptions; the C frontend uses no language_options. */
     62   const KitSlice* bytes;
     63   Pool* pool;
     64   Lexer* lex;
     65   Pp* pp;
     66   DeclTable* decls;
     67 
     68   if (!fe || !fe->c) return KIT_INVALID;
     69   c = fe->c;
     70   if (!fe_opts || !input || !cg) c_bad_options(c, "compile args missing");
     71   bytes = &input->bytes;
     72 
     73   kit_frontend_metrics_scope_begin(c, "compile.c.setup");
     74   kit_frontend_metrics_scope_begin(c, "compile.c.pool_new");
     75   pool = c_pool_new(c);
     76   kit_frontend_metrics_scope_end(c, "compile.c.pool_new");
     77   if (!pool) compiler_panic(c, c_no_loc(), "C compiler out of memory");
     78   kit_frontend_metrics_scope_begin(c, "compile.c.lex_open");
     79   lex = lex_open_mem(c, input->name.s, bytes->s, bytes->len);
     80   if (lex) lex_skip_shebang(lex);
     81   kit_frontend_metrics_scope_end(c, "compile.c.lex_open");
     82   kit_frontend_metrics_scope_begin(c, "compile.c.pp_new");
     83   pp = pp_new(c);
     84   kit_frontend_metrics_scope_end(c, "compile.c.pp_new");
     85   if (!lex || !pp || !cg)
     86     compiler_panic(c, c_no_loc(), "C compiler out of memory");
     87   kit_frontend_metrics_scope_begin(c, "compile.c.decl_new");
     88   decls = decl_new(c, pool, cg);
     89   kit_frontend_metrics_scope_end(c, "compile.c.decl_new");
     90   kit_frontend_metrics_scope_end(c, "compile.c.setup");
     91 
     92   kit_frontend_metrics_scope_begin(c, "compile.c.pp_options");
     93   kit_frontend_metrics_count(c, "compile.c.pp_include_dirs",
     94                              fe_opts->preprocess.ninclude_dirs);
     95   kit_frontend_metrics_count(c, "compile.c.pp_system_include_dirs",
     96                              fe_opts->preprocess.nsystem_include_dirs);
     97   kit_frontend_metrics_count(c, "compile.c.pp_defines",
     98                              fe_opts->preprocess.ndefines);
     99   kit_frontend_metrics_count(c, "compile.c.pp_undefines",
    100                              fe_opts->preprocess.nundefines);
    101   c_apply_pp_options(pp, &fe_opts->preprocess);
    102   kit_frontend_metrics_scope_end(c, "compile.c.pp_options");
    103   kit_frontend_metrics_scope_begin(c, "compile.c.pp_push_input");
    104   pp_push_input(pp, lex);
    105   kit_frontend_metrics_scope_end(c, "compile.c.pp_push_input");
    106 
    107   kit_frontend_metrics_scope_begin(c, "compile.c.parse_codegen");
    108   parse_c(c, pool, pp, decls, cg, (KitSymVis)fe_opts->code.default_visibility);
    109   kit_frontend_metrics_scope_end(c, "compile.c.parse_codegen");
    110 
    111   kit_frontend_metrics_scope_begin(c, "compile.c.cleanup");
    112   decl_free(decls);
    113   pp_free(pp);
    114   c_pool_free(pool);
    115   kit_frontend_metrics_scope_end(c, "compile.c.cleanup");
    116   return KIT_OK;
    117 }
    118 
    119 static void c_frontend_free(KitFrontendState* frontend) {
    120   CFrontend* fe = (CFrontend*)frontend;
    121   KitHeap* h;
    122   if (!fe) return;
    123   h = kit_compiler_context(fe->c)->heap;
    124   h->free(h, fe, sizeof(*fe));
    125 }
    126 
    127 /* C is just another frontend: it claims its source/header extensions so the
    128  * language-for-path lookup resolves them by the same registry walk as every
    129  * other language, with no special fallback. */
    130 static const KitSlice c_extensions[] = {KIT_SLICE_LIT("c"), KIT_SLICE_LIT("h")};
    131 /* Canonical `-x` name; mirrors the driver's "c" spelling. */
    132 static const KitSlice c_names[] = {KIT_SLICE_LIT("c")};
    133 
    134 const KitFrontendVTable kit_c_frontend_vtable = {
    135     c_frontend_new,
    136     c_frontend_compile_cg,
    137     NULL, /* compile_obj: semantic frontends are wrapped by compile session */
    138     c_frontend_free,
    139     c_extensions,
    140     (uint32_t)(sizeof c_extensions / sizeof c_extensions[0]),
    141     c_names,
    142     (uint32_t)(sizeof c_names / sizeof c_names[0]),
    143     /* commit/abort: C has no durable cross-compile state yet */
    144     NULL,
    145     NULL,
    146     {true, KIT_FRONTEND_LTO_CG, false},
    147     NULL, /* parse_options: C has no frontend-specific flags */
    148     NULL, /* free_options */
    149 };