type.ha (12555B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use hare::ast; 5 use hare::ast::{builtin_type}; 6 use hare::lex; 7 use hare::lex::{ltok}; 8 use strings; 9 10 fn prototype(lexer: *lex::lexer) (ast::func_type | error) = { 11 let variadism = ast::variadism::NONE; 12 let params: []ast::func_param = []; 13 want(lexer, ltok::LPAREN)?; 14 for (try(lexer, ltok::RPAREN)? is void) { 15 let loc = lex::mkloc(lexer); 16 match (try(lexer, ltok::ELLIPSIS)?) { 17 case lex::token => 18 variadism = ast::variadism::C; 19 want(lexer, ltok::RPAREN)?; 20 break; 21 case void => void; 22 }; 23 24 let name_or_type = _type(lexer)?; 25 match (try(lexer, ltok::COLON)?) { 26 case void => 27 append(params, ast::func_param { 28 loc = loc, 29 name = "", 30 _type = alloc(name_or_type), 31 default_value = void, 32 }); 33 case lex::token => 34 // Bit of a hack because we can't unlex twice. 35 synassert(loc, name_or_type.repr is ast::alias_type, 36 "Invalid parameter name")?; 37 let ns = (name_or_type.repr as ast::alias_type).ident; 38 synassert(loc, len(ns) == 1, "Invalid parameter name")?; 39 append(params, ast::func_param { 40 loc = loc, 41 name = ns[0], 42 _type = alloc(_type(lexer)?), 43 default_value = void, 44 }); 45 }; 46 match (try(lexer, ltok::EQUAL)?) { 47 case void => 48 yield void; 49 case lex::token => 50 params[len(params) - 1].default_value = expr(lexer)?; 51 }; 52 match (try(lexer, ltok::ELLIPSIS)?) { 53 case lex::token => 54 variadism = ast::variadism::HARE; 55 want(lexer, ltok::RPAREN)?; 56 break; 57 case void => void; 58 }; 59 match (try(lexer, ltok::COMMA)?) { 60 case void => 61 want(lexer, ltok::RPAREN)?; 62 break; 63 case lex::token => void; 64 }; 65 }; 66 let t = _type(lexer)?; 67 return ast::func_type { 68 result = alloc(t), 69 variadism = variadism, 70 params = params, 71 }; 72 }; 73 74 fn integer_type( 75 lexer: *lex::lexer, 76 ) (builtin_type | error) = { 77 switch (want(lexer)?.0) { 78 case ltok::INT => 79 return builtin_type::INT; 80 case ltok::I8 => 81 return builtin_type::I8; 82 case ltok::I16 => 83 return builtin_type::I16; 84 case ltok::I32 => 85 return builtin_type::I32; 86 case ltok::I64 => 87 return builtin_type::I64; 88 case ltok::SIZE => 89 return builtin_type::SIZE; 90 case ltok::UINT => 91 return builtin_type::UINT; 92 case ltok::UINTPTR => 93 return builtin_type::UINTPTR; 94 case ltok::U8 => 95 return builtin_type::U8; 96 case ltok::U16 => 97 return builtin_type::U16; 98 case ltok::U32 => 99 return builtin_type::U32; 100 case ltok::U64 => 101 return builtin_type::U64; 102 case => 103 return syntaxerr(lex::mkloc(lexer), "Expected integer type"); 104 }; 105 }; 106 107 fn primitive_type(lexer: *lex::lexer) (ast::_type | error) = { 108 let tok = want(lexer)?; 109 let builtin = switch (tok.0) { 110 case ltok::I8, ltok::I16, ltok::I32, ltok::I64, 111 ltok::INT, ltok::UINT, ltok::UINTPTR, ltok::SIZE, 112 ltok::U8, ltok::U16, ltok::U32, ltok::U64 => 113 lex::unlex(lexer, tok); 114 yield integer_type(lexer)?; 115 case ltok::RUNE => 116 yield builtin_type::RUNE; 117 case ltok::STR => 118 yield builtin_type::STR; 119 case ltok::F32 => 120 yield builtin_type::F32; 121 case ltok::F64 => 122 yield builtin_type::F64; 123 case ltok::BOOL => 124 yield builtin_type::BOOL; 125 case ltok::DONE => 126 yield builtin_type::DONE; 127 case ltok::VALIST => 128 yield builtin_type::VALIST; 129 case ltok::VOID => 130 yield builtin_type::VOID; 131 case ltok::OPAQUE => 132 yield builtin_type::OPAQUE; 133 case ltok::NEVER => 134 yield builtin_type::NEVER; 135 case => 136 return syntaxerr(lex::mkloc(lexer), 137 "Unexected {}, was expecting primitive type", 138 lex::tokstr(tok)); 139 }; 140 return ast::_type { 141 start = tok.2, 142 end = lex::prevloc(lexer), 143 flags = ast::type_flag::NONE, 144 repr = builtin, 145 }; 146 }; 147 148 fn alias_type(lexer: *lex::lexer) (ast::_type | error) = { 149 const start = lex::mkloc(lexer); 150 let unwrap = try(lexer, ltok::ELLIPSIS)? is lex::token; 151 let ident = ident(lexer)?; 152 return ast::_type { 153 start = start, 154 end = lex::prevloc(lexer), 155 flags = 0, 156 repr = ast::alias_type { 157 unwrap = unwrap, 158 ident = ident, 159 }, 160 }; 161 }; 162 163 fn pointer_type(lexer: *lex::lexer) (ast::_type | error) = { 164 const start = lex::mkloc(lexer); 165 let flags = match (try(lexer, ltok::NULLABLE)?) { 166 case void => 167 yield ast::pointer_flag::NONE; 168 case => 169 yield ast::pointer_flag::NULLABLE; 170 }; 171 want(lexer, ltok::TIMES)?; 172 let _type = _type(lexer)?; 173 return ast::_type { 174 start = start, 175 end = lex::prevloc(lexer), 176 flags = ast::type_flag::NONE, 177 repr = ast::pointer_type { 178 referent = alloc(_type), 179 flags = flags, 180 }, 181 }; 182 }; 183 184 fn tagged_type( 185 lexer: *lex::lexer, 186 first: ast::_type, 187 start: lex::location 188 ) (ast::_type | error) = { 189 let tagged: ast::tagged_type = []; 190 append(tagged, alloc(first)); 191 for (true) { 192 append(tagged, alloc(_type(lexer)?)); 193 194 match (try(lexer, ltok::BOR)?) { 195 case lex::token => 196 match (try(lexer, ltok::RPAREN)) { 197 case lex::token => break; 198 case => void; 199 }; 200 case void => 201 want(lexer, ltok::RPAREN)?; 202 break; 203 }; 204 }; 205 return ast::_type { 206 start = start, 207 end = lex::prevloc(lexer), 208 flags = ast::type_flag::NONE, 209 repr = tagged, 210 }; 211 }; 212 213 fn tuple_type( 214 lexer: *lex::lexer, 215 first: ast::_type, 216 start: lex::location 217 ) (ast::_type | error) = { 218 let tuple: ast::tuple_type = []; 219 append(tuple, alloc(first)); 220 for (true) { 221 append(tuple, alloc(_type(lexer)?)); 222 match (try(lexer, ltok::COMMA)?) { 223 case lex::token => 224 match (try(lexer, ltok::RPAREN)) { 225 case lex::token => break; 226 case => void; 227 }; 228 case void => 229 want(lexer, ltok::RPAREN)?; 230 break; 231 }; 232 }; 233 return ast::_type { 234 start = start, 235 end = lex::prevloc(lexer), 236 flags = ast::type_flag::NONE, 237 repr = tuple, 238 }; 239 }; 240 241 fn fn_type(lexer: *lex::lexer) (ast::_type | error) = { 242 const start = lex::mkloc(lexer); 243 want(lexer, ltok::FN)?; 244 let proto = prototype(lexer)?; 245 return ast::_type { 246 start = start, 247 end = lex::prevloc(lexer), 248 flags = 0, 249 repr = proto, 250 }; 251 }; 252 253 fn struct_union_type(lexer: *lex::lexer) (ast::_type | error) = { 254 let membs: []ast::struct_member = []; 255 let kind = want(lexer, ltok::STRUCT, ltok::UNION)?; 256 let packed = false; 257 258 if (kind.0 == ltok::STRUCT && try(lexer, ltok::ATTR_PACKED)? is lex::token) { 259 packed = true; 260 }; 261 262 want(lexer, ltok::LBRACE)?; 263 264 for (true) { 265 if (try(lexer, ltok::RBRACE)? is lex::token) { 266 synassert(lex::mkloc(lexer), len(membs) != 0, 267 "Expected field list")?; 268 break; 269 }; 270 271 let comment = ""; 272 273 let offs: nullable *ast::expr = match (try(lexer, ltok::ATTR_OFFSET)?) { 274 case void => 275 yield null; 276 case lex::token => 277 comment = strings::dup(lex::comment(lexer)); 278 want(lexer, ltok::LPAREN)?; 279 let ex = expr(lexer)?; 280 want(lexer, ltok::RPAREN)?; 281 yield alloc(ex); 282 }; 283 284 let tok = want(lexer, ltok::NAME, ltok::STRUCT, ltok::UNION)?; 285 if (comment == "") { 286 comment = strings::dup(lex::comment(lexer)); 287 }; 288 switch (tok.0) { 289 case ltok::NAME => 290 lex::unlex(lexer, tok); 291 let memb = struct_embed_or_field(lexer, offs, comment)?; 292 append(membs, memb); 293 case ltok::STRUCT, ltok::UNION => 294 lex::unlex(lexer, tok); 295 let subtype = struct_union_type(lexer)?; 296 append(membs, ast::struct_member { 297 _offset = offs, 298 member = alloc(subtype), 299 docs = comment, 300 }); 301 case => abort(); 302 }; 303 304 switch (want(lexer, ltok::RBRACE, ltok::COMMA)?.0) { 305 case ltok::RBRACE => break; 306 case ltok::COMMA => 307 const linecomment = lex::comment(lexer); 308 const docs = &membs[len(membs) - 1].docs; 309 if (linecomment != "" && *docs == "") { 310 *docs = strings::dup(linecomment); 311 free(lexer.comment); 312 lexer.comment = ""; 313 }; 314 case => abort(); 315 }; 316 }; 317 318 return ast::_type { 319 start = kind.2, 320 end = lex::prevloc(lexer), 321 flags = ast::type_flag::NONE, 322 repr = switch (kind.0) { 323 case ltok::STRUCT => 324 yield ast::struct_type { members = membs, packed = packed, ...}; 325 case ltok::UNION => 326 yield membs: ast::union_type; 327 case => abort(); 328 }, 329 }; 330 }; 331 332 fn struct_embed_or_field( 333 lexer: *lex::lexer, 334 offs: nullable *ast::expr, 335 comment: str, 336 ) (ast::struct_member | error) = { 337 // Disambiguates between `name: type` and `identifier` 338 // 339 // struct-union-field 340 // name : type 341 // identifier 342 // 343 // identifier 344 // name 345 // name :: identifier 346 let name = want(lexer, ltok::NAME)?; 347 348 let id: ast::ident = match (try(lexer, ltok::COLON, ltok::DOUBLE_COLON)?) { 349 case void => 350 yield alloc([name.1 as str]); 351 case let tok: lex::token => 352 yield switch (tok.0) { 353 case ltok::COLON => 354 let field = ast::struct_field { 355 name = name.1 as str, 356 _type = alloc(_type(lexer)?), 357 }; 358 return ast::struct_member { 359 _offset = offs, 360 member = field, 361 docs = comment, 362 }; 363 case ltok::DOUBLE_COLON => 364 let id = ident(lexer)?; 365 insert(id[0], name.1 as str); 366 yield id; 367 case => abort(); 368 }; 369 }; 370 371 return ast::struct_member { 372 _offset = offs, 373 member = id: ast::struct_alias, 374 docs = comment, 375 }; 376 }; 377 378 fn array_slice_type(lexer: *lex::lexer) (ast::_type | error) = { 379 let start = want(lexer, ltok::LBRACKET)?; 380 381 let length = match (try(lexer, ltok::UNDERSCORE, 382 ltok::TIMES, ltok::RBRACKET)?) { 383 case void => 384 yield alloc(expr(lexer)?); 385 case let tok: lex::token => 386 yield switch (tok.0) { 387 case ltok::UNDERSCORE => 388 yield ast::len_contextual; 389 case ltok::TIMES => 390 yield ast::len_unbounded; 391 case ltok::RBRACKET => 392 yield ast::len_slice; 393 case => abort(); 394 }; 395 }; 396 397 if (!(length is ast::len_slice)) { 398 want(lexer, ltok::RBRACKET)?; 399 }; 400 401 let _type = _type(lexer)?; 402 return ast::_type { 403 start = start.2, 404 end = lex::prevloc(lexer), 405 flags = ast::type_flag::NONE, 406 repr = ast::list_type { 407 length = length, 408 members = alloc(_type), 409 }, 410 }; 411 }; 412 413 fn enum_type(lexer: *lex::lexer) (ast::_type | error) = { 414 let start = want(lexer, ltok::ENUM)?; 415 416 const storage = match (try(lexer, ltok::LBRACE, ltok::RUNE)?) { 417 case void => 418 let storage = integer_type(lexer)?; 419 want(lexer, ltok::LBRACE)?; 420 yield storage; 421 case let tok: lex::token => 422 yield switch (tok.0) { 423 case ltok::LBRACE => 424 yield builtin_type::INT; 425 case ltok::RUNE => 426 want(lexer, ltok::LBRACE)?; 427 yield builtin_type::RUNE; 428 case => abort(); // unreachable 429 }; 430 }; 431 432 let membs: []ast::enum_field = []; 433 for (true) { 434 if (try(lexer, ltok::RBRACE)? is lex::token) { 435 synassert(lex::mkloc(lexer), len(membs) != 0, 436 "Expected member list")?; 437 break; 438 }; 439 440 const loc = lex::mkloc(lexer); 441 let name = want(lexer, ltok::NAME)?; 442 let comment = strings::dup(lex::comment(lexer)); 443 let value: nullable *ast::expr = 444 if (try(lexer, ltok::EQUAL)? is lex::token) 445 alloc(expr(lexer)?) 446 else null; 447 448 defer append(membs, ast::enum_field { 449 name = name.1 as str, 450 value = value, 451 loc = loc, 452 docs = comment, 453 }); 454 455 switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) { 456 case ltok::COMMA => 457 const linecomment = lex::comment(lexer); 458 if (linecomment != "" && comment == "") { 459 free(comment); 460 comment = strings::dup(linecomment); 461 free(lexer.comment); 462 lexer.comment = ""; 463 }; 464 case ltok::RBRACE => break; 465 case => abort(); 466 }; 467 }; 468 469 return ast::_type { 470 start = start.2, 471 end = lex::prevloc(lexer), 472 flags = ast::type_flag::NONE, 473 repr = ast::enum_type { 474 storage = storage, 475 values = membs, 476 }, 477 }; 478 }; 479 480 // Parses a type, e.g. '[]int'. 481 export fn _type(lexer: *lex::lexer) (ast::_type | error) = { 482 let flags = ast::type_flag::NONE; 483 if (try(lexer, ltok::CONST)? is lex::token) { 484 flags |= ast::type_flag::CONST; 485 }; 486 487 if (try(lexer, ltok::LNOT)? is lex::token) { 488 flags |= ast::type_flag::ERROR; 489 }; 490 491 let tok = peek(lexer)? as lex::token; 492 let typ: ast::_type = switch (tok.0) { 493 case ltok::RUNE, ltok::STR, ltok::BOOL, ltok::DONE, ltok::I8, ltok::I16, 494 ltok::I32, ltok::I64, ltok::U8, ltok::U16, ltok::U32, 495 ltok::U64, ltok::INT, ltok::UINT, ltok::UINTPTR, 496 ltok::SIZE, ltok::F32, ltok::F64, ltok::VALIST, 497 ltok::VOID, ltok::OPAQUE, ltok::NEVER => 498 yield primitive_type(lexer)?; 499 case ltok::ENUM => 500 yield enum_type(lexer)?; 501 case ltok::NULLABLE, ltok::TIMES => 502 yield pointer_type(lexer)?; 503 case ltok::STRUCT, ltok::UNION => 504 yield struct_union_type(lexer)?; 505 case ltok::LBRACKET => 506 yield array_slice_type(lexer)?; 507 case ltok::LPAREN => 508 want(lexer, ltok::LPAREN)?; 509 let t = _type(lexer)?; 510 yield switch (want(lexer, ltok::BOR, ltok::COMMA)?.0) { 511 case ltok::BOR => 512 yield tagged_type(lexer, t, tok.2)?; 513 case ltok::COMMA => 514 yield tuple_type(lexer, t, tok.2)?; 515 case => abort("unreachable"); 516 }; 517 case ltok::FN => 518 yield fn_type(lexer)?; 519 case ltok::ELLIPSIS, ltok::NAME => 520 yield alias_type(lexer)?; 521 case => 522 return syntaxerr(lex::mkloc(lexer), 523 "Unexpected {}, was expecting type", 524 lex::tokstr(tok)); 525 }; 526 527 typ.flags |= flags; 528 return typ; 529 };