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