attrs.c (13394B)
1 #include <string.h> 2 3 #include "internal.h" 4 5 static void toy_attr_set_init(ToyAttrSet* attrs, KitSymBind default_bind) { 6 memset(attrs, 0, sizeof *attrs); 7 attrs->sym.bind = default_bind; 8 attrs->sym.visibility = KIT_CG_VIS_DEFAULT; 9 attrs->object.tls_model = KIT_CG_TLS_AUTO; 10 attrs->call_conv = KIT_CG_CC_TARGET_C; 11 } 12 13 int toy_parse_attr_dot_name(ToyParser* p, KitSym* out) { 14 if (!toy_parser_expect(p, TOK_DOT) || 15 !(p->cur.kind == TOK_IDENT || 16 (p->cur.kind >= TOK_FN && p->cur.kind <= TOK_INT))) { 17 toy_error(p, p->cur.loc, "expected attribute name"); 18 return 0; 19 } 20 *out = toy_tok_sym(p, p->cur); 21 toy_parser_advance(p); 22 return 1; 23 } 24 25 static int toy_parse_attr_dot_arg(ToyParser* p, KitSym* out) { 26 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_attr_dot_name(p, out) || 27 !toy_parser_expect(p, TOK_RPAREN)) { 28 toy_error(p, p->cur.loc, "expected dot attribute argument"); 29 return 0; 30 } 31 return 1; 32 } 33 34 int toy_parse_attr_int_arg(ToyParser* p, int64_t* out) { 35 if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_number_arg(p, out) || 36 !toy_parser_expect(p, TOK_RPAREN)) { 37 toy_error(p, p->cur.loc, "expected integer attribute argument"); 38 return 0; 39 } 40 return 1; 41 } 42 43 static int toy_parse_attr_string_arg(ToyParser* p, KitSym* out) { 44 if (!toy_parser_expect(p, TOK_LPAREN) || 45 !toy_parse_string_sym(p, out, NULL) || 46 !toy_parser_expect(p, TOK_RPAREN)) { 47 toy_error(p, p->cur.loc, "expected string attribute argument"); 48 return 0; 49 } 50 return 1; 51 } 52 53 int toy_parse_callconv_const(ToyParser* p, KitCgCallConv* out) { 54 static const ToyConstRow rows[] = { 55 {"target_c", KIT_CG_CC_TARGET_C}, {"sysv", KIT_CG_CC_SYSV}, 56 {"win64", KIT_CG_CC_WIN64}, {"aapcs", KIT_CG_CC_AAPCS}, 57 {"wasm", KIT_CG_CC_WASM}, {"interrupt", KIT_CG_CC_INTERRUPT}, 58 }; 59 uint64_t v; 60 if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1, 61 "call convention", "call convention", &v)) 62 return 0; 63 *out = (KitCgCallConv)v; 64 return 1; 65 } 66 67 static int toy_parse_attr_one(ToyParser* p, ToyAttrSet* attrs) { 68 KitSym name; 69 KitSym arg; 70 int64_t int_arg; 71 if (!toy_parse_attr_dot_name(p, &name)) return 0; 72 73 if (toy_sym_is(p, name, "bind")) { 74 attrs->attr_kinds |= TOY_ATTR_SYMBOL; 75 if (!toy_parse_attr_dot_arg(p, &arg)) return 0; 76 if (toy_sym_is(p, arg, "local")) 77 attrs->sym.bind = KIT_SB_LOCAL; 78 else if (toy_sym_is(p, arg, "global")) 79 attrs->sym.bind = KIT_SB_GLOBAL; 80 else if (toy_sym_is(p, arg, "weak")) 81 attrs->sym.bind = KIT_SB_WEAK; 82 else { 83 toy_error(p, p->cur.loc, "unknown bind attribute"); 84 return 0; 85 } 86 return 1; 87 } 88 if (toy_sym_is(p, name, "visibility")) { 89 attrs->attr_kinds |= TOY_ATTR_SYMBOL; 90 if (!toy_parse_attr_dot_arg(p, &arg)) return 0; 91 if (toy_sym_is(p, arg, "default")) 92 attrs->sym.visibility = KIT_CG_VIS_DEFAULT; 93 else if (toy_sym_is(p, arg, "hidden")) 94 attrs->sym.visibility = KIT_CG_VIS_HIDDEN; 95 else if (toy_sym_is(p, arg, "protected")) 96 attrs->sym.visibility = KIT_CG_VIS_PROTECTED; 97 else { 98 toy_error(p, p->cur.loc, "unknown visibility attribute"); 99 return 0; 100 } 101 return 1; 102 } 103 if (toy_sym_is(p, name, "used")) { 104 attrs->attr_kinds |= TOY_ATTR_SYMBOL; 105 attrs->sym.flags |= KIT_CG_SYM_USED; 106 return 1; 107 } 108 if (toy_sym_is(p, name, "dllimport")) { 109 attrs->attr_kinds |= TOY_ATTR_SYMBOL; 110 attrs->sym.flags |= KIT_CG_SYM_DLLIMPORT; 111 return 1; 112 } 113 if (toy_sym_is(p, name, "dllexport")) { 114 attrs->attr_kinds |= TOY_ATTR_SYMBOL; 115 attrs->sym.flags |= KIT_CG_SYM_DLLEXPORT; 116 return 1; 117 } 118 if (toy_sym_is(p, name, "section")) { 119 KitSym section; 120 attrs->attr_kinds |= TOY_ATTR_SECTION; 121 if (!toy_parse_attr_string_arg(p, §ion)) return 0; 122 attrs->func.section = section; 123 attrs->object.section = section; 124 attrs->data.section = section; 125 return 1; 126 } 127 if (toy_sym_is(p, name, "noreturn")) { 128 attrs->attr_kinds |= TOY_ATTR_FUNC; 129 attrs->func.flags |= KIT_CG_FUNC_NORETURN; 130 return 1; 131 } 132 if (toy_sym_is(p, name, "ifunc")) { 133 attrs->attr_kinds |= TOY_ATTR_FUNC; 134 attrs->func.flags |= KIT_CG_FUNC_IFUNC; 135 return 1; 136 } 137 if (toy_sym_is(p, name, "cold")) { 138 attrs->attr_kinds |= TOY_ATTR_FUNC; 139 attrs->func.flags |= KIT_CG_FUNC_COLD; 140 return 1; 141 } 142 if (toy_sym_is(p, name, "hot")) { 143 attrs->attr_kinds |= TOY_ATTR_FUNC; 144 attrs->func.flags |= KIT_CG_FUNC_HOT; 145 return 1; 146 } 147 if (toy_sym_is(p, name, "naked")) { 148 attrs->attr_kinds |= TOY_ATTR_FUNC; 149 attrs->func.flags |= KIT_CG_FUNC_NAKED; 150 return 1; 151 } 152 if (toy_sym_is(p, name, "interrupt")) { 153 attrs->attr_kinds |= TOY_ATTR_FUNC; 154 attrs->func.flags |= KIT_CG_FUNC_INTERRUPT; 155 return 1; 156 } 157 if (toy_sym_is(p, name, "no_red_zone")) { 158 attrs->attr_kinds |= TOY_ATTR_FUNC; 159 attrs->func.flags |= KIT_CG_FUNC_NO_RED_ZONE; 160 return 1; 161 } 162 if (toy_sym_is(p, name, "inline")) { 163 attrs->attr_kinds |= TOY_ATTR_FUNC; 164 attrs->func.inline_policy = KIT_CG_INLINE_HINT; 165 return 1; 166 } 167 if (toy_sym_is(p, name, "always_inline")) { 168 attrs->attr_kinds |= TOY_ATTR_FUNC; 169 attrs->func.inline_policy = KIT_CG_INLINE_ALWAYS; 170 return 1; 171 } 172 if (toy_sym_is(p, name, "noinline")) { 173 attrs->attr_kinds |= TOY_ATTR_FUNC; 174 attrs->func.inline_policy = KIT_CG_INLINE_NEVER; 175 return 1; 176 } 177 if (toy_sym_is(p, name, "stack_align")) { 178 attrs->attr_kinds |= TOY_ATTR_FUNC; 179 if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0; 180 attrs->func.stack_align = (uint32_t)int_arg; 181 return 1; 182 } 183 if (toy_sym_is(p, name, "target_features")) { 184 attrs->attr_kinds |= TOY_ATTR_FUNC; 185 if (!toy_parse_attr_string_arg(p, &attrs->func.target_features)) return 0; 186 return 1; 187 } 188 if (toy_sym_is(p, name, "callconv")) { 189 attrs->attr_kinds |= TOY_ATTR_FUNC; 190 if (!toy_parser_expect(p, TOK_LPAREN) || 191 !toy_parse_callconv_const(p, &attrs->call_conv) || 192 !toy_parser_expect(p, TOK_RPAREN)) { 193 toy_error(p, p->cur.loc, "expected callconv attribute argument"); 194 return 0; 195 } 196 attrs->has_call_conv = 1; 197 return 1; 198 } 199 if (toy_sym_is(p, name, "align")) { 200 attrs->attr_kinds |= TOY_ATTR_OBJECT_DATA; 201 if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0; 202 attrs->object.align = (uint32_t)int_arg; 203 attrs->data.align = (uint32_t)int_arg; 204 return 1; 205 } 206 if (toy_sym_is(p, name, "readonly")) { 207 attrs->attr_kinds |= TOY_ATTR_OBJECT_DATA; 208 attrs->object.flags |= KIT_CG_OBJ_READONLY; 209 attrs->data.flags |= KIT_CG_DATADEF_READONLY; 210 return 1; 211 } 212 if (toy_sym_is(p, name, "threadlocal")) { 213 attrs->attr_kinds |= TOY_ATTR_OBJECT; 214 attrs->object.flags |= KIT_CG_OBJ_TLS; 215 return 1; 216 } 217 if (toy_sym_is(p, name, "tls_model")) { 218 attrs->attr_kinds |= TOY_ATTR_OBJECT; 219 if (!toy_parse_attr_dot_arg(p, &arg)) return 0; 220 if (toy_sym_is(p, arg, "auto")) 221 attrs->object.tls_model = KIT_CG_TLS_AUTO; 222 else if (toy_sym_is(p, arg, "local_exec")) 223 attrs->object.tls_model = KIT_CG_TLS_LOCAL_EXEC; 224 else if (toy_sym_is(p, arg, "initial_exec")) 225 attrs->object.tls_model = KIT_CG_TLS_INITIAL_EXEC; 226 else if (toy_sym_is(p, arg, "local_dynamic")) 227 attrs->object.tls_model = KIT_CG_TLS_LOCAL_DYNAMIC; 228 else if (toy_sym_is(p, arg, "general_dynamic")) 229 attrs->object.tls_model = KIT_CG_TLS_GENERAL_DYNAMIC; 230 else { 231 toy_error(p, p->cur.loc, "unknown tls_model attribute"); 232 return 0; 233 } 234 return 1; 235 } 236 if (toy_sym_is(p, name, "static")) { 237 attrs->attr_kinds |= TOY_ATTR_OBJECT; 238 attrs->has_static = 1; 239 return 1; 240 } 241 if (toy_sym_is(p, name, "common")) { 242 attrs->attr_kinds |= TOY_ATTR_OBJECT; 243 attrs->is_common = 1; 244 return 1; 245 } 246 if (toy_sym_is(p, name, "retain")) { 247 attrs->attr_kinds |= TOY_ATTR_DATA; 248 attrs->data.flags |= KIT_CG_DATADEF_RETAIN; 249 return 1; 250 } 251 if (toy_sym_is(p, name, "merge")) { 252 attrs->attr_kinds |= TOY_ATTR_DATA; 253 attrs->data.flags |= KIT_CG_DATADEF_MERGE; 254 return 1; 255 } 256 if (toy_sym_is(p, name, "strings")) { 257 attrs->attr_kinds |= TOY_ATTR_DATA; 258 attrs->data.flags |= KIT_CG_DATADEF_STRINGS; 259 return 1; 260 } 261 if (toy_sym_is(p, name, "entsize")) { 262 attrs->attr_kinds |= TOY_ATTR_DATA; 263 if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0; 264 attrs->data.entsize = (uint32_t)int_arg; 265 return 1; 266 } 267 268 toy_error(p, p->cur.loc, "unknown attribute"); 269 return 0; 270 } 271 272 int toy_parse_attr_list(ToyParser* p, ToyAttrSet* attrs, 273 KitSymBind default_bind) { 274 toy_attr_set_init(attrs, default_bind); 275 if (!toy_parser_match(p, TOK_AT)) return 1; 276 if (!toy_parser_expect(p, TOK_LBRACKET)) { 277 toy_error(p, p->cur.loc, "expected '[' after '@'"); 278 return 0; 279 } 280 while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) { 281 if (!toy_parse_attr_one(p, attrs)) return 0; 282 if (!toy_parser_match(p, TOK_COMMA)) break; 283 } 284 if (!toy_parser_expect(p, TOK_RBRACKET)) { 285 toy_error(p, p->cur.loc, "expected ']' after attribute list"); 286 return 0; 287 } 288 return 1; 289 } 290 291 int toy_validate_attr_placement(ToyParser* p, const ToyAttrSet* attrs, 292 uint32_t allowed, const char* message) { 293 if (attrs->attr_kinds & ~allowed) { 294 toy_error(p, p->cur.loc, message); 295 return 0; 296 } 297 return 1; 298 } 299 300 static int toy_parse_abi_attr_one(ToyParser* p, KitCgAbiAttrs* attrs) { 301 KitSym name; 302 int64_t int_arg; 303 if (!toy_parse_attr_dot_name(p, &name)) return 0; 304 if (toy_sym_is(p, name, "signext")) 305 attrs->flags |= KIT_CG_ABI_SIGNEXT; 306 else if (toy_sym_is(p, name, "zeroext")) 307 attrs->flags |= KIT_CG_ABI_ZEROEXT; 308 else if (toy_sym_is(p, name, "sret")) 309 attrs->flags |= KIT_CG_ABI_SRET; 310 else if (toy_sym_is(p, name, "byval")) 311 attrs->flags |= KIT_CG_ABI_BYVAL; 312 else if (toy_sym_is(p, name, "byref")) 313 attrs->flags |= KIT_CG_ABI_BYREF; 314 else if (toy_sym_is(p, name, "inreg")) 315 attrs->flags |= KIT_CG_ABI_INREG; 316 else if (toy_sym_is(p, name, "noalias")) 317 attrs->flags |= KIT_CG_ABI_NOALIAS; 318 else if (toy_sym_is(p, name, "readonly")) 319 attrs->flags |= KIT_CG_ABI_READONLY; 320 else if (toy_sym_is(p, name, "writeonly")) 321 attrs->flags |= KIT_CG_ABI_WRITEONLY; 322 else if (toy_sym_is(p, name, "nonnull")) 323 attrs->flags |= KIT_CG_ABI_NONNULL; 324 else if (toy_sym_is(p, name, "nest")) 325 attrs->flags |= KIT_CG_ABI_NEST; 326 else if (toy_sym_is(p, name, "align")) { 327 if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0; 328 attrs->align = (uint32_t)int_arg; 329 } else if (toy_sym_is(p, name, "dereferenceable")) { 330 if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0; 331 attrs->dereferenceable_size = (uint64_t)int_arg; 332 } else { 333 toy_error(p, p->cur.loc, "unknown ABI attribute"); 334 return 0; 335 } 336 return 1; 337 } 338 339 int toy_parse_abi_attr_list(ToyParser* p, KitCgAbiAttrs* attrs) { 340 memset(attrs, 0, sizeof *attrs); 341 if (!toy_parser_match(p, TOK_AT)) return 1; 342 if (!toy_parser_expect(p, TOK_LBRACKET)) { 343 toy_error(p, p->cur.loc, "expected '[' after '@'"); 344 return 0; 345 } 346 while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) { 347 if (!toy_parse_abi_attr_one(p, attrs)) return 0; 348 if (!toy_parser_match(p, TOK_COMMA)) break; 349 } 350 if (!toy_parser_expect(p, TOK_RBRACKET)) { 351 toy_error(p, p->cur.loc, "expected ']' after ABI attribute list"); 352 return 0; 353 } 354 return 1; 355 } 356 357 int toy_parse_field_attr_list(ToyParser* p, KitCgField* field) { 358 if (!toy_parser_match(p, TOK_AT)) return 1; 359 if (!toy_parser_expect(p, TOK_LBRACKET)) { 360 toy_error(p, p->cur.loc, "expected '[' after '@'"); 361 return 0; 362 } 363 while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) { 364 KitSym name; 365 int64_t int_arg; 366 if (!toy_parse_attr_dot_name(p, &name)) return 0; 367 if (toy_sym_is(p, name, "align")) { 368 if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0; 369 field->align_override = (uint32_t)int_arg; 370 } else if (toy_sym_is(p, name, "packed")) { 371 field->align_override = 1; 372 } else { 373 toy_error(p, p->cur.loc, "unknown field attribute"); 374 return 0; 375 } 376 if (!toy_parser_match(p, TOK_COMMA)) break; 377 } 378 if (!toy_parser_expect(p, TOK_RBRACKET)) { 379 toy_error(p, p->cur.loc, "expected ']' after field attribute list"); 380 return 0; 381 } 382 return 1; 383 } 384 385 int toy_parse_record_attr_list(ToyParser* p, int* packed_out, 386 uint32_t* align_out) { 387 *packed_out = 0; 388 *align_out = 0; 389 if (!toy_parser_match(p, TOK_AT)) return 1; 390 if (!toy_parser_expect(p, TOK_LBRACKET)) { 391 toy_error(p, p->cur.loc, "expected '[' after '@'"); 392 return 0; 393 } 394 while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) { 395 KitSym name; 396 int64_t int_arg; 397 if (!toy_parse_attr_dot_name(p, &name)) return 0; 398 if (toy_sym_is(p, name, "packed")) { 399 *packed_out = 1; 400 } else if (toy_sym_is(p, name, "align")) { 401 if (!toy_parse_attr_int_arg(p, &int_arg) || int_arg < 0) return 0; 402 *align_out = (uint32_t)int_arg; 403 } else { 404 toy_error(p, p->cur.loc, "unknown record attribute"); 405 return 0; 406 } 407 if (!toy_parser_match(p, TOK_COMMA)) break; 408 } 409 if (!toy_parser_expect(p, TOK_RBRACKET)) { 410 toy_error(p, p->cur.loc, "expected ']' after record attribute list"); 411 return 0; 412 } 413 return 1; 414 }