kit

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

compile.c (8229B)


      1 #include <string.h>
      2 
      3 #include "internal.h"
      4 #include "toy.h"
      5 
      6 typedef struct ToyFrontend {
      7   KitCompiler* c;
      8   ToyModule module; /* durable cross-snippet declarations */
      9   ToyParser parser; /* per-compile; borrows &module */
     10   int parser_live;
     11 } ToyFrontend;
     12 
     13 static int toy_buf_append(ToyFrontend* fe, char** buf, size_t* len, size_t* cap,
     14                           const char* src, size_t n) {
     15   KitHeap* h = kit_compiler_context(fe->c)->heap;
     16   if (*len + n + 1u > *cap) {
     17     size_t nc = *cap ? *cap * 2u : 256u;
     18     char* nb;
     19     while (nc < *len + n + 1u) nc *= 2u;
     20     nb = (char*)h->realloc(h, *buf, *cap ? *cap : 1u, nc, _Alignof(char));
     21     if (!nb) return 0;
     22     *buf = nb;
     23     *cap = nc;
     24   }
     25   if (n) memcpy(*buf + *len, src, n);
     26   *len += n;
     27   (*buf)[*len] = '\0';
     28   return 1;
     29 }
     30 
     31 static int toy_build_repl_source(ToyFrontend* fe,
     32                                  const KitFrontendCompileOptions* opts,
     33                                  const KitSourceInput* input,
     34                                  const uint8_t** source_out,
     35                                  size_t* source_len_out, char** owned_out,
     36                                  size_t* owned_cap_out) {
     37   KitSlice name = opts->repl_entry_name;
     38   const char* body = input->bytes.data ? (const char*)input->bytes.data : "";
     39   size_t body_len = input->bytes.data ? input->bytes.len : 0u;
     40   char* src = NULL;
     41   size_t len = 0;
     42   size_t cap = 0;
     43 
     44   *owned_out = NULL;
     45   *owned_cap_out = 0;
     46   if (opts->input_kind == KIT_FRONTEND_INPUT_TRANSLATION_UNIT ||
     47       opts->input_kind == KIT_FRONTEND_INPUT_REPL_TOPLEVEL) {
     48     *source_out = (const uint8_t*)body;
     49     *source_len_out = body_len;
     50     return 1;
     51   }
     52   if (!name.s || !name.len) return 0;
     53   if (!toy_buf_append(fe, &src, &len, &cap, "fn ", 3) ||
     54       !toy_buf_append(fe, &src, &len, &cap, name.s, name.len) ||
     55       !toy_buf_append(fe, &src, &len, &cap, "(): i64 {\n", 10)) {
     56     goto oom;
     57   }
     58   if (opts->input_kind == KIT_FRONTEND_INPUT_REPL_EXPR) {
     59     if (!toy_buf_append(fe, &src, &len, &cap, "  return (", 10) ||
     60         !toy_buf_append(fe, &src, &len, &cap, body, body_len) ||
     61         !toy_buf_append(fe, &src, &len, &cap, ") as i64;\n", 10)) {
     62       goto oom;
     63     }
     64   } else if (opts->input_kind == KIT_FRONTEND_INPUT_REPL_BLOCK) {
     65     if (!toy_buf_append(fe, &src, &len, &cap, body, body_len) ||
     66         (body_len && body[body_len - 1u] != '\n' &&
     67          !toy_buf_append(fe, &src, &len, &cap, "\n", 1))) {
     68       goto oom;
     69     }
     70   } else {
     71     goto oom;
     72   }
     73   if (!toy_buf_append(fe, &src, &len, &cap, "}\n", 2)) goto oom;
     74   *source_out = (const uint8_t*)src;
     75   *source_len_out = len;
     76   *owned_out = src;
     77   *owned_cap_out = cap;
     78   return 1;
     79 
     80 oom:
     81   if (src) {
     82     KitHeap* h = kit_compiler_context(fe->c)->heap;
     83     h->free(h, src, cap ? cap : 1u);
     84   }
     85   return 0;
     86 }
     87 
     88 static int toy_seed_repl_symbols(ToyParser* p) {
     89   size_t i;
     90   for (i = 0; i < p->module->nfns; ++i) {
     91     ToyFn* fn = &p->module->fns[i];
     92     KitCgDecl decl;
     93     KitCgSym sym;
     94     memset(&decl, 0, sizeof decl);
     95     decl.kind = KIT_CG_DECL_FUNC;
     96     decl.linkage_name = toy_c_linkage_name(p, fn->name);
     97     decl.display_name = fn->name;
     98     decl.type = fn->type;
     99     decl.sym = fn->sym_attrs;
    100     decl.sym.bind = KIT_SB_GLOBAL;
    101     decl.as.func = fn->func_attrs;
    102     sym = kit_cg_decl(p->cg, decl);
    103     if (sym == KIT_CG_SYM_NONE) return 0;
    104     if (!toy_fn_set_cur_sym(p, i, sym)) return 0;
    105   }
    106   for (i = 0; i < p->module->nglobals; ++i) {
    107     ToyGlobal* g = &p->module->globals[i];
    108     KitCgDecl decl;
    109     KitCgSym sym;
    110     memset(&decl, 0, sizeof decl);
    111     decl.kind = KIT_CG_DECL_OBJECT;
    112     decl.linkage_name = toy_c_linkage_name(p, g->name);
    113     decl.display_name = g->name;
    114     decl.type = g->type;
    115     decl.sym = g->sym_attrs;
    116     decl.sym.bind = KIT_SB_GLOBAL;
    117     decl.as.object = g->object_attrs;
    118     sym = kit_cg_decl(p->cg, decl);
    119     if (sym == KIT_CG_SYM_NONE) return 0;
    120     if (!toy_global_set_cur_sym(p, i, sym)) return 0;
    121   }
    122   return 1;
    123 }
    124 
    125 static KitFrontendState* toy_frontend_new(KitCompiler* c) {
    126   KitHeap* h;
    127   ToyFrontend* fe;
    128   if (!c) return NULL;
    129   h = kit_compiler_context(c)->heap;
    130   fe = (ToyFrontend*)h->alloc(h, sizeof(*fe), _Alignof(ToyFrontend));
    131   if (!fe) return NULL;
    132   memset(fe, 0, sizeof *fe);
    133   fe->c = c;
    134   return (KitFrontendState*)fe;
    135 }
    136 
    137 static KitStatus toy_frontend_compile_cg(KitFrontendState* frontend,
    138                                          const KitFrontendCompileOptions* opts,
    139                                          const KitSourceInput* input,
    140                                          KitCg* cg) {
    141   ToyFrontend* fe = (ToyFrontend*)frontend;
    142   KitCompiler* c;
    143   ToyParser* p;
    144   const uint8_t* source;
    145   size_t source_len;
    146   KitStatus st = KIT_OK;
    147   char* owned_source = NULL;
    148   size_t owned_source_cap = 0;
    149 
    150   if (!fe || !fe->c || !opts || !input || !cg) return KIT_INVALID;
    151   c = fe->c;
    152   (void)opts->language_options; /* toy frontend has no per-language options */
    153 
    154   if (!toy_build_repl_source(fe, opts, input, &source, &source_len,
    155                              &owned_source, &owned_source_cap)) {
    156     return KIT_ERR;
    157   }
    158 
    159   if (!fe->parser_live) {
    160     toy_parser_init(&fe->parser, c, cg, &fe->module, source, source_len,
    161                     input->name.s);
    162     fe->parser.input_kind = opts->input_kind;
    163     fe->parser_live = 1;
    164   } else {
    165     toy_parser_reinit(&fe->parser, c, cg, source, source_len, input->name.s,
    166                       opts->input_kind);
    167   }
    168   /* Drive the heap-resident parser directly. The previous copy-by-value
    169    * variant (`ToyParser p = fe->parser; ...; fe->parser = p;`) lost any
    170    * growth of the parser's internal arrays when a wasm CG panic longjmp'd
    171    * past the `fe->parser = p;` sync-back, leaving fe->parser holding
    172    * pointers that the local `p`'s grow path had freed and replaced —
    173    * dispose then double-freed via the stale pointer. */
    174   p = &fe->parser;
    175   /* Open the transaction over the durable module before staging anything. A
    176    * failed or panicking compile is rolled back by the session via the abort
    177    * hook; a successful compile leaves the transaction open for the caller to
    178    * commit (after a successful publish) or abort (if publish fails). */
    179   toy_txn_begin(p);
    180   if (opts->input_kind != KIT_FRONTEND_INPUT_TRANSLATION_UNIT &&
    181       !toy_seed_repl_symbols(p)) {
    182     st = KIT_ERR;
    183     goto done_status;
    184   }
    185 
    186   if (!toy_parse_program(p) || p->has_error) {
    187     st = KIT_ERR;
    188     goto done_status;
    189   }
    190   if (p->cur.kind != TOK_EOF) {
    191     toy_error(p, p->cur.loc, "unexpected token after program end");
    192     st = KIT_ERR;
    193     goto done_status;
    194   }
    195 
    196   st = KIT_OK;
    197 
    198 done_status:
    199   if (owned_source) {
    200     KitHeap* h = kit_compiler_context(fe->c)->heap;
    201     h->free(h, owned_source, owned_source_cap ? owned_source_cap : 1u);
    202   }
    203   return st;
    204 }
    205 
    206 static void toy_frontend_commit(KitFrontendState* frontend) {
    207   ToyFrontend* fe = (ToyFrontend*)frontend;
    208   if (fe && fe->parser_live) toy_txn_commit(&fe->parser);
    209 }
    210 
    211 static void toy_frontend_abort(KitFrontendState* frontend) {
    212   ToyFrontend* fe = (ToyFrontend*)frontend;
    213   if (fe && fe->parser_live) toy_txn_abort(&fe->parser);
    214 }
    215 
    216 static void toy_frontend_free(KitFrontendState* frontend) {
    217   ToyFrontend* fe = (ToyFrontend*)frontend;
    218   KitHeap* h;
    219   if (!fe) return;
    220   if (fe->parser_live) {
    221     toy_parser_dispose(&fe->parser);
    222     toy_module_dispose(&fe->module, fe->c);
    223   }
    224   h = kit_compiler_context(fe->c)->heap;
    225   h->free(h, fe, sizeof(*fe));
    226 }
    227 
    228 static const KitSlice toy_extensions[] = {KIT_SLICE_LIT("toy")};
    229 /* Canonical `-x` name; mirrors the driver's "toy" spelling. */
    230 static const KitSlice toy_names[] = {KIT_SLICE_LIT("toy")};
    231 
    232 const KitFrontendVTable kit_toy_frontend_vtable = {
    233     toy_frontend_new,
    234     toy_frontend_compile_cg,
    235     NULL, /* compile_obj: semantic frontends are wrapped by compile session */
    236     toy_frontend_free,
    237     toy_extensions,
    238     (uint32_t)(sizeof toy_extensions / sizeof toy_extensions[0]),
    239     toy_names,
    240     (uint32_t)(sizeof toy_names / sizeof toy_names[0]),
    241     toy_frontend_commit,
    242     toy_frontend_abort,
    243     /* cache_repl_toplevel_source: the toy REPL re-reads earlier toplevel text. */
    244     {false, KIT_FRONTEND_LTO_CG, true},
    245     NULL, /* parse_options: no toy-specific flags yet */
    246     NULL, /* free_options */
    247 };