type.ha (12644B)
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 ltok::NOMEM => 136 yield builtin_type::NOMEM; 137 case => 138 return syntaxerr(lex::mkloc(lexer), 139 "Unexpected {}, was expecting primitive type", 140 lex::tokstr(tok)); 141 }; 142 return ast::_type { 143 start = tok.2, 144 end = lex::prevloc(lexer), 145 flags = ast::type_flag::NONE, 146 repr = builtin, 147 }; 148 }; 149 150 fn alias_type(lexer: *lex::lexer) (ast::_type | error) = { 151 const start = lex::mkloc(lexer); 152 let unwrap = try(lexer, ltok::ELLIPSIS)? is lex::token; 153 let ident = ident(lexer)?; 154 return ast::_type { 155 start = start, 156 end = lex::prevloc(lexer), 157 flags = 0, 158 repr = ast::alias_type { 159 unwrap = unwrap, 160 ident = ident, 161 }, 162 }; 163 }; 164 165 fn pointer_type(lexer: *lex::lexer) (ast::_type | error) = { 166 const start = lex::mkloc(lexer); 167 let flags = match (try(lexer, ltok::NULLABLE)?) { 168 case void => 169 yield ast::pointer_flag::NONE; 170 case => 171 yield ast::pointer_flag::NULLABLE; 172 }; 173 want(lexer, ltok::TIMES)?; 174 let _type = _type(lexer)?; 175 return ast::_type { 176 start = start, 177 end = lex::prevloc(lexer), 178 flags = ast::type_flag::NONE, 179 repr = ast::pointer_type { 180 referent = alloc(_type)!, 181 flags = flags, 182 }, 183 }; 184 }; 185 186 fn tagged_type( 187 lexer: *lex::lexer, 188 first: ast::_type, 189 start: lex::location 190 ) (ast::_type | error) = { 191 let tagged: ast::tagged_type = []; 192 append(tagged, alloc(first)!)!; 193 for (true) { 194 append(tagged, alloc(_type(lexer)?)!)!; 195 196 match (try(lexer, ltok::BOR)?) { 197 case lex::token => 198 match (try(lexer, ltok::RPAREN)) { 199 case lex::token => break; 200 case => void; 201 }; 202 case void => 203 want(lexer, ltok::RPAREN)?; 204 break; 205 }; 206 }; 207 return ast::_type { 208 start = start, 209 end = lex::prevloc(lexer), 210 flags = ast::type_flag::NONE, 211 repr = tagged, 212 }; 213 }; 214 215 fn tuple_type( 216 lexer: *lex::lexer, 217 first: ast::_type, 218 start: lex::location 219 ) (ast::_type | error) = { 220 let tuple: ast::tuple_type = []; 221 append(tuple, alloc(first)!)!; 222 for (true) { 223 append(tuple, alloc(_type(lexer)?)!)!; 224 match (try(lexer, ltok::COMMA)?) { 225 case lex::token => 226 match (try(lexer, ltok::RPAREN)) { 227 case lex::token => break; 228 case => void; 229 }; 230 case void => 231 want(lexer, ltok::RPAREN)?; 232 break; 233 }; 234 }; 235 return ast::_type { 236 start = start, 237 end = lex::prevloc(lexer), 238 flags = ast::type_flag::NONE, 239 repr = tuple, 240 }; 241 }; 242 243 fn fn_type(lexer: *lex::lexer) (ast::_type | error) = { 244 const start = lex::mkloc(lexer); 245 want(lexer, ltok::FN)?; 246 let proto = prototype(lexer)?; 247 return ast::_type { 248 start = start, 249 end = lex::prevloc(lexer), 250 flags = 0, 251 repr = proto, 252 }; 253 }; 254 255 fn struct_union_type(lexer: *lex::lexer) (ast::_type | error) = { 256 let membs: []ast::struct_member = []; 257 let kind = want(lexer, ltok::STRUCT, ltok::UNION)?; 258 let packed = false; 259 260 if (kind.0 == ltok::STRUCT && try(lexer, ltok::ATTR_PACKED)? is lex::token) { 261 packed = true; 262 }; 263 264 want(lexer, ltok::LBRACE)?; 265 266 for (true) { 267 if (try(lexer, ltok::RBRACE)? is lex::token) { 268 synassert(lex::mkloc(lexer), len(membs) != 0, 269 "Expected field list")?; 270 break; 271 }; 272 273 let comment = ""; 274 275 let offs: nullable *ast::expr = match (try(lexer, ltok::ATTR_OFFSET)?) { 276 case void => 277 yield null; 278 case lex::token => 279 comment = strings::dup(lex::comment(lexer)); 280 want(lexer, ltok::LPAREN)?; 281 let ex = expr(lexer)?; 282 want(lexer, ltok::RPAREN)?; 283 yield alloc(ex)!; 284 }; 285 286 let tok = want(lexer, ltok::NAME, ltok::STRUCT, ltok::UNION)?; 287 if (comment == "") { 288 comment = strings::dup(lex::comment(lexer)); 289 }; 290 switch (tok.0) { 291 case ltok::NAME => 292 lex::unlex(lexer, tok); 293 let memb = struct_embed_or_field(lexer, offs, comment)?; 294 append(membs, memb)!; 295 case ltok::STRUCT, ltok::UNION => 296 lex::unlex(lexer, tok); 297 let subtype = struct_union_type(lexer)?; 298 append(membs, ast::struct_member { 299 _offset = offs, 300 member = alloc(subtype)!, 301 docs = comment, 302 })!; 303 case => abort(); 304 }; 305 306 switch (want(lexer, ltok::RBRACE, ltok::COMMA)?.0) { 307 case ltok::RBRACE => break; 308 case ltok::COMMA => 309 const linecomment = lex::comment(lexer); 310 const docs = &membs[len(membs) - 1].docs; 311 if (linecomment != "" && *docs == "") { 312 *docs = strings::dup(linecomment); 313 free(lexer.comment); 314 lexer.comment = ""; 315 }; 316 case => abort(); 317 }; 318 }; 319 320 return ast::_type { 321 start = kind.2, 322 end = lex::prevloc(lexer), 323 flags = ast::type_flag::NONE, 324 repr = switch (kind.0) { 325 case ltok::STRUCT => 326 yield ast::struct_type { members = membs, packed = packed, ...}; 327 case ltok::UNION => 328 yield membs: ast::union_type; 329 case => abort(); 330 }, 331 }; 332 }; 333 334 fn struct_embed_or_field( 335 lexer: *lex::lexer, 336 offs: nullable *ast::expr, 337 comment: str, 338 ) (ast::struct_member | error) = { 339 // Disambiguates between `name: type` and `identifier` 340 // 341 // struct-union-field 342 // name : type 343 // identifier 344 // 345 // identifier 346 // name 347 // name :: identifier 348 let name = want(lexer, ltok::NAME)?; 349 350 let id: ast::ident = match (try(lexer, ltok::COLON, ltok::DOUBLE_COLON)?) { 351 case void => 352 yield alloc([name.1 as str])!; 353 case let tok: lex::token => 354 yield switch (tok.0) { 355 case ltok::COLON => 356 let field = ast::struct_field { 357 name = name.1 as str, 358 _type = alloc(_type(lexer)?)!, 359 }; 360 return ast::struct_member { 361 _offset = offs, 362 member = field, 363 docs = comment, 364 }; 365 case ltok::DOUBLE_COLON => 366 let id = ident(lexer)?; 367 insert(id[0], name.1 as str)!; 368 yield id; 369 case => abort(); 370 }; 371 }; 372 373 return ast::struct_member { 374 _offset = offs, 375 member = id: ast::struct_alias, 376 docs = comment, 377 }; 378 }; 379 380 fn array_slice_type(lexer: *lex::lexer) (ast::_type | error) = { 381 let start = want(lexer, ltok::LBRACKET)?; 382 383 let length = match (try(lexer, ltok::UNDERSCORE, 384 ltok::TIMES, ltok::RBRACKET)?) { 385 case void => 386 yield alloc(expr(lexer)?)!; 387 case let tok: lex::token => 388 yield switch (tok.0) { 389 case ltok::UNDERSCORE => 390 yield ast::len_contextual; 391 case ltok::TIMES => 392 yield ast::len_unbounded; 393 case ltok::RBRACKET => 394 yield ast::len_slice; 395 case => abort(); 396 }; 397 }; 398 399 if (!(length is ast::len_slice)) { 400 want(lexer, ltok::RBRACKET)?; 401 }; 402 403 let _type = _type(lexer)?; 404 return ast::_type { 405 start = start.2, 406 end = lex::prevloc(lexer), 407 flags = ast::type_flag::NONE, 408 repr = ast::list_type { 409 length = length, 410 members = alloc(_type)!, 411 }, 412 }; 413 }; 414 415 fn enum_type(lexer: *lex::lexer) (ast::_type | error) = { 416 let start = want(lexer, ltok::ENUM)?; 417 418 const storage = match (try(lexer, ltok::LBRACE, ltok::RUNE)?) { 419 case void => 420 let storage = integer_type(lexer)?; 421 want(lexer, ltok::LBRACE)?; 422 yield storage; 423 case let tok: lex::token => 424 yield switch (tok.0) { 425 case ltok::LBRACE => 426 yield builtin_type::INT; 427 case ltok::RUNE => 428 want(lexer, ltok::LBRACE)?; 429 yield builtin_type::RUNE; 430 case => abort(); // unreachable 431 }; 432 }; 433 434 let membs: []ast::enum_field = []; 435 for (true) { 436 if (try(lexer, ltok::RBRACE)? is lex::token) { 437 synassert(lex::mkloc(lexer), len(membs) != 0, 438 "Expected member list")?; 439 break; 440 }; 441 442 const loc = lex::mkloc(lexer); 443 let name = want(lexer, ltok::NAME)?; 444 let comment = strings::dup(lex::comment(lexer)); 445 let value: nullable *ast::expr = 446 if (try(lexer, ltok::EQUAL)? is lex::token) 447 alloc(expr(lexer)?)! 448 else null; 449 450 defer append(membs, ast::enum_field { 451 name = name.1 as str, 452 value = value, 453 loc = loc, 454 docs = comment, 455 })!; 456 457 switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) { 458 case ltok::COMMA => 459 const linecomment = lex::comment(lexer); 460 if (linecomment != "" && comment == "") { 461 free(comment); 462 comment = strings::dup(linecomment); 463 free(lexer.comment); 464 lexer.comment = ""; 465 }; 466 case ltok::RBRACE => break; 467 case => abort(); 468 }; 469 }; 470 471 return ast::_type { 472 start = start.2, 473 end = lex::prevloc(lexer), 474 flags = ast::type_flag::NONE, 475 repr = ast::enum_type { 476 storage = storage, 477 values = membs, 478 }, 479 }; 480 }; 481 482 // Parses a type, e.g. '[]int'. 483 export fn _type(lexer: *lex::lexer) (ast::_type | error) = { 484 let flags = ast::type_flag::NONE; 485 if (try(lexer, ltok::CONST)? is lex::token) { 486 flags |= ast::type_flag::CONST; 487 }; 488 489 if (try(lexer, ltok::LNOT)? is lex::token) { 490 flags |= ast::type_flag::ERROR; 491 }; 492 493 let tok = peek(lexer)? as lex::token; 494 let typ: ast::_type = switch (tok.0) { 495 case ltok::RUNE, ltok::STR, ltok::BOOL, ltok::DONE, ltok::I8, ltok::I16, 496 ltok::I32, ltok::I64, ltok::U8, ltok::U16, ltok::U32, 497 ltok::U64, ltok::INT, ltok::UINT, ltok::UINTPTR, 498 ltok::SIZE, ltok::F32, ltok::F64, ltok::VALIST, 499 ltok::VOID, ltok::OPAQUE, ltok::NEVER, ltok::NOMEM => 500 yield primitive_type(lexer)?; 501 case ltok::ENUM => 502 yield enum_type(lexer)?; 503 case ltok::NULLABLE, ltok::TIMES => 504 yield pointer_type(lexer)?; 505 case ltok::STRUCT, ltok::UNION => 506 yield struct_union_type(lexer)?; 507 case ltok::LBRACKET => 508 yield array_slice_type(lexer)?; 509 case ltok::LPAREN => 510 want(lexer, ltok::LPAREN)?; 511 let t = _type(lexer)?; 512 yield switch (want(lexer, ltok::BOR, ltok::COMMA)?.0) { 513 case ltok::BOR => 514 yield tagged_type(lexer, t, tok.2)?; 515 case ltok::COMMA => 516 yield tuple_type(lexer, t, tok.2)?; 517 case => abort("unreachable"); 518 }; 519 case ltok::FN => 520 yield fn_type(lexer)?; 521 case ltok::ELLIPSIS, ltok::NAME => 522 yield alias_type(lexer)?; 523 case => 524 return syntaxerr(lex::mkloc(lexer), 525 "Unexpected {}, was expecting type", 526 lex::tokstr(tok)); 527 }; 528 529 typ.flags |= flags; 530 return typ; 531 };