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 };