parser_core.c (18287B)
1 #include <stdarg.h> 2 #include <stdio.h> 3 #include <string.h> 4 5 #include "internal.h" 6 7 KitCgTypeId toy_builtin_type(ToyParser* p, KitCgBuiltinType ty) { 8 return kit_cg_type_builtin(p->c, ty); 9 } 10 11 KitCgTypeId toy_cg_record_type(ToyParser* p, KitSym tag, 12 const KitCgFieldDesc* fields, uint32_t nfields, 13 int is_union, uint32_t align_override) { 14 KitCgRecordDesc desc; 15 memset(&desc, 0, sizeof desc); 16 desc.tag = tag; 17 desc.fields = fields; 18 desc.nfields = nfields; 19 desc.is_union = is_union; 20 desc.align_override = align_override; 21 return kit_cg_type_record(p->c, &desc); 22 } 23 24 int toy_cg_record_complete(ToyParser* p, KitCgTypeId record, KitSym tag, 25 const KitCgFieldDesc* fields, uint32_t nfields, 26 int is_union, uint32_t align_override) { 27 KitCgRecordDesc desc; 28 memset(&desc, 0, sizeof desc); 29 desc.tag = tag; 30 desc.fields = fields; 31 desc.nfields = nfields; 32 desc.is_union = is_union; 33 desc.align_override = align_override; 34 return kit_cg_type_record_complete(p->c, record, &desc) == KIT_OK; 35 } 36 37 KitCgTypeId toy_cg_func_ret(ToyParser* p, KitCgTypeId fn_ty) { 38 KitCgTypeId rt = kit_cg_type_func_result(p->c, fn_ty).type; 39 return rt ? rt : toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 40 } 41 42 void* toy_parser_zalloc(ToyParser* p, size_t count, size_t elem_size, 43 const char* what) { 44 KitHeap* h = kit_compiler_context(p->c)->heap; 45 size_t size = count * elem_size; 46 void* items; 47 if (count != 0 && size / count != elem_size) { 48 toy_error(p, p->cur.loc, "out of memory growing %.*s", 49 KIT_SLICE_ARG(kit_slice_cstr(what))); 50 return NULL; 51 } 52 items = h->alloc(h, size ? size : 1u, 1); 53 if (!items) { 54 toy_error(p, p->cur.loc, "out of memory growing %.*s", 55 KIT_SLICE_ARG(kit_slice_cstr(what))); 56 return NULL; 57 } 58 memset(items, 0, size ? size : 1u); 59 return items; 60 } 61 62 void toy_parser_free_mem(ToyParser* p, void* items, size_t size) { 63 KitHeap* h; 64 if (!items) return; 65 h = kit_compiler_context(p->c)->heap; 66 h->free(h, items, size ? size : 1u); 67 } 68 69 static uint32_t toy_source_file_id(KitCompiler* c, const char* name) { 70 uint32_t file_id = 0; 71 if (name && *name) 72 (void)kit_source_add_memory(c, kit_slice_cstr(name), &file_id); 73 return file_id; 74 } 75 76 void toy_parser_init(ToyParser* p, KitCompiler* c, KitCg* cg, ToyModule* module, 77 const uint8_t* data, size_t len, const char* input_name) { 78 memset(p, 0, sizeof *p); 79 p->module = module; 80 p->file_id = toy_source_file_id(c, input_name); 81 p->input_name = input_name; 82 toy_lexer_init(&p->lex, data, len, p->file_id); 83 p->cur = toy_lexer_next(&p->lex); 84 p->c = c; 85 p->cg = cg; 86 p->target = kit_compiler_target_spec(c); 87 p->int_type = toy_builtin_type(p, KIT_CG_BUILTIN_I64); 88 p->size_type = toy_builtin_type( 89 p, p->target.ptr_size <= 4u ? KIT_CG_BUILTIN_I32 : KIT_CG_BUILTIN_I64); 90 p->int_ptr_type = kit_cg_type_ptr(c, p->int_type, 0); 91 p->va_list_type = toy_builtin_type(p, KIT_CG_BUILTIN_VARARG_STATE); 92 p->nvars = 0; 93 p->cap_vars = 0; 94 p->vars = NULL; 95 /* The durable module is zero-initialized by the frontend; register the 96 * builtin types into it exactly once, on this first compile. */ 97 toy_type_register_builtins(p); 98 p->nscopes = 0; 99 p->cap_scopes = 0; 100 p->scopes = NULL; 101 p->nlabels = 0; 102 p->cap_labels = 0; 103 p->labels = NULL; 104 p->goto_targets = NULL; 105 p->cap_goto_targets = 0; 106 p->cur_fn_ret = toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 107 p->cur_fn_ret_toy = toy_type_from_cg(p, p->cur_fn_ret); 108 p->diag = kit_compiler_context(c)->diag; 109 p->input_name = input_name; 110 p->has_error = 0; 111 p->expr_island_mask = 0; 112 p->last_type = TOY_TYPE_NONE; 113 p->allow_tail_call_expr = 0; 114 p->tail_call_expr = 0; 115 p->tail_call_ret_toy = TOY_TYPE_NONE; 116 p->input_kind = KIT_FRONTEND_INPUT_TRANSLATION_UNIT; 117 } 118 119 void toy_parser_reinit(ToyParser* p, KitCompiler* c, KitCg* cg, 120 const uint8_t* data, size_t len, const char* input_name, 121 KitFrontendInputKind input_kind) { 122 p->file_id = toy_source_file_id(c, input_name); 123 p->input_name = input_name; 124 toy_lexer_init(&p->lex, data, len, p->file_id); 125 p->cur = toy_lexer_next(&p->lex); 126 p->c = c; 127 p->cg = cg; 128 p->target = kit_compiler_target_spec(c); 129 p->int_type = toy_builtin_type(p, KIT_CG_BUILTIN_I64); 130 p->size_type = toy_builtin_type( 131 p, p->target.ptr_size <= 4u ? KIT_CG_BUILTIN_I32 : KIT_CG_BUILTIN_I64); 132 p->int_ptr_type = kit_cg_type_ptr(c, p->int_type, 0); 133 p->va_list_type = toy_builtin_type(p, KIT_CG_BUILTIN_VARARG_STATE); 134 p->nvars = 0; 135 p->nscopes = 0; 136 p->nlabels = 0; 137 p->cur_fn_ret = toy_builtin_type(p, KIT_CG_BUILTIN_VOID); 138 p->cur_fn_ret_toy = toy_type_from_cg(p, p->cur_fn_ret); 139 p->diag = kit_compiler_context(c)->diag; 140 p->input_name = input_name; 141 p->has_error = 0; 142 p->expr_island_mask = 0; 143 p->last_type = TOY_TYPE_NONE; 144 p->allow_tail_call_expr = 0; 145 p->tail_call_expr = 0; 146 p->tail_call_ret_toy = TOY_TYPE_NONE; 147 p->input_kind = input_kind; 148 } 149 150 /* Frees one heap block sized for the module owner. Mirrors 151 * toy_parser_free_mem but does not need a live parser, so the durable module 152 * can be torn down independently of any compile. */ 153 static void toy_mem_free(KitCompiler* c, void* items, size_t size) { 154 KitHeap* h; 155 if (!items) return; 156 h = kit_compiler_context(c)->heap; 157 h->free(h, items, size ? size : 1u); 158 } 159 160 void toy_parser_dispose(ToyParser* p) { 161 /* Per-compile scratch only; the durable arrays belong to the module and 162 * are freed by toy_module_dispose. */ 163 toy_parser_free_mem(p, p->vars, p->cap_vars * sizeof *p->vars); 164 toy_parser_free_mem(p, p->scopes, p->cap_scopes * sizeof *p->scopes); 165 toy_parser_free_mem(p, p->labels, p->cap_labels * sizeof *p->labels); 166 toy_parser_free_mem(p, p->goto_targets, 167 p->cap_goto_targets * sizeof *p->goto_targets); 168 toy_parser_free_mem(p, p->fn_syms, p->cap_fn_syms * sizeof *p->fn_syms); 169 toy_parser_free_mem(p, p->global_syms, 170 p->cap_global_syms * sizeof *p->global_syms); 171 toy_parser_free_mem(p, p->txn.undo, p->txn.cap_undo * sizeof *p->txn.undo); 172 p->txn.undo = NULL; 173 p->txn.cap_undo = 0; 174 p->txn.nundo = 0; 175 p->txn.open = 0; 176 p->vars = NULL; 177 p->scopes = NULL; 178 p->labels = NULL; 179 p->goto_targets = NULL; 180 p->fn_syms = NULL; 181 p->global_syms = NULL; 182 p->cap_fn_syms = 0; 183 p->cap_global_syms = 0; 184 p->nvars = 0; 185 p->nscopes = p->nlabels = 0; 186 p->cap_vars = 0; 187 p->cap_scopes = p->cap_labels = 0; 188 p->cap_goto_targets = 0; 189 p->last_type = TOY_TYPE_NONE; 190 } 191 192 void toy_module_dispose(ToyModule* m, KitCompiler* c) { 193 size_t i; 194 ToyTypeTable* tt = &m->type_table; 195 /* Only free per-element pointer arrays when their companion count is 196 * non-zero — allocation only happens in that case, so a zero count means 197 * the pointer field was never written by an allocation. This guards 198 * against rare paths that leave a pointer slot uninitialized while 199 * leaving the count at 0; without it, freeing a garbage pointer aborts 200 * libc malloc with "pointer being freed was not allocated". */ 201 for (i = 0; i < m->nfns; ++i) { 202 if (m->fns[i].nparams) { 203 toy_mem_free(c, m->fns[i].params, 204 m->fns[i].nparams * sizeof *m->fns[i].params); 205 toy_mem_free(c, m->fns[i].toy_params, 206 m->fns[i].nparams * sizeof *m->fns[i].toy_params); 207 } 208 } 209 toy_mem_free(c, m->fns, m->cap_fns * sizeof *m->fns); 210 toy_mem_free(c, m->globals, m->cap_globals * sizeof *m->globals); 211 for (i = 0; i < tt->ntypes; ++i) { 212 if (tt->types[i].nparams) { 213 toy_mem_free(c, tt->types[i].params, 214 tt->types[i].nparams * sizeof *tt->types[i].params); 215 } 216 } 217 toy_mem_free(c, tt->types, tt->cap_types * sizeof *tt->types); 218 for (i = 0; i < tt->count; ++i) { 219 if (tt->named[i].cap_enum_values) { 220 toy_mem_free( 221 c, tt->named[i].enum_values, 222 tt->named[i].cap_enum_values * sizeof *tt->named[i].enum_values); 223 } 224 if (tt->named[i].cap_fields) { 225 toy_mem_free(c, tt->named[i].fields, 226 tt->named[i].cap_fields * sizeof *tt->named[i].fields); 227 } 228 } 229 toy_mem_free(c, tt->named, tt->cap * sizeof *tt->named); 230 m->fns = NULL; 231 m->globals = NULL; 232 tt->types = NULL; 233 tt->named = NULL; 234 m->nfns = m->nglobals = 0; 235 tt->count = tt->ntypes = 0; 236 m->cap_fns = m->cap_globals = 0; 237 tt->cap = tt->cap_types = 0; 238 } 239 240 void toy_txn_begin(ToyParser* p) { 241 ToyModule* m = p->module; 242 p->txn.open = 1; 243 p->txn.fns = m->nfns; 244 p->txn.globals = m->nglobals; 245 p->txn.types = m->type_table.ntypes; 246 p->txn.named = m->type_table.count; 247 p->txn.nundo = 0; /* reuse the journal buffer; cap_undo persists */ 248 } 249 250 void toy_txn_commit(ToyParser* p) { 251 if (!p->txn.open) return; 252 /* Staged appends are already in the module; just drop the journal. */ 253 p->txn.open = 0; 254 p->txn.nundo = 0; 255 } 256 257 int toy_txn_record_named(ToyParser* p, size_t index) { 258 size_t i; 259 if (!p->txn.open || index >= p->txn.named) return 1; /* staged or no txn */ 260 for (i = 0; i < p->txn.nundo; ++i) { 261 if (p->txn.undo[i].kind == TOY_UNDO_NAMED && p->txn.undo[i].index == index) 262 return 1; /* keep the earliest before-image */ 263 } 264 if (!toy_parser_reserve(p, (void**)&p->txn.undo, &p->txn.cap_undo, 265 p->txn.nundo + 1u, sizeof *p->txn.undo, 266 "undo journal")) { 267 return 0; 268 } 269 p->txn.undo[p->txn.nundo].kind = TOY_UNDO_NAMED; 270 p->txn.undo[p->txn.nundo].index = index; 271 p->txn.undo[p->txn.nundo].saved.named = p->module->type_table.named[index]; 272 p->txn.nundo++; 273 return 1; 274 } 275 276 int toy_txn_record_type(ToyParser* p, size_t index) { 277 size_t i; 278 if (!p->txn.open || index >= p->txn.types) return 1; /* staged or no txn */ 279 for (i = 0; i < p->txn.nundo; ++i) { 280 if (p->txn.undo[i].kind == TOY_UNDO_TYPE && p->txn.undo[i].index == index) 281 return 1; 282 } 283 if (!toy_parser_reserve(p, (void**)&p->txn.undo, &p->txn.cap_undo, 284 p->txn.nundo + 1u, sizeof *p->txn.undo, 285 "undo journal")) { 286 return 0; 287 } 288 p->txn.undo[p->txn.nundo].kind = TOY_UNDO_TYPE; 289 p->txn.undo[p->txn.nundo].index = index; 290 p->txn.undo[p->txn.nundo].saved.type = p->module->type_table.types[index]; 291 p->txn.nundo++; 292 return 1; 293 } 294 295 void toy_txn_abort(ToyParser* p) { 296 ToyModule* m = p->module; 297 ToyTypeTable* tt = &m->type_table; 298 size_t i; 299 if (!p->txn.open) return; 300 p->txn.open = 0; 301 /* 1. Restore committed entries that were mutated in place, newest first. 302 * The current entry may have allocated a fields/enum/params array since the 303 * snapshot; free it before restoring the (typically NULL) saved pointer. A 304 * committed entry is only mutated when completing a forward declaration, so 305 * the saved array is NULL and there is no realloc-of-saved hazard. */ 306 while (p->txn.nundo > 0) { 307 ToyUndo* u = &p->txn.undo[--p->txn.nundo]; 308 if (u->kind == TOY_UNDO_NAMED) { 309 ToyNamedType* cur = &tt->named[u->index]; 310 if (cur->fields != u->saved.named.fields) { 311 toy_mem_free(p->c, cur->fields, cur->cap_fields * sizeof *cur->fields); 312 } 313 if (cur->enum_values != u->saved.named.enum_values) { 314 toy_mem_free(p->c, cur->enum_values, 315 cur->cap_enum_values * sizeof *cur->enum_values); 316 } 317 *cur = u->saved.named; 318 } else { 319 ToyType* cur = &tt->types[u->index]; 320 if (cur->params != u->saved.type.params) { 321 toy_mem_free(p->c, cur->params, cur->nparams * sizeof *cur->params); 322 } 323 *cur = u->saved.type; 324 } 325 } 326 /* 2. Truncate staged appends, freeing each dropped entry's sub-arrays. */ 327 for (i = p->txn.fns; i < m->nfns; ++i) { 328 if (m->fns[i].nparams) { 329 toy_mem_free(p->c, m->fns[i].params, 330 m->fns[i].nparams * sizeof *m->fns[i].params); 331 toy_mem_free(p->c, m->fns[i].toy_params, 332 m->fns[i].nparams * sizeof *m->fns[i].toy_params); 333 } 334 } 335 m->nfns = p->txn.fns; 336 m->nglobals = p->txn.globals; /* globals own no sub-arrays */ 337 for (i = p->txn.types; i < tt->ntypes; ++i) { 338 if (tt->types[i].nparams) { 339 toy_mem_free(p->c, tt->types[i].params, 340 tt->types[i].nparams * sizeof *tt->types[i].params); 341 } 342 } 343 tt->ntypes = p->txn.types; 344 for (i = p->txn.named; i < tt->count; ++i) { 345 if (tt->named[i].cap_fields) { 346 toy_mem_free(p->c, tt->named[i].fields, 347 tt->named[i].cap_fields * sizeof *tt->named[i].fields); 348 } 349 if (tt->named[i].cap_enum_values) { 350 toy_mem_free( 351 p->c, tt->named[i].enum_values, 352 tt->named[i].cap_enum_values * sizeof *tt->named[i].enum_values); 353 } 354 } 355 tt->count = p->txn.named; 356 } 357 358 int toy_parser_reserve(ToyParser* p, void** items, size_t* cap, size_t want, 359 size_t elem_size, const char* what) { 360 KitHeap* h; 361 size_t new_cap; 362 size_t old_size; 363 size_t new_size; 364 size_t old_cap; 365 void* new_items; 366 if (want <= *cap) return 1; 367 old_cap = *cap; 368 new_cap = old_cap ? old_cap * 2u : 8u; 369 while (new_cap < want) new_cap *= 2u; 370 old_size = old_cap * elem_size; 371 new_size = new_cap * elem_size; 372 if (new_cap != 0 && new_size / new_cap != elem_size) { 373 toy_error(p, p->cur.loc, "out of memory growing %.*s", 374 KIT_SLICE_ARG(kit_slice_cstr(what))); 375 return 0; 376 } 377 h = kit_compiler_context(p->c)->heap; 378 /* Allocate fresh and copy old contents over (rather than realloc'ing in 379 * place and only zeroing the tail). Zeroing the whole buffer guarantees 380 * any slot the writer doesn't fully initialize has NULL pointers, so the 381 * dispose path never sees stale bytes — a previous realloc-in-place 382 * variant left under-initialized slots holding the realloc'd pages' 383 * prior contents, which manifested as a "pointer being freed was not 384 * allocated" abort in lib c malloc when the dispose loop walked the 385 * type table. */ 386 new_items = h->alloc(h, new_size ? new_size : 1u, 1); 387 if (!new_items) { 388 toy_error(p, p->cur.loc, "out of memory growing %.*s", 389 KIT_SLICE_ARG(kit_slice_cstr(what))); 390 return 0; 391 } 392 memset(new_items, 0, new_size ? new_size : 1u); 393 if (*items && old_size) memcpy(new_items, *items, old_size); 394 if (*items) h->free(h, *items, old_size ? old_size : 1u); 395 *items = new_items; 396 *cap = new_cap; 397 return 1; 398 } 399 400 void toy_parser_advance(ToyParser* p) { p->cur = toy_lexer_next(&p->lex); } 401 402 int toy_parser_match(ToyParser* p, ToyTokenKind kind) { 403 if (p->cur.kind == kind) { 404 toy_parser_advance(p); 405 return 1; 406 } 407 return 0; 408 } 409 410 int toy_parser_expect(ToyParser* p, ToyTokenKind kind) { 411 if (p->cur.kind == kind) { 412 toy_parser_advance(p); 413 return 1; 414 } 415 return 0; 416 } 417 418 void toy_error(ToyParser* p, KitSrcLoc loc, const char* fmt, ...) { 419 va_list ap; 420 p->has_error = 1; 421 if (!p->diag) return; 422 va_start(ap, fmt); 423 p->diag->emit(p->diag, KIT_DIAG_ERROR, loc, fmt, ap); 424 va_end(ap); 425 } 426 427 void toy_set_loc(ToyParser* p) { 428 if (p->cg) kit_cg_set_loc(p->cg, p->cur.loc); 429 } 430 431 KitSym toy_tok_sym(ToyParser* p, ToyToken tok) { 432 char buf[64]; 433 if (tok.text_len >= sizeof(buf)) { 434 toy_error(p, tok.loc, "identifier too long"); 435 return 0; 436 } 437 memcpy(buf, tok.text, tok.text_len); 438 buf[tok.text_len] = '\0'; 439 return kit_sym_intern(p->c, (KitSlice){.s = buf, .len = tok.text_len}); 440 } 441 442 int toy_sym_is(ToyParser* p, KitSym sym, const char* name) { 443 return sym == kit_sym_intern(p->c, kit_slice_cstr(name)); 444 } 445 446 int toy_lookup_const(ToyParser* p, KitSym tok, const ToyConstRow* rows, 447 size_t n, const char* what, uint64_t* out) { 448 size_t i; 449 for (i = 0; i < n; ++i) { 450 if (tok == kit_sym_intern(p->c, kit_slice_cstr(rows[i].name))) { 451 *out = rows[i].value; 452 return 1; 453 } 454 } 455 toy_error(p, p->cur.loc, "unknown %s", what); 456 return 0; 457 } 458 459 int toy_parse_dot_const(ToyParser* p, const ToyConstRow* rows, size_t n, 460 int strict_ident, const char* expected, 461 const char* unknown, uint64_t* out) { 462 KitSym tok; 463 if (strict_ident) { 464 if (!toy_parser_expect(p, TOK_DOT) || p->cur.kind != TOK_IDENT) { 465 toy_error(p, p->cur.loc, "expected %s", expected); 466 return 0; 467 } 468 tok = toy_tok_sym(p, p->cur); 469 toy_parser_advance(p); 470 } else { 471 (void)expected; 472 if (!toy_parse_attr_dot_name(p, &tok)) return 0; 473 } 474 return toy_lookup_const(p, tok, rows, n, unknown, out); 475 } 476 477 int toy_parse_flag_set(ToyParser* p, const ToyConstRow* rows, size_t n, 478 const char* unknown, int comma_prefixed, 479 uint32_t* mask) { 480 for (;;) { 481 KitSym name; 482 uint64_t value; 483 if (comma_prefixed) { 484 if (!toy_parser_match(p, TOK_COMMA)) break; 485 } else if (p->cur.kind == TOK_RPAREN || p->cur.kind == TOK_EOF) { 486 break; 487 } 488 if (!toy_parse_attr_dot_name(p, &name)) return 0; 489 if (!toy_lookup_const(p, name, rows, n, unknown, &value)) return 0; 490 *mask |= (uint32_t)value; 491 if (!comma_prefixed && !toy_parser_match(p, TOK_COMMA)) break; 492 } 493 return 1; 494 } 495 496 int toy_skip_attr_list_ex(ToyParser* p, int* has_static) { 497 int bracket_depth = 0; 498 int paren_depth = 0; 499 if (has_static) *has_static = 0; 500 if (!toy_parser_match(p, TOK_AT)) return 1; 501 if (!toy_parser_expect(p, TOK_LBRACKET)) { 502 toy_error(p, p->cur.loc, "expected '[' after '@'"); 503 return 0; 504 } 505 bracket_depth = 1; 506 while (p->cur.kind != TOK_EOF && bracket_depth > 0) { 507 if (p->cur.kind == TOK_DOT) { 508 toy_parser_advance(p); 509 if (p->cur.kind == TOK_IDENT && has_static && p->cur.text_len == 6 && 510 memcmp(p->cur.text, "static", 6) == 0) { 511 *has_static = 1; 512 } 513 continue; 514 } 515 if (p->cur.kind == TOK_LBRACKET && paren_depth == 0) 516 bracket_depth++; 517 else if (p->cur.kind == TOK_RBRACKET && paren_depth == 0) 518 bracket_depth--; 519 else if (p->cur.kind == TOK_LPAREN) 520 paren_depth++; 521 else if (p->cur.kind == TOK_RPAREN && paren_depth > 0) 522 paren_depth--; 523 toy_parser_advance(p); 524 } 525 if (bracket_depth != 0) { 526 toy_error(p, p->cur.loc, "unterminated attribute list"); 527 return 0; 528 } 529 return 1; 530 } 531 532 int toy_skip_attr_list(ToyParser* p) { return toy_skip_attr_list_ex(p, NULL); }