| author | |
| committer | |
| log | 3ef2f7058b0bbe2c81f79f990398aaab2e5a7a2f |
| tree | d5c6033ff111ff126dc14844ee85edbc0a0828b9 |
| parent | d4b8852d784b6f180e5329efa8d418397ee7f1ef |
7 files changed, 1345 insertions(+), 1103 deletions(-)
src/all_types.hpp created+928| ... | ... | @@ -0,0 +1,928 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2015 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | #ifndef ZIG_ALL_TYPES_HPP | |
| 9 | #define ZIG_ALL_TYPES_HPP | |
| 10 | ||
| 11 | #include "list.hpp" | |
| 12 | #include "buffer.hpp" | |
| 13 | #include "zig_llvm.hpp" | |
| 14 | #include "hash_map.hpp" | |
| 15 | #include "errmsg.hpp" | |
| 16 | ||
| 17 | struct AstNode; | |
| 18 | struct ImportTableEntry; | |
| 19 | struct AsmToken; | |
| 20 | struct FnTableEntry; | |
| 21 | struct BlockContext; | |
| 22 | struct TypeTableEntry; | |
| 23 | struct VariableTableEntry; | |
| 24 | struct Cast; | |
| 25 | struct BuiltinFnEntry; | |
| 26 | struct LabelTableEntry; | |
| 27 | struct TypeStructField; | |
| 28 | struct CodeGen; | |
| 29 | ||
| 30 | enum OutType { | |
| 31 | OutTypeUnknown, | |
| 32 | OutTypeExe, | |
| 33 | OutTypeLib, | |
| 34 | OutTypeObj, | |
| 35 | }; | |
| 36 | ||
| 37 | enum CodeGenBuildType { | |
| 38 | CodeGenBuildTypeDebug, | |
| 39 | CodeGenBuildTypeRelease, | |
| 40 | }; | |
| 41 | ||
| 42 | enum CastOp { | |
| 43 | CastOpNothing, | |
| 44 | CastOpPtrToInt, | |
| 45 | CastOpIntWidenOrShorten, | |
| 46 | CastOpToUnknownSizeArray, | |
| 47 | CastOpMaybeWrap, | |
| 48 | CastOpPointerReinterpret, | |
| 49 | }; | |
| 50 | ||
| 51 | struct Cast { | |
| 52 | CastOp op; | |
| 53 | // if op is CastOpArrayToString, this will be a pointer to | |
| 54 | // the string struct on the stack | |
| 55 | LLVMValueRef ptr; | |
| 56 | TypeTableEntry *after_type; | |
| 57 | AstNode *source_node; | |
| 58 | }; | |
| 59 | ||
| 60 | struct Expr { | |
| 61 | TypeTableEntry *type_entry; | |
| 62 | // the context in which this expression is evaluated. | |
| 63 | // for blocks, this points to the containing scope, not the block's own scope for its children. | |
| 64 | BlockContext *block_context; | |
| 65 | ||
| 66 | // may be null for no cast | |
| 67 | Cast implicit_cast; // happens first | |
| 68 | Cast implicit_maybe_cast; // happens second | |
| 69 | }; | |
| 70 | ||
| 71 | struct NumLitCodeGen { | |
| 72 | TypeTableEntry *resolved_type; | |
| 73 | }; | |
| 74 | ||
| 75 | struct StructValExprCodeGen { | |
| 76 | TypeTableEntry *type_entry; | |
| 77 | LLVMValueRef ptr; | |
| 78 | AstNode *source_node; | |
| 79 | }; | |
| 80 | ||
| 81 | struct TopLevelDecl { | |
| 82 | // reminder: hash tables must be initialized before use | |
| 83 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> deps; | |
| 84 | Buf *name; | |
| 85 | ImportTableEntry *import; | |
| 86 | // set this flag temporarily to detect infinite loops | |
| 87 | bool in_current_deps; | |
| 88 | }; | |
| 89 | ||
| 90 | enum NodeType { | |
| 91 | NodeTypeRoot, | |
| 92 | NodeTypeRootExportDecl, | |
| 93 | NodeTypeFnProto, | |
| 94 | NodeTypeFnDef, | |
| 95 | NodeTypeFnDecl, | |
| 96 | NodeTypeParamDecl, | |
| 97 | NodeTypeType, | |
| 98 | NodeTypeBlock, | |
| 99 | NodeTypeExternBlock, | |
| 100 | NodeTypeDirective, | |
| 101 | NodeTypeReturnExpr, | |
| 102 | NodeTypeVariableDeclaration, | |
| 103 | NodeTypeBinOpExpr, | |
| 104 | NodeTypeCastExpr, | |
| 105 | NodeTypeNumberLiteral, | |
| 106 | NodeTypeStringLiteral, | |
| 107 | NodeTypeCharLiteral, | |
| 108 | NodeTypeUnreachable, | |
| 109 | NodeTypeSymbol, | |
| 110 | NodeTypePrefixOpExpr, | |
| 111 | NodeTypeFnCallExpr, | |
| 112 | NodeTypeArrayAccessExpr, | |
| 113 | NodeTypeSliceExpr, | |
| 114 | NodeTypeFieldAccessExpr, | |
| 115 | NodeTypeUse, | |
| 116 | NodeTypeVoid, | |
| 117 | NodeTypeBoolLiteral, | |
| 118 | NodeTypeNullLiteral, | |
| 119 | NodeTypeIfBoolExpr, | |
| 120 | NodeTypeIfVarExpr, | |
| 121 | NodeTypeWhileExpr, | |
| 122 | NodeTypeLabel, | |
| 123 | NodeTypeGoto, | |
| 124 | NodeTypeBreak, | |
| 125 | NodeTypeContinue, | |
| 126 | NodeTypeAsmExpr, | |
| 127 | NodeTypeStructDecl, | |
| 128 | NodeTypeStructField, | |
| 129 | NodeTypeStructValueExpr, | |
| 130 | NodeTypeStructValueField, | |
| 131 | NodeTypeEnumDecl, | |
| 132 | NodeTypeEnumField, | |
| 133 | NodeTypeCompilerFnExpr, | |
| 134 | NodeTypeCompilerFnType, | |
| 135 | }; | |
| 136 | ||
| 137 | struct AstNodeRoot { | |
| 138 | ZigList<AstNode *> top_level_decls; | |
| 139 | }; | |
| 140 | ||
| 141 | enum VisibMod { | |
| 142 | VisibModPrivate, | |
| 143 | VisibModPub, | |
| 144 | VisibModExport, | |
| 145 | }; | |
| 146 | ||
| 147 | struct AstNodeFnProto { | |
| 148 | ZigList<AstNode *> *directives; | |
| 149 | VisibMod visib_mod; | |
| 150 | Buf name; | |
| 151 | ZigList<AstNode *> params; | |
| 152 | AstNode *return_type; | |
| 153 | bool is_var_args; | |
| 154 | ||
| 155 | // populated by semantic analyzer: | |
| 156 | ||
| 157 | // the extern block this fn proto is inside. can be null. | |
| 158 | AstNode *extern_node; | |
| 159 | // the struct decl node this fn proto is inside. can be null. | |
| 160 | AstNode *struct_node; | |
| 161 | // the function definition this fn proto is inside. can be null. | |
| 162 | AstNode *fn_def_node; | |
| 163 | FnTableEntry *fn_table_entry; | |
| 164 | bool skip; | |
| 165 | TopLevelDecl top_level_decl; | |
| 166 | }; | |
| 167 | ||
| 168 | struct AstNodeFnDef { | |
| 169 | AstNode *fn_proto; | |
| 170 | AstNode *body; | |
| 171 | ||
| 172 | // populated by semantic analyzer | |
| 173 | TypeTableEntry *implicit_return_type; | |
| 174 | BlockContext *block_context; | |
| 175 | }; | |
| 176 | ||
| 177 | struct AstNodeFnDecl { | |
| 178 | AstNode *fn_proto; | |
| 179 | }; | |
| 180 | ||
| 181 | struct AstNodeParamDecl { | |
| 182 | Buf name; | |
| 183 | AstNode *type; | |
| 184 | ||
| 185 | // populated by semantic analyzer | |
| 186 | VariableTableEntry *variable; | |
| 187 | }; | |
| 188 | ||
| 189 | enum AstNodeTypeType { | |
| 190 | AstNodeTypeTypePrimitive, | |
| 191 | AstNodeTypeTypePointer, | |
| 192 | AstNodeTypeTypeArray, | |
| 193 | AstNodeTypeTypeMaybe, | |
| 194 | AstNodeTypeTypeCompilerExpr, | |
| 195 | }; | |
| 196 | ||
| 197 | struct AstNodeType { | |
| 198 | AstNodeTypeType type; | |
| 199 | Buf primitive_name; | |
| 200 | AstNode *child_type; | |
| 201 | AstNode *array_size; // can be null | |
| 202 | bool is_const; | |
| 203 | bool is_noalias; | |
| 204 | AstNode *compiler_expr; | |
| 205 | ||
| 206 | // populated by semantic analyzer | |
| 207 | TypeTableEntry *entry; | |
| 208 | }; | |
| 209 | ||
| 210 | struct AstNodeBlock { | |
| 211 | ZigList<AstNode *> statements; | |
| 212 | ||
| 213 | // populated by semantic analyzer | |
| 214 | BlockContext *block_context; | |
| 215 | Expr resolved_expr; | |
| 216 | }; | |
| 217 | ||
| 218 | struct AstNodeReturnExpr { | |
| 219 | // might be null in case of return void; | |
| 220 | AstNode *expr; | |
| 221 | ||
| 222 | // populated by semantic analyzer: | |
| 223 | Expr resolved_expr; | |
| 224 | }; | |
| 225 | ||
| 226 | struct AstNodeVariableDeclaration { | |
| 227 | Buf symbol; | |
| 228 | bool is_const; | |
| 229 | VisibMod visib_mod; | |
| 230 | // one or both of type and expr will be non null | |
| 231 | AstNode *type; | |
| 232 | AstNode *expr; | |
| 233 | ||
| 234 | // populated by semantic analyzer | |
| 235 | TopLevelDecl top_level_decl; | |
| 236 | Expr resolved_expr; | |
| 237 | }; | |
| 238 | ||
| 239 | enum BinOpType { | |
| 240 | BinOpTypeInvalid, | |
| 241 | BinOpTypeAssign, | |
| 242 | BinOpTypeAssignTimes, | |
| 243 | BinOpTypeAssignDiv, | |
| 244 | BinOpTypeAssignMod, | |
| 245 | BinOpTypeAssignPlus, | |
| 246 | BinOpTypeAssignMinus, | |
| 247 | BinOpTypeAssignBitShiftLeft, | |
| 248 | BinOpTypeAssignBitShiftRight, | |
| 249 | BinOpTypeAssignBitAnd, | |
| 250 | BinOpTypeAssignBitXor, | |
| 251 | BinOpTypeAssignBitOr, | |
| 252 | BinOpTypeAssignBoolAnd, | |
| 253 | BinOpTypeAssignBoolOr, | |
| 254 | BinOpTypeBoolOr, | |
| 255 | BinOpTypeBoolAnd, | |
| 256 | BinOpTypeCmpEq, | |
| 257 | BinOpTypeCmpNotEq, | |
| 258 | BinOpTypeCmpLessThan, | |
| 259 | BinOpTypeCmpGreaterThan, | |
| 260 | BinOpTypeCmpLessOrEq, | |
| 261 | BinOpTypeCmpGreaterOrEq, | |
| 262 | BinOpTypeBinOr, | |
| 263 | BinOpTypeBinXor, | |
| 264 | BinOpTypeBinAnd, | |
| 265 | BinOpTypeBitShiftLeft, | |
| 266 | BinOpTypeBitShiftRight, | |
| 267 | BinOpTypeAdd, | |
| 268 | BinOpTypeSub, | |
| 269 | BinOpTypeMult, | |
| 270 | BinOpTypeDiv, | |
| 271 | BinOpTypeMod, | |
| 272 | BinOpTypeUnwrapMaybe, | |
| 273 | }; | |
| 274 | ||
| 275 | struct AstNodeBinOpExpr { | |
| 276 | AstNode *op1; | |
| 277 | BinOpType bin_op; | |
| 278 | AstNode *op2; | |
| 279 | ||
| 280 | // populated by semantic analyzer: | |
| 281 | // for when op is BinOpTypeAssign | |
| 282 | VariableTableEntry *var_entry; | |
| 283 | Expr resolved_expr; | |
| 284 | }; | |
| 285 | ||
| 286 | struct AstNodeFnCallExpr { | |
| 287 | AstNode *fn_ref_expr; | |
| 288 | ZigList<AstNode *> params; | |
| 289 | bool is_builtin; | |
| 290 | ||
| 291 | // populated by semantic analyzer: | |
| 292 | BuiltinFnEntry *builtin_fn; | |
| 293 | Expr resolved_expr; | |
| 294 | }; | |
| 295 | ||
| 296 | struct AstNodeArrayAccessExpr { | |
| 297 | AstNode *array_ref_expr; | |
| 298 | AstNode *subscript; | |
| 299 | ||
| 300 | // populated by semantic analyzer: | |
| 301 | Expr resolved_expr; | |
| 302 | }; | |
| 303 | ||
| 304 | struct AstNodeSliceExpr { | |
| 305 | AstNode *array_ref_expr; | |
| 306 | AstNode *start; | |
| 307 | AstNode *end; | |
| 308 | bool is_const; | |
| 309 | ||
| 310 | // populated by semantic analyzer: | |
| 311 | Expr resolved_expr; | |
| 312 | StructValExprCodeGen resolved_struct_val_expr; | |
| 313 | }; | |
| 314 | ||
| 315 | struct AstNodeFieldAccessExpr { | |
| 316 | AstNode *struct_expr; | |
| 317 | Buf field_name; | |
| 318 | ||
| 319 | // populated by semantic analyzer | |
| 320 | int field_index; | |
| 321 | TypeStructField *type_struct_field; | |
| 322 | Expr resolved_expr; | |
| 323 | }; | |
| 324 | ||
| 325 | struct AstNodeExternBlock { | |
| 326 | ZigList<AstNode *> *directives; | |
| 327 | ZigList<AstNode *> fn_decls; | |
| 328 | }; | |
| 329 | ||
| 330 | struct AstNodeDirective { | |
| 331 | Buf name; | |
| 332 | Buf param; | |
| 333 | }; | |
| 334 | ||
| 335 | struct AstNodeRootExportDecl { | |
| 336 | Buf type; | |
| 337 | Buf name; | |
| 338 | ZigList<AstNode *> *directives; | |
| 339 | }; | |
| 340 | ||
| 341 | struct AstNodeCastExpr { | |
| 342 | AstNode *expr; | |
| 343 | AstNode *type; | |
| 344 | ||
| 345 | // populated by semantic analyzer | |
| 346 | Cast cast; | |
| 347 | Expr resolved_expr; | |
| 348 | }; | |
| 349 | ||
| 350 | enum PrefixOp { | |
| 351 | PrefixOpInvalid, | |
| 352 | PrefixOpBoolNot, | |
| 353 | PrefixOpBinNot, | |
| 354 | PrefixOpNegation, | |
| 355 | PrefixOpAddressOf, | |
| 356 | PrefixOpConstAddressOf, | |
| 357 | PrefixOpDereference, | |
| 358 | }; | |
| 359 | ||
| 360 | struct AstNodePrefixOpExpr { | |
| 361 | PrefixOp prefix_op; | |
| 362 | AstNode *primary_expr; | |
| 363 | ||
| 364 | // populated by semantic analyzer | |
| 365 | Expr resolved_expr; | |
| 366 | }; | |
| 367 | ||
| 368 | struct AstNodeUse { | |
| 369 | Buf path; | |
| 370 | ZigList<AstNode *> *directives; | |
| 371 | ||
| 372 | // populated by semantic analyzer | |
| 373 | ImportTableEntry *import; | |
| 374 | }; | |
| 375 | ||
| 376 | struct AstNodeIfBoolExpr { | |
| 377 | AstNode *condition; | |
| 378 | AstNode *then_block; | |
| 379 | AstNode *else_node; // null, block node, or other if expr node | |
| 380 | ||
| 381 | // populated by semantic analyzer | |
| 382 | Expr resolved_expr; | |
| 383 | }; | |
| 384 | ||
| 385 | struct AstNodeIfVarExpr { | |
| 386 | AstNodeVariableDeclaration var_decl; | |
| 387 | AstNode *then_block; | |
| 388 | AstNode *else_node; // null, block node, or other if expr node | |
| 389 | ||
| 390 | // populated by semantic analyzer | |
| 391 | TypeTableEntry *type; | |
| 392 | BlockContext *block_context; | |
| 393 | Expr resolved_expr; | |
| 394 | }; | |
| 395 | ||
| 396 | struct AstNodeWhileExpr { | |
| 397 | AstNode *condition; | |
| 398 | AstNode *body; | |
| 399 | ||
| 400 | // populated by semantic analyzer | |
| 401 | bool condition_always_true; | |
| 402 | bool contains_break; | |
| 403 | Expr resolved_expr; | |
| 404 | }; | |
| 405 | ||
| 406 | struct AstNodeLabel { | |
| 407 | Buf name; | |
| 408 | ||
| 409 | // populated by semantic analyzer | |
| 410 | LabelTableEntry *label_entry; | |
| 411 | Expr resolved_expr; | |
| 412 | }; | |
| 413 | ||
| 414 | struct AstNodeGoto { | |
| 415 | Buf name; | |
| 416 | ||
| 417 | // populated by semantic analyzer | |
| 418 | LabelTableEntry *label_entry; | |
| 419 | Expr resolved_expr; | |
| 420 | }; | |
| 421 | ||
| 422 | struct AsmOutput { | |
| 423 | Buf asm_symbolic_name; | |
| 424 | Buf constraint; | |
| 425 | Buf variable_name; | |
| 426 | AstNode *return_type; // null unless "=r" and return | |
| 427 | }; | |
| 428 | ||
| 429 | struct AsmInput { | |
| 430 | Buf asm_symbolic_name; | |
| 431 | Buf constraint; | |
| 432 | AstNode *expr; | |
| 433 | }; | |
| 434 | ||
| 435 | struct SrcPos { | |
| 436 | int line; | |
| 437 | int column; | |
| 438 | }; | |
| 439 | ||
| 440 | struct AstNodeAsmExpr { | |
| 441 | bool is_volatile; | |
| 442 | Buf asm_template; | |
| 443 | ZigList<SrcPos> offset_map; | |
| 444 | ZigList<AsmToken> token_list; | |
| 445 | ZigList<AsmOutput*> output_list; | |
| 446 | ZigList<AsmInput*> input_list; | |
| 447 | ZigList<Buf*> clobber_list; | |
| 448 | ||
| 449 | // populated by semantic analyzer | |
| 450 | int return_count; | |
| 451 | Expr resolved_expr; | |
| 452 | }; | |
| 453 | ||
| 454 | struct AstNodeStructDecl { | |
| 455 | Buf name; | |
| 456 | ZigList<AstNode *> fields; | |
| 457 | ZigList<AstNode *> fns; | |
| 458 | ZigList<AstNode *> *directives; | |
| 459 | VisibMod visib_mod; | |
| 460 | ||
| 461 | // populated by semantic analyzer | |
| 462 | TypeTableEntry *type_entry; | |
| 463 | TopLevelDecl top_level_decl; | |
| 464 | }; | |
| 465 | ||
| 466 | struct AstNodeStructField { | |
| 467 | Buf name; | |
| 468 | AstNode *type; | |
| 469 | ZigList<AstNode *> *directives; | |
| 470 | }; | |
| 471 | ||
| 472 | struct AstNodeEnumDecl { | |
| 473 | Buf name; | |
| 474 | ZigList<AstNode *> fields; | |
| 475 | ZigList<AstNode *> *directives; | |
| 476 | VisibMod visib_mod; | |
| 477 | }; | |
| 478 | ||
| 479 | struct AstNodeEnumField { | |
| 480 | Buf name; | |
| 481 | ZigList<AstNode *> fields; // length 0 means simple enum | |
| 482 | AstNode *val_expr; | |
| 483 | }; | |
| 484 | ||
| 485 | struct AstNodeStringLiteral { | |
| 486 | Buf buf; | |
| 487 | bool c; | |
| 488 | ||
| 489 | // populated by semantic analyzer: | |
| 490 | Expr resolved_expr; | |
| 491 | }; | |
| 492 | ||
| 493 | struct AstNodeCharLiteral { | |
| 494 | uint8_t value; | |
| 495 | ||
| 496 | // populated by semantic analyzer: | |
| 497 | Expr resolved_expr; | |
| 498 | }; | |
| 499 | ||
| 500 | enum NumLit { | |
| 501 | NumLitF32, | |
| 502 | NumLitF64, | |
| 503 | NumLitF128, | |
| 504 | NumLitU8, | |
| 505 | NumLitU16, | |
| 506 | NumLitU32, | |
| 507 | NumLitU64, | |
| 508 | NumLitI8, | |
| 509 | NumLitI16, | |
| 510 | NumLitI32, | |
| 511 | NumLitI64, | |
| 512 | ||
| 513 | NumLitCount | |
| 514 | }; | |
| 515 | ||
| 516 | struct AstNodeNumberLiteral { | |
| 517 | NumLit kind; | |
| 518 | ||
| 519 | // overflow is true if when parsing the number, we discovered it would not | |
| 520 | // fit without losing data in a uint64_t, int64_t, or double | |
| 521 | bool overflow; | |
| 522 | ||
| 523 | union { | |
| 524 | uint64_t x_uint; | |
| 525 | int64_t x_int; | |
| 526 | double x_float; | |
| 527 | } data; | |
| 528 | ||
| 529 | // populated by semantic analyzer | |
| 530 | NumLitCodeGen codegen; | |
| 531 | Expr resolved_expr; | |
| 532 | }; | |
| 533 | ||
| 534 | struct AstNodeStructValueField { | |
| 535 | Buf name; | |
| 536 | AstNode *expr; | |
| 537 | ||
| 538 | // populated by semantic analyzer | |
| 539 | int index; | |
| 540 | }; | |
| 541 | ||
| 542 | struct AstNodeStructValueExpr { | |
| 543 | AstNode *type; | |
| 544 | ZigList<AstNode *> fields; | |
| 545 | ||
| 546 | // populated by semantic analyzer | |
| 547 | StructValExprCodeGen codegen; | |
| 548 | Expr resolved_expr; | |
| 549 | }; | |
| 550 | ||
| 551 | struct AstNodeCompilerFnExpr { | |
| 552 | Buf name; | |
| 553 | AstNode *expr; | |
| 554 | ||
| 555 | // populated by semantic analyzer | |
| 556 | Expr resolved_expr; | |
| 557 | }; | |
| 558 | ||
| 559 | struct AstNodeCompilerFnType { | |
| 560 | Buf name; | |
| 561 | AstNode *type; | |
| 562 | ||
| 563 | // populated by semantic analyzer | |
| 564 | Expr resolved_expr; | |
| 565 | NumLitCodeGen resolved_num_lit; | |
| 566 | }; | |
| 567 | ||
| 568 | struct AstNodeNullLiteral { | |
| 569 | // populated by semantic analyzer | |
| 570 | StructValExprCodeGen resolved_struct_val_expr; | |
| 571 | Expr resolved_expr; | |
| 572 | }; | |
| 573 | ||
| 574 | struct AstNodeVoidExpr { | |
| 575 | // populated by semantic analyzer | |
| 576 | Expr resolved_expr; | |
| 577 | }; | |
| 578 | ||
| 579 | struct AstNodeUnreachableExpr { | |
| 580 | // populated by semantic analyzer | |
| 581 | Expr resolved_expr; | |
| 582 | }; | |
| 583 | ||
| 584 | struct AstNodeSymbolExpr { | |
| 585 | Buf symbol; | |
| 586 | ||
| 587 | // populated by semantic analyzer | |
| 588 | Expr resolved_expr; | |
| 589 | }; | |
| 590 | ||
| 591 | struct AstNodeBoolLiteral { | |
| 592 | bool value; | |
| 593 | ||
| 594 | // populated by semantic analyzer | |
| 595 | Expr resolved_expr; | |
| 596 | }; | |
| 597 | ||
| 598 | struct AstNodeBreakExpr { | |
| 599 | // populated by semantic analyzer | |
| 600 | Expr resolved_expr; | |
| 601 | }; | |
| 602 | ||
| 603 | struct AstNodeContinueExpr { | |
| 604 | // populated by semantic analyzer | |
| 605 | Expr resolved_expr; | |
| 606 | }; | |
| 607 | ||
| 608 | struct AstNode { | |
| 609 | enum NodeType type; | |
| 610 | int line; | |
| 611 | int column; | |
| 612 | uint32_t create_index; // for determinism purposes | |
| 613 | ImportTableEntry *owner; | |
| 614 | union { | |
| 615 | AstNodeRoot root; | |
| 616 | AstNodeRootExportDecl root_export_decl; | |
| 617 | AstNodeFnDef fn_def; | |
| 618 | AstNodeFnDecl fn_decl; | |
| 619 | AstNodeFnProto fn_proto; | |
| 620 | AstNodeType type; | |
| 621 | AstNodeParamDecl param_decl; | |
| 622 | AstNodeBlock block; | |
| 623 | AstNodeReturnExpr return_expr; | |
| 624 | AstNodeVariableDeclaration variable_declaration; | |
| 625 | AstNodeBinOpExpr bin_op_expr; | |
| 626 | AstNodeExternBlock extern_block; | |
| 627 | AstNodeDirective directive; | |
| 628 | AstNodeCastExpr cast_expr; | |
| 629 | AstNodePrefixOpExpr prefix_op_expr; | |
| 630 | AstNodeFnCallExpr fn_call_expr; | |
| 631 | AstNodeArrayAccessExpr array_access_expr; | |
| 632 | AstNodeSliceExpr slice_expr; | |
| 633 | AstNodeUse use; | |
| 634 | AstNodeIfBoolExpr if_bool_expr; | |
| 635 | AstNodeIfVarExpr if_var_expr; | |
| 636 | AstNodeWhileExpr while_expr; | |
| 637 | AstNodeLabel label; | |
| 638 | AstNodeGoto goto_expr; | |
| 639 | AstNodeAsmExpr asm_expr; | |
| 640 | AstNodeFieldAccessExpr field_access_expr; | |
| 641 | AstNodeStructDecl struct_decl; | |
| 642 | AstNodeStructField struct_field; | |
| 643 | AstNodeEnumDecl enum_decl; | |
| 644 | AstNodeEnumField enum_field; | |
| 645 | AstNodeStringLiteral string_literal; | |
| 646 | AstNodeCharLiteral char_literal; | |
| 647 | AstNodeNumberLiteral number_literal; | |
| 648 | AstNodeStructValueExpr struct_val_expr; | |
| 649 | AstNodeStructValueField struct_val_field; | |
| 650 | AstNodeCompilerFnExpr compiler_fn_expr; | |
| 651 | AstNodeCompilerFnType compiler_fn_type; | |
| 652 | AstNodeNullLiteral null_literal; | |
| 653 | AstNodeVoidExpr void_expr; | |
| 654 | AstNodeUnreachableExpr unreachable_expr; | |
| 655 | AstNodeSymbolExpr symbol_expr; | |
| 656 | AstNodeBoolLiteral bool_literal; | |
| 657 | AstNodeBreakExpr break_expr; | |
| 658 | AstNodeContinueExpr continue_expr; | |
| 659 | } data; | |
| 660 | }; | |
| 661 | ||
| 662 | enum AsmTokenId { | |
| 663 | AsmTokenIdTemplate, | |
| 664 | AsmTokenIdPercent, | |
| 665 | AsmTokenIdVar, | |
| 666 | }; | |
| 667 | ||
| 668 | struct AsmToken { | |
| 669 | enum AsmTokenId id; | |
| 670 | int start; | |
| 671 | int end; | |
| 672 | }; | |
| 673 | ||
| 674 | struct TypeTableEntryPointer { | |
| 675 | TypeTableEntry *child_type; | |
| 676 | bool is_const; | |
| 677 | bool is_noalias; | |
| 678 | }; | |
| 679 | ||
| 680 | struct TypeTableEntryInt { | |
| 681 | bool is_signed; | |
| 682 | }; | |
| 683 | ||
| 684 | struct TypeTableEntryArray { | |
| 685 | TypeTableEntry *child_type; | |
| 686 | uint64_t len; | |
| 687 | }; | |
| 688 | ||
| 689 | struct TypeStructField { | |
| 690 | Buf *name; | |
| 691 | TypeTableEntry *type_entry; | |
| 692 | }; | |
| 693 | ||
| 694 | struct TypeTableEntryStruct { | |
| 695 | AstNode *decl_node; | |
| 696 | bool is_packed; | |
| 697 | int field_count; | |
| 698 | TypeStructField *fields; | |
| 699 | uint64_t size_bytes; | |
| 700 | bool is_invalid; // true if any fields are invalid | |
| 701 | bool is_unknown_size_array; | |
| 702 | // reminder: hash tables must be initialized before use | |
| 703 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | |
| 704 | ||
| 705 | // set this flag temporarily to detect infinite loops | |
| 706 | bool embedded_in_current; | |
| 707 | bool reported_infinite_err; | |
| 708 | }; | |
| 709 | ||
| 710 | struct TypeTableEntryNumLit { | |
| 711 | NumLit kind; | |
| 712 | }; | |
| 713 | ||
| 714 | struct TypeTableEntryMaybe { | |
| 715 | TypeTableEntry *child_type; | |
| 716 | }; | |
| 717 | ||
| 718 | enum TypeTableEntryId { | |
| 719 | TypeTableEntryIdInvalid, | |
| 720 | TypeTableEntryIdVoid, | |
| 721 | TypeTableEntryIdBool, | |
| 722 | TypeTableEntryIdUnreachable, | |
| 723 | TypeTableEntryIdInt, | |
| 724 | TypeTableEntryIdFloat, | |
| 725 | TypeTableEntryIdPointer, | |
| 726 | TypeTableEntryIdArray, | |
| 727 | TypeTableEntryIdStruct, | |
| 728 | TypeTableEntryIdNumberLiteral, | |
| 729 | TypeTableEntryIdMaybe, | |
| 730 | }; | |
| 731 | ||
| 732 | struct TypeTableEntry { | |
| 733 | TypeTableEntryId id; | |
| 734 | ||
| 735 | LLVMTypeRef type_ref; | |
| 736 | LLVMZigDIType *di_type; | |
| 737 | uint64_t size_in_bits; | |
| 738 | uint64_t align_in_bits; | |
| 739 | ||
| 740 | Buf name; | |
| 741 | ||
| 742 | union { | |
| 743 | TypeTableEntryPointer pointer; | |
| 744 | TypeTableEntryInt integral; | |
| 745 | TypeTableEntryArray array; | |
| 746 | TypeTableEntryStruct structure; | |
| 747 | TypeTableEntryNumLit num_lit; | |
| 748 | TypeTableEntryMaybe maybe; | |
| 749 | } data; | |
| 750 | ||
| 751 | // use these fields to make sure we don't duplicate type table entries for the same type | |
| 752 | TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias | |
| 753 | TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias | |
| 754 | HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size; | |
| 755 | TypeTableEntry *maybe_parent; | |
| 756 | ||
| 757 | }; | |
| 758 | ||
| 759 | struct ImporterInfo { | |
| 760 | ImportTableEntry *import; | |
| 761 | AstNode *source_node; | |
| 762 | }; | |
| 763 | ||
| 764 | struct ImportTableEntry { | |
| 765 | AstNode *root; | |
| 766 | Buf *path; // relative to root_source_dir | |
| 767 | LLVMZigDIFile *di_file; | |
| 768 | Buf *source_code; | |
| 769 | ZigList<int> *line_offsets; | |
| 770 | BlockContext *block_context; | |
| 771 | ZigList<ImporterInfo> importers; | |
| 772 | ||
| 773 | // reminder: hash tables must be initialized before use | |
| 774 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | |
| 775 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; | |
| 776 | }; | |
| 777 | ||
| 778 | struct LabelTableEntry { | |
| 779 | AstNode *label_node; | |
| 780 | LLVMBasicBlockRef basic_block; | |
| 781 | bool used; | |
| 782 | bool entered_from_fallthrough; | |
| 783 | }; | |
| 784 | ||
| 785 | enum FnAttrId { | |
| 786 | FnAttrIdNaked, | |
| 787 | FnAttrIdAlwaysInline, | |
| 788 | }; | |
| 789 | ||
| 790 | struct FnTableEntry { | |
| 791 | LLVMValueRef fn_value; | |
| 792 | AstNode *proto_node; | |
| 793 | AstNode *fn_def_node; | |
| 794 | bool is_extern; | |
| 795 | bool internal_linkage; | |
| 796 | unsigned calling_convention; | |
| 797 | ImportTableEntry *import_entry; | |
| 798 | ZigList<FnAttrId> fn_attr_list; | |
| 799 | // Required to be a pre-order traversal of the AST. (parents must come before children) | |
| 800 | ZigList<BlockContext *> all_block_contexts; | |
| 801 | TypeTableEntry *member_of_struct; | |
| 802 | Buf symbol_name; | |
| 803 | ||
| 804 | // reminder: hash tables must be initialized before use | |
| 805 | HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; | |
| 806 | }; | |
| 807 | ||
| 808 | enum BuiltinFnId { | |
| 809 | BuiltinFnIdInvalid, | |
| 810 | BuiltinFnIdArithmeticWithOverflow, | |
| 811 | BuiltinFnIdMemcpy, | |
| 812 | BuiltinFnIdMemset, | |
| 813 | }; | |
| 814 | ||
| 815 | struct BuiltinFnEntry { | |
| 816 | BuiltinFnId id; | |
| 817 | Buf name; | |
| 818 | int param_count; | |
| 819 | TypeTableEntry *return_type; | |
| 820 | TypeTableEntry **param_types; | |
| 821 | LLVMValueRef fn_val; | |
| 822 | }; | |
| 823 | ||
| 824 | struct CodeGen { | |
| 825 | LLVMModuleRef module; | |
| 826 | ZigList<ErrorMsg*> errors; | |
| 827 | LLVMBuilderRef builder; | |
| 828 | LLVMZigDIBuilder *dbuilder; | |
| 829 | LLVMZigDICompileUnit *compile_unit; | |
| 830 | ||
| 831 | ZigList<Buf *> lib_search_paths; | |
| 832 | ||
| 833 | // reminder: hash tables must be initialized before use | |
| 834 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; | |
| 835 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; | |
| 836 | HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; | |
| 837 | HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table; | |
| 838 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table; | |
| 839 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls; | |
| 840 | ||
| 841 | uint32_t next_unresolved_index; | |
| 842 | ||
| 843 | struct { | |
| 844 | TypeTableEntry *entry_bool; | |
| 845 | TypeTableEntry *entry_u8; | |
| 846 | TypeTableEntry *entry_u16; | |
| 847 | TypeTableEntry *entry_u32; | |
| 848 | TypeTableEntry *entry_u64; | |
| 849 | TypeTableEntry *entry_i8; | |
| 850 | TypeTableEntry *entry_i16; | |
| 851 | TypeTableEntry *entry_i32; | |
| 852 | TypeTableEntry *entry_i64; | |
| 853 | TypeTableEntry *entry_isize; | |
| 854 | TypeTableEntry *entry_usize; | |
| 855 | TypeTableEntry *entry_f32; | |
| 856 | TypeTableEntry *entry_f64; | |
| 857 | TypeTableEntry *entry_c_string_literal; | |
| 858 | TypeTableEntry *entry_void; | |
| 859 | TypeTableEntry *entry_unreachable; | |
| 860 | TypeTableEntry *entry_invalid; | |
| 861 | } builtin_types; | |
| 862 | ||
| 863 | TypeTableEntry *num_lit_types[NumLitCount]; | |
| 864 | ||
| 865 | LLVMTargetDataRef target_data_ref; | |
| 866 | unsigned pointer_size_bytes; | |
| 867 | bool is_static; | |
| 868 | bool strip_debug_symbols; | |
| 869 | bool have_exported_main; | |
| 870 | bool link_libc; | |
| 871 | Buf *libc_path; | |
| 872 | CodeGenBuildType build_type; | |
| 873 | LLVMTargetMachineRef target_machine; | |
| 874 | LLVMZigDIFile *dummy_di_file; | |
| 875 | bool is_native_target; | |
| 876 | Buf *root_source_dir; | |
| 877 | Buf *root_out_name; | |
| 878 | ||
| 879 | // The function definitions this module includes. There must be a corresponding | |
| 880 | // fn_protos entry. | |
| 881 | ZigList<FnTableEntry *> fn_defs; | |
| 882 | // The function prototypes this module includes. In the case of external declarations, | |
| 883 | // there will not be a corresponding fn_defs entry. | |
| 884 | ZigList<FnTableEntry *> fn_protos; | |
| 885 | ZigList<VariableTableEntry *> global_vars; | |
| 886 | ||
| 887 | OutType out_type; | |
| 888 | FnTableEntry *cur_fn; | |
| 889 | BlockContext *cur_block_context; | |
| 890 | ZigList<LLVMBasicBlockRef> break_block_stack; | |
| 891 | ZigList<LLVMBasicBlockRef> continue_block_stack; | |
| 892 | bool c_stdint_used; | |
| 893 | AstNode *root_export_decl; | |
| 894 | int version_major; | |
| 895 | int version_minor; | |
| 896 | int version_patch; | |
| 897 | bool verbose; | |
| 898 | ErrColor err_color; | |
| 899 | ImportTableEntry *root_import; | |
| 900 | ImportTableEntry *bootstrap_import; | |
| 901 | LLVMValueRef memcpy_fn_val; | |
| 902 | bool error_during_imports; | |
| 903 | }; | |
| 904 | ||
| 905 | struct VariableTableEntry { | |
| 906 | Buf name; | |
| 907 | TypeTableEntry *type; | |
| 908 | LLVMValueRef value_ref; | |
| 909 | bool is_const; | |
| 910 | bool is_ptr; // if true, value_ref is a pointer | |
| 911 | AstNode *decl_node; | |
| 912 | LLVMZigDILocalVariable *di_loc_var; | |
| 913 | int arg_index; | |
| 914 | }; | |
| 915 | ||
| 916 | struct BlockContext { | |
| 917 | AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot | |
| 918 | FnTableEntry *fn_entry; // null at the module scope | |
| 919 | BlockContext *parent; // null when this is the root | |
| 920 | HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table; | |
| 921 | ZigList<Cast *> cast_expr_alloca_list; | |
| 922 | ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list; | |
| 923 | AstNode *parent_loop_node; | |
| 924 | AstNode *next_child_parent_loop_node; | |
| 925 | LLVMZigDIScope *di_scope; | |
| 926 | }; | |
| 927 | ||
| 928 | #endif |
src/analyze.cpp+353-177| ... | ... | @@ -6,6 +6,7 @@ |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | #include "analyze.hpp" |
| 9 | #include "parser.hpp" | |
| 9 | 10 | #include "error.hpp" |
| 10 | 11 | #include "zig_llvm.hpp" |
| 11 | 12 | #include "os.hpp" |
| ... | ... | @@ -14,7 +15,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 14 | 15 | TypeTableEntry *expected_type, AstNode *node); |
| 15 | 16 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 16 | 17 | AstNode *node, AstNodeNumberLiteral *out_number_literal); |
| 17 | static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, DeclNode *decl_node); | |
| 18 | static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, TopLevelDecl *decl_node); | |
| 18 | 19 | static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, |
| 19 | 20 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node); |
| 20 | 21 | |
| ... | ... | @@ -317,7 +318,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, |
| 317 | 318 | out_number_literal->kind = NumLitU8; |
| 318 | 319 | out_number_literal->overflow = false; |
| 319 | 320 | out_number_literal->data.x_uint = (op1_lit.data.x_uint != op2_lit.data.x_uint); |
| 320 | return node->codegen_node->expr_node.type_entry; | |
| 321 | return get_resolved_expr(node)->type_entry; | |
| 321 | 322 | } else { |
| 322 | 323 | return g->builtin_types.entry_invalid; |
| 323 | 324 | } |
| ... | ... | @@ -330,7 +331,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, |
| 330 | 331 | out_number_literal->kind = NumLitU8; |
| 331 | 332 | out_number_literal->overflow = false; |
| 332 | 333 | out_number_literal->data.x_uint = (op1_lit.data.x_uint < op2_lit.data.x_uint); |
| 333 | return node->codegen_node->expr_node.type_entry; | |
| 334 | return get_resolved_expr(node)->type_entry; | |
| 334 | 335 | } else { |
| 335 | 336 | return g->builtin_types.entry_invalid; |
| 336 | 337 | } |
| ... | ... | @@ -343,7 +344,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, |
| 343 | 344 | out_number_literal->kind = NumLitU64; |
| 344 | 345 | out_number_literal->overflow = false; |
| 345 | 346 | out_number_literal->data.x_uint = (op1_lit.data.x_uint % op2_lit.data.x_uint); |
| 346 | return node->codegen_node->expr_node.type_entry; | |
| 347 | return get_resolved_expr(node)->type_entry; | |
| 347 | 348 | } else { |
| 348 | 349 | return g->builtin_types.entry_invalid; |
| 349 | 350 | } |
| ... | ... | @@ -390,20 +391,20 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 390 | 391 | switch (node->type) { |
| 391 | 392 | case NodeTypeNumberLiteral: |
| 392 | 393 | *out_number_literal = node->data.number_literal; |
| 393 | return node->codegen_node->expr_node.type_entry; | |
| 394 | return get_resolved_expr(node)->type_entry; | |
| 394 | 395 | case NodeTypeBoolLiteral: |
| 395 | out_number_literal->data.x_uint = node->data.bool_literal ? 1 : 0; | |
| 396 | return node->codegen_node->expr_node.type_entry; | |
| 396 | out_number_literal->data.x_uint = node->data.bool_literal.value ? 1 : 0; | |
| 397 | return get_resolved_expr(node)->type_entry; | |
| 397 | 398 | case NodeTypeNullLiteral: |
| 398 | return node->codegen_node->expr_node.type_entry; | |
| 399 | return get_resolved_expr(node)->type_entry; | |
| 399 | 400 | case NodeTypeBinOpExpr: |
| 400 | 401 | return eval_const_expr_bin_op(g, context, node, out_number_literal); |
| 401 | 402 | case NodeTypeCompilerFnType: |
| 402 | 403 | { |
| 403 | 404 | Buf *name = &node->data.compiler_fn_type.name; |
| 404 | TypeTableEntry *expr_type = node->codegen_node->expr_node.type_entry; | |
| 405 | TypeTableEntry *expr_type = get_resolved_expr(node)->type_entry; | |
| 405 | 406 | if (buf_eql_str(name, "sizeof")) { |
| 406 | TypeTableEntry *target_type = node->data.compiler_fn_type.type->codegen_node->data.type_node.entry; | |
| 407 | TypeTableEntry *target_type = node->data.compiler_fn_type.type->data.type.entry; | |
| 407 | 408 | out_number_literal->overflow = false; |
| 408 | 409 | out_number_literal->data.x_uint = target_type->size_in_bits / 8; |
| 409 | 410 | out_number_literal->kind = get_number_literal_kind_unsigned(out_number_literal->data.x_uint); |
| ... | ... | @@ -420,11 +421,11 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, |
| 420 | 421 | } |
| 421 | 422 | case NodeTypeSymbol: |
| 422 | 423 | { |
| 423 | VariableTableEntry *var = find_variable(context, &node->data.symbol); | |
| 424 | VariableTableEntry *var = find_variable(context, &node->data.symbol_expr.symbol); | |
| 424 | 425 | assert(var); |
| 425 | 426 | AstNode *decl_node = var->decl_node; |
| 426 | 427 | AstNode *expr_node = decl_node->data.variable_declaration.expr; |
| 427 | BlockContext *next_context = expr_node->codegen_node->expr_node.block_context; | |
| 428 | BlockContext *next_context = get_resolved_expr(expr_node)->block_context; | |
| 428 | 429 | return eval_const_expr(g, next_context, expr_node, out_number_literal); |
| 429 | 430 | } |
| 430 | 431 | default: |
| ... | ... | @@ -436,8 +437,6 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry |
| 436 | 437 | BlockContext *context, bool noalias_allowed) |
| 437 | 438 | { |
| 438 | 439 | assert(node->type == NodeTypeType); |
| 439 | alloc_codegen_node(node); | |
| 440 | TypeNode *type_node = &node->codegen_node->data.type_node; | |
| 441 | 440 | switch (node->data.type.type) { |
| 442 | 441 | case AstNodeTypeTypePrimitive: |
| 443 | 442 | { |
| ... | ... | @@ -447,13 +446,13 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry |
| 447 | 446 | table_entry = g->primitive_type_table.maybe_get(name); |
| 448 | 447 | } |
| 449 | 448 | if (table_entry) { |
| 450 | type_node->entry = table_entry->value; | |
| 449 | node->data.type.entry = table_entry->value; | |
| 451 | 450 | } else { |
| 452 | 451 | add_node_error(g, node, |
| 453 | 452 | buf_sprintf("invalid type name: '%s'", buf_ptr(name))); |
| 454 | type_node->entry = g->builtin_types.entry_invalid; | |
| 453 | node->data.type.entry = g->builtin_types.entry_invalid; | |
| 455 | 454 | } |
| 456 | return type_node->entry; | |
| 455 | return node->data.type.entry; | |
| 457 | 456 | } |
| 458 | 457 | case AstNodeTypeTypePointer: |
| 459 | 458 | { |
| ... | ... | @@ -468,19 +467,19 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry |
| 468 | 467 | } |
| 469 | 468 | |
| 470 | 469 | resolve_type(g, node->data.type.child_type, import, context, false); |
| 471 | TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; | |
| 470 | TypeTableEntry *child_type = node->data.type.child_type->data.type.entry; | |
| 472 | 471 | assert(child_type); |
| 473 | 472 | if (child_type->id == TypeTableEntryIdUnreachable) { |
| 474 | 473 | add_node_error(g, node, |
| 475 | 474 | buf_create_from_str("pointer to unreachable not allowed")); |
| 476 | type_node->entry = g->builtin_types.entry_invalid; | |
| 477 | return type_node->entry; | |
| 475 | node->data.type.entry = g->builtin_types.entry_invalid; | |
| 476 | return node->data.type.entry; | |
| 478 | 477 | } else if (child_type->id == TypeTableEntryIdInvalid) { |
| 479 | type_node->entry = child_type; | |
| 478 | node->data.type.entry = child_type; | |
| 480 | 479 | return child_type; |
| 481 | 480 | } else { |
| 482 | type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const, use_noalias); | |
| 483 | return type_node->entry; | |
| 481 | node->data.type.entry = get_pointer_to_type(g, child_type, node->data.type.is_const, use_noalias); | |
| 482 | return node->data.type.entry; | |
| 484 | 483 | } |
| 485 | 484 | } |
| 486 | 485 | case AstNodeTypeTypeArray: |
| ... | ... | @@ -501,16 +500,16 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry |
| 501 | 500 | if (child_type->id == TypeTableEntryIdUnreachable) { |
| 502 | 501 | add_node_error(g, node, |
| 503 | 502 | buf_create_from_str("array of unreachable not allowed")); |
| 504 | type_node->entry = g->builtin_types.entry_invalid; | |
| 505 | return type_node->entry; | |
| 503 | node->data.type.entry = g->builtin_types.entry_invalid; | |
| 504 | return node->data.type.entry; | |
| 506 | 505 | } |
| 507 | 506 | |
| 508 | 507 | if (size_node) { |
| 509 | 508 | TypeTableEntry *size_type = analyze_expression(g, import, context, |
| 510 | 509 | g->builtin_types.entry_usize, size_node); |
| 511 | 510 | if (size_type->id == TypeTableEntryIdInvalid) { |
| 512 | type_node->entry = g->builtin_types.entry_invalid; | |
| 513 | return type_node->entry; | |
| 511 | node->data.type.entry = g->builtin_types.entry_invalid; | |
| 512 | return node->data.type.entry; | |
| 514 | 513 | } |
| 515 | 514 | |
| 516 | 515 | AstNodeNumberLiteral number_literal; |
| ... | ... | @@ -520,27 +519,27 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry |
| 520 | 519 | if (resolved_type->data.integral.is_signed) { |
| 521 | 520 | add_node_error(g, size_node, |
| 522 | 521 | buf_create_from_str("array size must be unsigned integer")); |
| 523 | type_node->entry = g->builtin_types.entry_invalid; | |
| 522 | node->data.type.entry = g->builtin_types.entry_invalid; | |
| 524 | 523 | } else { |
| 525 | type_node->entry = get_array_type(g, import, child_type, number_literal.data.x_uint); | |
| 524 | node->data.type.entry = get_array_type(g, import, child_type, number_literal.data.x_uint); | |
| 526 | 525 | } |
| 527 | 526 | } else { |
| 528 | 527 | add_node_error(g, size_node, |
| 529 | 528 | buf_create_from_str("unable to resolve constant expression")); |
| 530 | type_node->entry = g->builtin_types.entry_invalid; | |
| 529 | node->data.type.entry = g->builtin_types.entry_invalid; | |
| 531 | 530 | } |
| 532 | return type_node->entry; | |
| 531 | return node->data.type.entry; | |
| 533 | 532 | } else { |
| 534 | type_node->entry = get_unknown_size_array_type(g, import, child_type, | |
| 533 | node->data.type.entry = get_unknown_size_array_type(g, import, child_type, | |
| 535 | 534 | node->data.type.is_const, use_noalias); |
| 536 | return type_node->entry; | |
| 535 | return node->data.type.entry; | |
| 537 | 536 | } |
| 538 | 537 | |
| 539 | 538 | } |
| 540 | 539 | case AstNodeTypeTypeMaybe: |
| 541 | 540 | { |
| 542 | 541 | resolve_type(g, node->data.type.child_type, import, context, false); |
| 543 | TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; | |
| 542 | TypeTableEntry *child_type = node->data.type.child_type->data.type.entry; | |
| 544 | 543 | assert(child_type); |
| 545 | 544 | if (child_type->id == TypeTableEntryIdUnreachable) { |
| 546 | 545 | add_node_error(g, node, |
| ... | ... | @@ -548,22 +547,22 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry |
| 548 | 547 | } else if (child_type->id == TypeTableEntryIdInvalid) { |
| 549 | 548 | return child_type; |
| 550 | 549 | } |
| 551 | type_node->entry = get_maybe_type(g, import, child_type); | |
| 552 | return type_node->entry; | |
| 550 | node->data.type.entry = get_maybe_type(g, import, child_type); | |
| 551 | return node->data.type.entry; | |
| 553 | 552 | } |
| 554 | 553 | case AstNodeTypeTypeCompilerExpr: |
| 555 | 554 | { |
| 556 | 555 | AstNode *compiler_expr_node = node->data.type.compiler_expr; |
| 557 | 556 | Buf *fn_name = &compiler_expr_node->data.compiler_fn_expr.name; |
| 558 | 557 | if (buf_eql_str(fn_name, "typeof")) { |
| 559 | type_node->entry = analyze_expression(g, import, context, nullptr, | |
| 558 | node->data.type.entry = analyze_expression(g, import, context, nullptr, | |
| 560 | 559 | compiler_expr_node->data.compiler_fn_expr.expr); |
| 561 | 560 | } else { |
| 562 | 561 | add_node_error(g, node, |
| 563 | 562 | buf_sprintf("invalid compiler function: '%s'", buf_ptr(fn_name))); |
| 564 | type_node->entry = g->builtin_types.entry_invalid; | |
| 563 | node->data.type.entry = g->builtin_types.entry_invalid; | |
| 565 | 564 | } |
| 566 | return type_node->entry; | |
| 565 | return node->data.type.entry; | |
| 567 | 566 | } |
| 568 | 567 | } |
| 569 | 568 | zig_unreachable(); |
| ... | ... | @@ -631,8 +630,7 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_ |
| 631 | 630 | Buf *name = &label_node->data.label.name; |
| 632 | 631 | fn_table_entry->label_table.put(name, label_entry); |
| 633 | 632 | |
| 634 | alloc_codegen_node(label_node); | |
| 635 | label_node->codegen_node->data.label_entry = label_entry; | |
| 633 | label_node->data.label.label_entry = label_entry; | |
| 636 | 634 | } |
| 637 | 635 | } |
| 638 | 636 | |
| ... | ... | @@ -732,7 +730,8 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, |
| 732 | 730 | AstNode *struct_node = proto_node->data.fn_proto.struct_node; |
| 733 | 731 | TypeTableEntry *struct_type; |
| 734 | 732 | if (struct_node) { |
| 735 | struct_type = struct_node->codegen_node->data.struct_decl_node.type_entry; | |
| 733 | assert(struct_node->type == NodeTypeStructDecl); | |
| 734 | struct_type = struct_node->data.struct_decl.type_entry; | |
| 736 | 735 | } else { |
| 737 | 736 | struct_type = nullptr; |
| 738 | 737 | } |
| ... | ... | @@ -749,13 +748,14 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, |
| 749 | 748 | if (entry) { |
| 750 | 749 | add_node_error(g, proto_node, |
| 751 | 750 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 752 | proto_node->codegen_node->data.fn_proto_node.skip = true; | |
| 751 | proto_node->data.fn_proto.skip = true; | |
| 753 | 752 | skip = true; |
| 754 | 753 | } else if (is_pub) { |
| 754 | // TODO is this else if branch a mistake? | |
| 755 | 755 | auto entry = fn_table->maybe_get(proto_name); |
| 756 | 756 | if (entry) { |
| 757 | 757 | add_node_error(g, proto_node, buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 758 | proto_node->codegen_node->data.fn_proto_node.skip = true; | |
| 758 | proto_node->data.fn_proto.skip = true; | |
| 759 | 759 | skip = true; |
| 760 | 760 | } |
| 761 | 761 | } |
| ... | ... | @@ -804,7 +804,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, |
| 804 | 804 | resolve_function_proto(g, proto_node, fn_table_entry, import); |
| 805 | 805 | |
| 806 | 806 | |
| 807 | proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; | |
| 807 | proto_node->data.fn_proto.fn_table_entry = fn_table_entry; | |
| 808 | 808 | |
| 809 | 809 | if (fn_def_node) { |
| 810 | 810 | preview_function_labels(g, fn_def_node->data.fn_def.body, fn_table_entry); |
| ... | ... | @@ -888,8 +888,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 888 | 888 | break; |
| 889 | 889 | case NodeTypeStructDecl: |
| 890 | 890 | { |
| 891 | StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node; | |
| 892 | TypeTableEntry *type_entry = struct_codegen->type_entry; | |
| 891 | TypeTableEntry *type_entry = node->data.struct_decl.type_entry; | |
| 893 | 892 | |
| 894 | 893 | resolve_struct_type(g, import, type_entry); |
| 895 | 894 | |
| ... | ... | @@ -962,8 +961,8 @@ static TypeTableEntry *get_return_type(BlockContext *context) { |
| 962 | 961 | AstNode *fn_proto_node = fn_entry->proto_node; |
| 963 | 962 | assert(fn_proto_node->type == NodeTypeFnProto); |
| 964 | 963 | AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type; |
| 965 | assert(return_type_node->codegen_node); | |
| 966 | return return_type_node->codegen_node->data.type_node.entry; | |
| 964 | assert(return_type_node->type == NodeTypeType); | |
| 965 | return return_type_node->data.type.entry; | |
| 967 | 966 | } |
| 968 | 967 | |
| 969 | 968 | static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) { |
| ... | ... | @@ -1003,15 +1002,14 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, |
| 1003 | 1002 | zig_unreachable(); |
| 1004 | 1003 | } |
| 1005 | 1004 | |
| 1006 | static TypeTableEntry * resolve_rhs_number_literal(CodeGen *g, AstNode *non_literal_node, | |
| 1005 | static TypeTableEntry *resolve_rhs_number_literal(CodeGen *g, AstNode *non_literal_node, | |
| 1007 | 1006 | TypeTableEntry *non_literal_type, AstNode *literal_node, TypeTableEntry *literal_type) |
| 1008 | 1007 | { |
| 1009 | assert(literal_node->codegen_node); | |
| 1010 | NumberLiteralNode *codegen_num_lit = &literal_node->codegen_node->data.num_lit_node; | |
| 1008 | NumLitCodeGen *num_lit_codegen = get_resolved_num_lit(literal_node); | |
| 1011 | 1009 | |
| 1012 | 1010 | if (non_literal_type && num_lit_fits_in_other_type(g, literal_type, non_literal_type)) { |
| 1013 | assert(!codegen_num_lit->resolved_type); | |
| 1014 | codegen_num_lit->resolved_type = non_literal_type; | |
| 1011 | assert(!num_lit_codegen->resolved_type); | |
| 1012 | num_lit_codegen->resolved_type = non_literal_type; | |
| 1015 | 1013 | return non_literal_type; |
| 1016 | 1014 | } else { |
| 1017 | 1015 | return nullptr; |
| ... | ... | @@ -1024,11 +1022,8 @@ static TypeTableEntry * resolve_number_literals(CodeGen *g, AstNode *node1, AstN |
| 1024 | 1022 | if (type1->id == TypeTableEntryIdNumberLiteral && |
| 1025 | 1023 | type2->id == TypeTableEntryIdNumberLiteral) |
| 1026 | 1024 | { |
| 1027 | assert(node1->codegen_node); | |
| 1028 | assert(node2->codegen_node); | |
| 1029 | ||
| 1030 | NumberLiteralNode *codegen_num_lit_1 = &node1->codegen_node->data.num_lit_node; | |
| 1031 | NumberLiteralNode *codegen_num_lit_2 = &node2->codegen_node->data.num_lit_node; | |
| 1025 | NumLitCodeGen *codegen_num_lit_1 = get_resolved_num_lit(node1); | |
| 1026 | NumLitCodeGen *codegen_num_lit_2 = get_resolved_num_lit(node2); | |
| 1032 | 1027 | |
| 1033 | 1028 | assert(!codegen_num_lit_1->resolved_type); |
| 1034 | 1029 | assert(!codegen_num_lit_2->resolved_type); |
| ... | ... | @@ -1113,9 +1108,10 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont |
| 1113 | 1108 | if (actual_type->id == TypeTableEntryIdNumberLiteral && |
| 1114 | 1109 | num_lit_fits_in_other_type(g, actual_type, expected_type)) |
| 1115 | 1110 | { |
| 1116 | assert(!node->codegen_node->data.num_lit_node.resolved_type || | |
| 1117 | node->codegen_node->data.num_lit_node.resolved_type == expected_type); | |
| 1118 | node->codegen_node->data.num_lit_node.resolved_type = expected_type; | |
| 1111 | NumLitCodeGen *num_lit_code_gen = get_resolved_num_lit(node); | |
| 1112 | assert(!num_lit_code_gen->resolved_type || | |
| 1113 | num_lit_code_gen->resolved_type == expected_type); | |
| 1114 | num_lit_code_gen->resolved_type = expected_type; | |
| 1119 | 1115 | return expected_type; |
| 1120 | 1116 | } |
| 1121 | 1117 | |
| ... | ... | @@ -1134,10 +1130,11 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont |
| 1134 | 1130 | if (resolved_type->id == TypeTableEntryIdInvalid) { |
| 1135 | 1131 | return resolved_type; |
| 1136 | 1132 | } |
| 1137 | node->codegen_node->expr_node.implicit_maybe_cast.op = CastOpMaybeWrap; | |
| 1138 | node->codegen_node->expr_node.implicit_maybe_cast.after_type = expected_type; | |
| 1139 | node->codegen_node->expr_node.implicit_maybe_cast.source_node = node; | |
| 1140 | context->cast_expr_alloca_list.append(&node->codegen_node->expr_node.implicit_maybe_cast); | |
| 1133 | Expr *expr = get_resolved_expr(node); | |
| 1134 | expr->implicit_maybe_cast.op = CastOpMaybeWrap; | |
| 1135 | expr->implicit_maybe_cast.after_type = expected_type; | |
| 1136 | expr->implicit_maybe_cast.source_node = node; | |
| 1137 | context->cast_expr_alloca_list.append(&expr->implicit_maybe_cast); | |
| 1141 | 1138 | return expected_type; |
| 1142 | 1139 | } |
| 1143 | 1140 | |
| ... | ... | @@ -1147,9 +1144,10 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont |
| 1147 | 1144 | expected_type->data.integral.is_signed == actual_type->data.integral.is_signed && |
| 1148 | 1145 | expected_type->size_in_bits > actual_type->size_in_bits) |
| 1149 | 1146 | { |
| 1150 | node->codegen_node->expr_node.implicit_cast.after_type = expected_type; | |
| 1151 | node->codegen_node->expr_node.implicit_cast.op = CastOpIntWidenOrShorten; | |
| 1152 | node->codegen_node->expr_node.implicit_cast.source_node = node; | |
| 1147 | Expr *expr = get_resolved_expr(node); | |
| 1148 | expr->implicit_cast.after_type = expected_type; | |
| 1149 | expr->implicit_cast.op = CastOpIntWidenOrShorten; | |
| 1150 | expr->implicit_cast.source_node = node; | |
| 1153 | 1151 | return expected_type; |
| 1154 | 1152 | } |
| 1155 | 1153 | |
| ... | ... | @@ -1159,10 +1157,11 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont |
| 1159 | 1157 | actual_type->id == TypeTableEntryIdArray && |
| 1160 | 1158 | actual_type->data.array.child_type == expected_type->data.structure.fields[0].type_entry->data.pointer.child_type) |
| 1161 | 1159 | { |
| 1162 | node->codegen_node->expr_node.implicit_cast.after_type = expected_type; | |
| 1163 | node->codegen_node->expr_node.implicit_cast.op = CastOpToUnknownSizeArray; | |
| 1164 | node->codegen_node->expr_node.implicit_cast.source_node = node; | |
| 1165 | context->cast_expr_alloca_list.append(&node->codegen_node->expr_node.implicit_cast); | |
| 1160 | Expr *expr = get_resolved_expr(node); | |
| 1161 | expr->implicit_cast.after_type = expected_type; | |
| 1162 | expr->implicit_cast.op = CastOpToUnknownSizeArray; | |
| 1163 | expr->implicit_cast.source_node = node; | |
| 1164 | context->cast_expr_alloca_list.append(&expr->implicit_cast); | |
| 1166 | 1165 | return expected_type; |
| 1167 | 1166 | } |
| 1168 | 1167 | |
| ... | ... | @@ -1225,7 +1224,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) { |
| 1225 | 1224 | |
| 1226 | 1225 | if (node && node->type == NodeTypeFnDef) { |
| 1227 | 1226 | AstNode *fn_proto_node = node->data.fn_def.fn_proto; |
| 1228 | context->fn_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; | |
| 1227 | context->fn_entry = fn_proto_node->data.fn_proto.fn_table_entry; | |
| 1229 | 1228 | } else if (parent) { |
| 1230 | 1229 | context->fn_entry = parent->fn_entry; |
| 1231 | 1230 | } |
| ... | ... | @@ -1275,6 +1274,8 @@ static void get_struct_field(TypeTableEntry *struct_type, Buf *name, TypeStructF |
| 1275 | 1274 | static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1276 | 1275 | AstNode *node) |
| 1277 | 1276 | { |
| 1277 | assert(node->type == NodeTypeFieldAccessExpr); | |
| 1278 | ||
| 1278 | 1279 | TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, |
| 1279 | 1280 | node->data.field_access_expr.struct_expr); |
| 1280 | 1281 | |
| ... | ... | @@ -1283,20 +1284,16 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 1283 | 1284 | if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && |
| 1284 | 1285 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) |
| 1285 | 1286 | { |
| 1286 | assert(node->codegen_node); | |
| 1287 | FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node; | |
| 1288 | assert(codegen_field_access); | |
| 1289 | ||
| 1290 | 1287 | Buf *field_name = &node->data.field_access_expr.field_name; |
| 1291 | 1288 | |
| 1292 | 1289 | TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ? |
| 1293 | 1290 | struct_type : struct_type->data.pointer.child_type; |
| 1294 | 1291 | |
| 1295 | 1292 | get_struct_field(bare_struct_type, field_name, |
| 1296 | &codegen_field_access->type_struct_field, | |
| 1297 | &codegen_field_access->field_index); | |
| 1298 | if (codegen_field_access->type_struct_field) { | |
| 1299 | return_type = codegen_field_access->type_struct_field->type_entry; | |
| 1293 | &node->data.field_access_expr.type_struct_field, | |
| 1294 | &node->data.field_access_expr.field_index); | |
| 1295 | if (node->data.field_access_expr.type_struct_field) { | |
| 1296 | return_type = node->data.field_access_expr.type_struct_field->type_entry; | |
| 1300 | 1297 | } else { |
| 1301 | 1298 | add_node_error(g, node, |
| 1302 | 1299 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&struct_type->name))); |
| ... | ... | @@ -1329,6 +1326,8 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 1329 | 1326 | static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1330 | 1327 | AstNode *node) |
| 1331 | 1328 | { |
| 1329 | assert(node->type == NodeTypeSliceExpr); | |
| 1330 | ||
| 1332 | 1331 | TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr, |
| 1333 | 1332 | node->data.slice_expr.array_ref_expr); |
| 1334 | 1333 | |
| ... | ... | @@ -1355,10 +1354,9 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, |
| 1355 | 1354 | } |
| 1356 | 1355 | |
| 1357 | 1356 | if (return_type->id != TypeTableEntryIdInvalid) { |
| 1358 | assert(node->codegen_node); | |
| 1359 | node->codegen_node->data.struct_val_expr_node.type_entry = return_type; | |
| 1360 | node->codegen_node->data.struct_val_expr_node.source_node = node; | |
| 1361 | context->struct_val_expr_alloca_list.append(&node->codegen_node->data.struct_val_expr_node); | |
| 1357 | node->data.slice_expr.resolved_struct_val_expr.type_entry = return_type; | |
| 1358 | node->data.slice_expr.resolved_struct_val_expr.source_node = node; | |
| 1359 | context->struct_val_expr_alloca_list.append(&node->data.slice_expr.resolved_struct_val_expr); | |
| 1362 | 1360 | } |
| 1363 | 1361 | |
| 1364 | 1362 | analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.start); |
| ... | ... | @@ -1463,6 +1461,8 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { |
| 1463 | 1461 | static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1464 | 1462 | TypeTableEntry *expected_type, AstNode *node) |
| 1465 | 1463 | { |
| 1464 | assert(node->type == NodeTypeCastExpr); | |
| 1465 | ||
| 1466 | 1466 | TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type, import, context, false); |
| 1467 | 1467 | TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr); |
| 1468 | 1468 | |
| ... | ... | @@ -1472,43 +1472,41 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 1472 | 1472 | return g->builtin_types.entry_invalid; |
| 1473 | 1473 | } |
| 1474 | 1474 | |
| 1475 | CastNode *cast_node = &node->codegen_node->data.cast_node; | |
| 1476 | cast_node->source_node = node; | |
| 1477 | cast_node->after_type = wanted_type; | |
| 1475 | Cast *cast = &node->data.cast_expr.cast; | |
| 1476 | cast->source_node = node; | |
| 1477 | cast->after_type = wanted_type; | |
| 1478 | 1478 | |
| 1479 | // special casing this for now, TODO think about casting and do a general solution | |
| 1480 | 1479 | if ((wanted_type == g->builtin_types.entry_isize || wanted_type == g->builtin_types.entry_usize) && |
| 1481 | 1480 | actual_type->id == TypeTableEntryIdPointer) |
| 1482 | 1481 | { |
| 1483 | cast_node->op = CastOpPtrToInt; | |
| 1482 | cast->op = CastOpPtrToInt; | |
| 1484 | 1483 | return wanted_type; |
| 1485 | 1484 | } else if (wanted_type->id == TypeTableEntryIdInt && |
| 1486 | 1485 | actual_type->id == TypeTableEntryIdInt) |
| 1487 | 1486 | { |
| 1488 | cast_node->op = CastOpIntWidenOrShorten; | |
| 1487 | cast->op = CastOpIntWidenOrShorten; | |
| 1489 | 1488 | return wanted_type; |
| 1490 | 1489 | } else if (wanted_type->id == TypeTableEntryIdStruct && |
| 1491 | 1490 | wanted_type->data.structure.is_unknown_size_array && |
| 1492 | 1491 | actual_type->id == TypeTableEntryIdArray && |
| 1493 | 1492 | actual_type->data.array.child_type == wanted_type->data.structure.fields[0].type_entry) |
| 1494 | 1493 | { |
| 1495 | cast_node->op = CastOpToUnknownSizeArray; | |
| 1496 | context->cast_expr_alloca_list.append(cast_node); | |
| 1494 | cast->op = CastOpToUnknownSizeArray; | |
| 1495 | context->cast_expr_alloca_list.append(cast); | |
| 1497 | 1496 | return wanted_type; |
| 1498 | 1497 | } else if (actual_type->id == TypeTableEntryIdNumberLiteral && |
| 1499 | 1498 | num_lit_fits_in_other_type(g, actual_type, wanted_type)) |
| 1500 | 1499 | { |
| 1501 | 1500 | AstNode *literal_node = node->data.cast_expr.expr; |
| 1502 | assert(literal_node->codegen_node); | |
| 1503 | NumberLiteralNode *codegen_num_lit = &literal_node->codegen_node->data.num_lit_node; | |
| 1501 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(literal_node); | |
| 1504 | 1502 | assert(!codegen_num_lit->resolved_type); |
| 1505 | 1503 | codegen_num_lit->resolved_type = wanted_type; |
| 1506 | cast_node->op = CastOpNothing; | |
| 1504 | cast->op = CastOpNothing; | |
| 1507 | 1505 | return wanted_type; |
| 1508 | 1506 | } else if (actual_type->id == TypeTableEntryIdPointer && |
| 1509 | 1507 | wanted_type->id == TypeTableEntryIdPointer) |
| 1510 | 1508 | { |
| 1511 | cast_node->op = CastOpPointerReinterpret; | |
| 1509 | cast->op = CastOpPointerReinterpret; | |
| 1512 | 1510 | return wanted_type; |
| 1513 | 1511 | } else { |
| 1514 | 1512 | add_node_error(g, node, |
| ... | ... | @@ -1529,7 +1527,7 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc |
| 1529 | 1527 | { |
| 1530 | 1528 | TypeTableEntry *expected_rhs_type = nullptr; |
| 1531 | 1529 | if (lhs_node->type == NodeTypeSymbol) { |
| 1532 | Buf *name = &lhs_node->data.symbol; | |
| 1530 | Buf *name = &lhs_node->data.symbol_expr.symbol; | |
| 1533 | 1531 | VariableTableEntry *var = find_variable(block_context, name); |
| 1534 | 1532 | if (var) { |
| 1535 | 1533 | if (purpose == LValPurposeAssign && var->is_const) { |
| ... | ... | @@ -1551,7 +1549,6 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc |
| 1551 | 1549 | } else if (lhs_node->type == NodeTypeArrayAccessExpr) { |
| 1552 | 1550 | expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node); |
| 1553 | 1551 | } else if (lhs_node->type == NodeTypeFieldAccessExpr) { |
| 1554 | alloc_codegen_node(lhs_node); | |
| 1555 | 1552 | expected_rhs_type = analyze_field_access_expr(g, import, block_context, lhs_node); |
| 1556 | 1553 | } else if (lhs_node->type == NodeTypePrefixOpExpr && |
| 1557 | 1554 | lhs_node->data.prefix_op_expr.prefix_op == PrefixOpDereference) |
| ... | ... | @@ -1774,10 +1771,9 @@ static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *i |
| 1774 | 1771 | if (expected_type) { |
| 1775 | 1772 | assert(expected_type->id == TypeTableEntryIdMaybe); |
| 1776 | 1773 | |
| 1777 | assert(node->codegen_node); | |
| 1778 | node->codegen_node->data.struct_val_expr_node.type_entry = expected_type; | |
| 1779 | node->codegen_node->data.struct_val_expr_node.source_node = node; | |
| 1780 | block_context->struct_val_expr_alloca_list.append(&node->codegen_node->data.struct_val_expr_node); | |
| 1774 | node->data.null_literal.resolved_struct_val_expr.type_entry = expected_type; | |
| 1775 | node->data.null_literal.resolved_struct_val_expr.source_node = node; | |
| 1776 | block_context->struct_val_expr_alloca_list.append(&node->data.null_literal.resolved_struct_val_expr); | |
| 1781 | 1777 | |
| 1782 | 1778 | return expected_type; |
| 1783 | 1779 | } else { |
| ... | ... | @@ -1796,7 +1792,7 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry |
| 1796 | 1792 | buf_sprintf("number literal too large to be represented in any type")); |
| 1797 | 1793 | return g->builtin_types.entry_invalid; |
| 1798 | 1794 | } else if (expected_type) { |
| 1799 | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; | |
| 1795 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); | |
| 1800 | 1796 | assert(!codegen_num_lit->resolved_type); |
| 1801 | 1797 | TypeTableEntry *after_implicit_cast_resolved_type = |
| 1802 | 1798 | resolve_type_compatibility(g, block_context, node, expected_type, num_lit_type); |
| ... | ... | @@ -1837,10 +1833,9 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp |
| 1837 | 1833 | return g->builtin_types.entry_invalid; |
| 1838 | 1834 | } |
| 1839 | 1835 | |
| 1840 | assert(node->codegen_node); | |
| 1841 | node->codegen_node->data.struct_val_expr_node.type_entry = type_entry; | |
| 1842 | node->codegen_node->data.struct_val_expr_node.source_node = node; | |
| 1843 | context->struct_val_expr_alloca_list.append(&node->codegen_node->data.struct_val_expr_node); | |
| 1836 | node->data.struct_val_expr.codegen.type_entry = type_entry; | |
| 1837 | node->data.struct_val_expr.codegen.source_node = node; | |
| 1838 | context->struct_val_expr_alloca_list.append(&node->data.struct_val_expr.codegen); | |
| 1844 | 1839 | |
| 1845 | 1840 | int expr_field_count = struct_val_expr->fields.length; |
| 1846 | 1841 | int actual_field_count = type_entry->data.structure.field_count; |
| ... | ... | @@ -1848,6 +1843,8 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp |
| 1848 | 1843 | int *field_use_counts = allocate<int>(actual_field_count); |
| 1849 | 1844 | for (int i = 0; i < expr_field_count; i += 1) { |
| 1850 | 1845 | AstNode *val_field_node = struct_val_expr->fields.at(i); |
| 1846 | assert(val_field_node->type == NodeTypeStructValueField); | |
| 1847 | ||
| 1851 | 1848 | int field_index; |
| 1852 | 1849 | TypeStructField *type_field = find_struct_type_field(type_entry, |
| 1853 | 1850 | &val_field_node->data.struct_val_field.name, &field_index); |
| ... | ... | @@ -1865,8 +1862,7 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp |
| 1865 | 1862 | continue; |
| 1866 | 1863 | } |
| 1867 | 1864 | |
| 1868 | alloc_codegen_node(val_field_node); | |
| 1869 | val_field_node->codegen_node->data.struct_val_field_node.index = field_index; | |
| 1865 | val_field_node->data.struct_val_field.index = field_index; | |
| 1870 | 1866 | |
| 1871 | 1867 | analyze_expression(g, import, context, type_field->type_entry, |
| 1872 | 1868 | val_field_node->data.struct_val_field.expr); |
| ... | ... | @@ -1885,6 +1881,8 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp |
| 1885 | 1881 | static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1886 | 1882 | TypeTableEntry *expected_type, AstNode *node) |
| 1887 | 1883 | { |
| 1884 | assert(node->type == NodeTypeWhileExpr); | |
| 1885 | ||
| 1888 | 1886 | AstNode *condition_node = node->data.while_expr.condition; |
| 1889 | 1887 | AstNode *while_body_node = node->data.while_expr.body; |
| 1890 | 1888 | TypeTableEntry *condition_type = analyze_expression(g, import, context, |
| ... | ... | @@ -1907,8 +1905,8 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, |
| 1907 | 1905 | assert(resolved_type->id == TypeTableEntryIdBool); |
| 1908 | 1906 | bool constant_cond_value = number_literal.data.x_uint; |
| 1909 | 1907 | if (constant_cond_value) { |
| 1910 | node->codegen_node->data.while_node.condition_always_true = true; | |
| 1911 | if (!node->codegen_node->data.while_node.contains_break) { | |
| 1908 | node->data.while_expr.condition_always_true = true; | |
| 1909 | if (!node->data.while_expr.contains_break) { | |
| 1912 | 1910 | expr_return_type = g->builtin_types.entry_unreachable; |
| 1913 | 1911 | } |
| 1914 | 1912 | } |
| ... | ... | @@ -1921,12 +1919,14 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, |
| 1921 | 1919 | static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1922 | 1920 | TypeTableEntry *expected_type, AstNode *node) |
| 1923 | 1921 | { |
| 1922 | assert(node->type == NodeTypeBreak); | |
| 1923 | ||
| 1924 | 1924 | AstNode *loop_node = context->parent_loop_node; |
| 1925 | 1925 | if (loop_node) { |
| 1926 | loop_node->codegen_node->data.while_node.contains_break = true; | |
| 1926 | assert(loop_node->type == NodeTypeWhileExpr); | |
| 1927 | loop_node->data.while_expr.contains_break = true; | |
| 1927 | 1928 | } else { |
| 1928 | add_node_error(g, node, | |
| 1929 | buf_sprintf("'break' expression outside loop")); | |
| 1929 | add_node_error(g, node, buf_sprintf("'break' expression outside loop")); | |
| 1930 | 1930 | } |
| 1931 | 1931 | return g->builtin_types.entry_unreachable; |
| 1932 | 1932 | } |
| ... | ... | @@ -1935,8 +1935,7 @@ static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *impor |
| 1935 | 1935 | TypeTableEntry *expected_type, AstNode *node) |
| 1936 | 1936 | { |
| 1937 | 1937 | if (!context->parent_loop_node) { |
| 1938 | add_node_error(g, node, | |
| 1939 | buf_sprintf("'continue' expression outside loop")); | |
| 1938 | add_node_error(g, node, buf_sprintf("'continue' expression outside loop")); | |
| 1940 | 1939 | } |
| 1941 | 1940 | return g->builtin_types.entry_unreachable; |
| 1942 | 1941 | } |
| ... | ... | @@ -1981,7 +1980,7 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, |
| 1981 | 1980 | assert(node->type == NodeTypeIfVarExpr); |
| 1982 | 1981 | |
| 1983 | 1982 | BlockContext *child_context = new_block_context(node, context); |
| 1984 | node->codegen_node->data.if_var_node.block_context = child_context; | |
| 1983 | node->data.if_var_expr.block_context = child_context; | |
| 1985 | 1984 | |
| 1986 | 1985 | analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true); |
| 1987 | 1986 | |
| ... | ... | @@ -2032,8 +2031,10 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im |
| 2032 | 2031 | static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2033 | 2032 | TypeTableEntry *expected_type, AstNode *node) |
| 2034 | 2033 | { |
| 2034 | assert(node->type == NodeTypeFnCallExpr); | |
| 2035 | ||
| 2035 | 2036 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; |
| 2036 | Buf *name = &fn_ref_expr->data.symbol; | |
| 2037 | Buf *name = &fn_ref_expr->data.symbol_expr.symbol; | |
| 2037 | 2038 | |
| 2038 | 2039 | auto entry = g->builtin_fn_table.maybe_get(name); |
| 2039 | 2040 | |
| ... | ... | @@ -2041,8 +2042,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 2041 | 2042 | BuiltinFnEntry *builtin_fn = entry->value; |
| 2042 | 2043 | int actual_param_count = node->data.fn_call_expr.params.length; |
| 2043 | 2044 | |
| 2044 | assert(node->codegen_node); | |
| 2045 | node->codegen_node->data.fn_call_node.builtin_fn = builtin_fn; | |
| 2045 | node->data.fn_call_expr.builtin_fn = builtin_fn; | |
| 2046 | 2046 | |
| 2047 | 2047 | if (builtin_fn->param_count != actual_param_count) { |
| 2048 | 2048 | add_node_error(g, node, |
| ... | ... | @@ -2155,7 +2155,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 2155 | 2155 | if (node->data.fn_call_expr.is_builtin) { |
| 2156 | 2156 | return analyze_builtin_fn_call_expr(g, import, context, expected_type, node); |
| 2157 | 2157 | } |
| 2158 | name = &fn_ref_expr->data.symbol; | |
| 2158 | name = &fn_ref_expr->data.symbol_expr.symbol; | |
| 2159 | 2159 | } else { |
| 2160 | 2160 | add_node_error(g, node, |
| 2161 | 2161 | buf_sprintf("function pointers not yet supported")); |
| ... | ... | @@ -2210,13 +2210,15 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 2210 | 2210 | AstNode *param_decl_node = fn_proto->params.at(fn_proto_i); |
| 2211 | 2211 | assert(param_decl_node->type == NodeTypeParamDecl); |
| 2212 | 2212 | AstNode *param_type_node = param_decl_node->data.param_decl.type; |
| 2213 | if (param_type_node->codegen_node) | |
| 2214 | expected_param_type = param_type_node->codegen_node->data.type_node.entry; | |
| 2213 | assert(param_type_node->type == NodeTypeType); | |
| 2214 | if (param_type_node->data.type.entry) { | |
| 2215 | expected_param_type = param_type_node->data.type.entry; | |
| 2216 | } | |
| 2215 | 2217 | } |
| 2216 | 2218 | analyze_expression(g, import, context, expected_param_type, child); |
| 2217 | 2219 | } |
| 2218 | 2220 | |
| 2219 | return fn_proto->return_type->codegen_node->data.type_node.entry; | |
| 2221 | return fn_proto->return_type->data.type.entry; | |
| 2220 | 2222 | } |
| 2221 | 2223 | } |
| 2222 | 2224 | |
| ... | ... | @@ -2224,18 +2226,17 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2224 | 2226 | TypeTableEntry *expected_type, AstNode *node) |
| 2225 | 2227 | { |
| 2226 | 2228 | TypeTableEntry *return_type = nullptr; |
| 2227 | alloc_codegen_node(node); | |
| 2228 | 2229 | switch (node->type) { |
| 2229 | 2230 | case NodeTypeBlock: |
| 2230 | 2231 | { |
| 2231 | 2232 | BlockContext *child_context = new_block_context(node, context); |
| 2232 | node->codegen_node->data.block_node.block_context = child_context; | |
| 2233 | node->data.block.block_context = child_context; | |
| 2233 | 2234 | return_type = g->builtin_types.entry_void; |
| 2234 | 2235 | |
| 2235 | 2236 | for (int i = 0; i < node->data.block.statements.length; i += 1) { |
| 2236 | 2237 | AstNode *child = node->data.block.statements.at(i); |
| 2237 | 2238 | if (child->type == NodeTypeLabel) { |
| 2238 | LabelTableEntry *label_entry = child->codegen_node->data.label_entry; | |
| 2239 | LabelTableEntry *label_entry = child->data.label.label_entry; | |
| 2239 | 2240 | assert(label_entry); |
| 2240 | 2241 | label_entry->entered_from_fallthrough = (return_type->id != TypeTableEntryIdUnreachable); |
| 2241 | 2242 | return_type = g->builtin_types.entry_void; |
| ... | ... | @@ -2288,13 +2289,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2288 | 2289 | case NodeTypeGoto: |
| 2289 | 2290 | { |
| 2290 | 2291 | FnTableEntry *fn_table_entry = get_context_fn_entry(context); |
| 2291 | auto table_entry = fn_table_entry->label_table.maybe_get(&node->data.go_to.name); | |
| 2292 | auto table_entry = fn_table_entry->label_table.maybe_get(&node->data.goto_expr.name); | |
| 2292 | 2293 | if (table_entry) { |
| 2293 | node->codegen_node->data.label_entry = table_entry->value; | |
| 2294 | node->data.goto_expr.label_entry = table_entry->value; | |
| 2294 | 2295 | table_entry->value->used = true; |
| 2295 | 2296 | } else { |
| 2296 | 2297 | add_node_error(g, node, |
| 2297 | buf_sprintf("use of undeclared label '%s'", buf_ptr(&node->data.go_to.name))); | |
| 2298 | buf_sprintf("use of undeclared label '%s'", buf_ptr(&node->data.goto_expr.name))); | |
| 2298 | 2299 | } |
| 2299 | 2300 | return_type = g->builtin_types.entry_unreachable; |
| 2300 | 2301 | break; |
| ... | ... | @@ -2380,7 +2381,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2380 | 2381 | |
| 2381 | 2382 | case NodeTypeSymbol: |
| 2382 | 2383 | { |
| 2383 | return_type = analyze_variable_name(g, import, context, node, &node->data.symbol); | |
| 2384 | return_type = analyze_variable_name(g, import, context, node, &node->data.symbol_expr.symbol); | |
| 2384 | 2385 | break; |
| 2385 | 2386 | } |
| 2386 | 2387 | case NodeTypeCastExpr: |
| ... | ... | @@ -2507,8 +2508,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2507 | 2508 | assert(return_type); |
| 2508 | 2509 | resolve_type_compatibility(g, context, node, expected_type, return_type); |
| 2509 | 2510 | |
| 2510 | node->codegen_node->expr_node.type_entry = return_type; | |
| 2511 | node->codegen_node->expr_node.block_context = context; | |
| 2511 | get_resolved_expr(node)->type_entry = return_type; | |
| 2512 | get_resolved_expr(node)->block_context = context; | |
| 2512 | 2513 | |
| 2513 | 2514 | return return_type; |
| 2514 | 2515 | } |
| ... | ... | @@ -2519,15 +2520,14 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo |
| 2519 | 2520 | AstNode *fn_proto_node = node->data.fn_def.fn_proto; |
| 2520 | 2521 | assert(fn_proto_node->type == NodeTypeFnProto); |
| 2521 | 2522 | |
| 2522 | if (fn_proto_node->codegen_node->data.fn_proto_node.skip) { | |
| 2523 | if (fn_proto_node->data.fn_proto.skip) { | |
| 2523 | 2524 | // we detected an error with this function definition which prevents us |
| 2524 | 2525 | // from further analyzing it. |
| 2525 | 2526 | return; |
| 2526 | 2527 | } |
| 2527 | 2528 | |
| 2528 | alloc_codegen_node(node); | |
| 2529 | 2529 | BlockContext *context = new_block_context(node, import->block_context); |
| 2530 | node->codegen_node->data.fn_def_node.block_context = context; | |
| 2530 | node->data.fn_def.block_context = context; | |
| 2531 | 2531 | |
| 2532 | 2532 | AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; |
| 2533 | 2533 | bool is_exported = (fn_proto->visib_mod == VisibModExport); |
| ... | ... | @@ -2538,7 +2538,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo |
| 2538 | 2538 | // define local variables for parameters |
| 2539 | 2539 | AstNodeParamDecl *param_decl = &param_decl_node->data.param_decl; |
| 2540 | 2540 | assert(param_decl->type->type == NodeTypeType); |
| 2541 | TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; | |
| 2541 | TypeTableEntry *type = param_decl->type->data.type.entry; | |
| 2542 | 2542 | |
| 2543 | 2543 | if (is_exported && type->id == TypeTableEntryIdStruct) { |
| 2544 | 2544 | add_node_error(g, param_decl_node, |
| ... | ... | @@ -2552,8 +2552,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo |
| 2552 | 2552 | variable_entry->decl_node = param_decl_node; |
| 2553 | 2553 | variable_entry->arg_index = i; |
| 2554 | 2554 | |
| 2555 | alloc_codegen_node(param_decl_node); | |
| 2556 | param_decl_node->codegen_node->data.param_decl_node.variable = variable_entry; | |
| 2555 | param_decl_node->data.param_decl.variable = variable_entry; | |
| 2557 | 2556 | |
| 2558 | 2557 | VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); |
| 2559 | 2558 | if (!existing_entry) { |
| ... | ... | @@ -2571,13 +2570,13 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo |
| 2571 | 2570 | } |
| 2572 | 2571 | } |
| 2573 | 2572 | |
| 2574 | TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry; | |
| 2573 | TypeTableEntry *expected_type = fn_proto->return_type->data.type.entry; | |
| 2575 | 2574 | TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); |
| 2576 | 2575 | |
| 2577 | node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type; | |
| 2576 | node->data.fn_def.implicit_return_type = block_return_type; | |
| 2578 | 2577 | |
| 2579 | 2578 | { |
| 2580 | FnTableEntry *fn_table_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; | |
| 2579 | FnTableEntry *fn_table_entry = fn_proto_node->data.fn_proto.fn_table_entry; | |
| 2581 | 2580 | auto it = fn_table_entry->label_table.entry_iterator(); |
| 2582 | 2581 | for (;;) { |
| 2583 | 2582 | auto *entry = it.next(); |
| ... | ... | @@ -2656,7 +2655,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 2656 | 2655 | } |
| 2657 | 2656 | |
| 2658 | 2657 | static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *expr_node, |
| 2659 | DeclNode *decl_node) | |
| 2658 | TopLevelDecl *decl_node) | |
| 2660 | 2659 | { |
| 2661 | 2660 | switch (expr_node->type) { |
| 2662 | 2661 | case NodeTypeNumberLiteral: |
| ... | ... | @@ -2672,7 +2671,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode |
| 2672 | 2671 | // no dependencies on other top level declarations |
| 2673 | 2672 | break; |
| 2674 | 2673 | case NodeTypeSymbol: |
| 2675 | decl_node->deps.put(&expr_node->data.symbol, expr_node); | |
| 2674 | decl_node->deps.put(&expr_node->data.symbol_expr.symbol, expr_node); | |
| 2676 | 2675 | break; |
| 2677 | 2676 | case NodeTypeBinOpExpr: |
| 2678 | 2677 | collect_expr_decl_deps(g, import, expr_node->data.bin_op_expr.op1, decl_node); |
| ... | ... | @@ -2787,7 +2786,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode |
| 2787 | 2786 | } |
| 2788 | 2787 | } |
| 2789 | 2788 | |
| 2790 | static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, DeclNode *decl_node) { | |
| 2789 | static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, TopLevelDecl *decl_node) { | |
| 2791 | 2790 | assert(type_node->type == NodeTypeType); |
| 2792 | 2791 | switch (type_node->data.type.type) { |
| 2793 | 2792 | case AstNodeTypeTypePrimitive: |
| ... | ... | @@ -2824,16 +2823,13 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 2824 | 2823 | switch (node->type) { |
| 2825 | 2824 | case NodeTypeStructDecl: |
| 2826 | 2825 | { |
| 2827 | alloc_codegen_node(node); | |
| 2828 | StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node; | |
| 2829 | ||
| 2830 | 2826 | Buf *name = &node->data.struct_decl.name; |
| 2831 | 2827 | auto table_entry = g->primitive_type_table.maybe_get(name); |
| 2832 | 2828 | if (!table_entry) { |
| 2833 | 2829 | table_entry = import->type_table.maybe_get(name); |
| 2834 | 2830 | } |
| 2835 | 2831 | if (table_entry) { |
| 2836 | struct_codegen->type_entry = table_entry->value; | |
| 2832 | node->data.struct_decl.type_entry = table_entry->value; | |
| 2837 | 2833 | add_node_error(g, node, |
| 2838 | 2834 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); |
| 2839 | 2835 | } else { |
| ... | ... | @@ -2848,7 +2844,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 2848 | 2844 | // put off adding the debug type until we do the full struct body |
| 2849 | 2845 | // this type is incomplete until we do another pass |
| 2850 | 2846 | import->type_table.put(&entry->name, entry); |
| 2851 | struct_codegen->type_entry = entry; | |
| 2847 | node->data.struct_decl.type_entry = entry; | |
| 2852 | 2848 | |
| 2853 | 2849 | bool is_pub = (node->data.struct_decl.visib_mod != VisibModPrivate); |
| 2854 | 2850 | if (is_pub) { |
| ... | ... | @@ -2867,14 +2863,15 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 2867 | 2863 | } |
| 2868 | 2864 | |
| 2869 | 2865 | // determine which other top level declarations this struct depends on. |
| 2870 | DeclNode *decl_node = &node->codegen_node->decl_node; | |
| 2866 | TopLevelDecl *decl_node = &node->data.struct_decl.top_level_decl; | |
| 2867 | decl_node->deps.init(1); | |
| 2871 | 2868 | for (int i = 0; i < node->data.struct_decl.fields.length; i += 1) { |
| 2872 | 2869 | AstNode *field_node = node->data.struct_decl.fields.at(i); |
| 2873 | 2870 | AstNode *type_node = field_node->data.struct_field.type; |
| 2874 | 2871 | collect_type_decl_deps(g, import, type_node, decl_node); |
| 2875 | 2872 | } |
| 2876 | node->codegen_node->decl_node.name = name; | |
| 2877 | node->codegen_node->decl_node.import = import; | |
| 2873 | decl_node->name = name; | |
| 2874 | decl_node->import = import; | |
| 2878 | 2875 | if (decl_node->deps.size() > 0) { |
| 2879 | 2876 | g->unresolved_top_level_decls.put(name, node); |
| 2880 | 2877 | } else { |
| ... | ... | @@ -2913,8 +2910,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 2913 | 2910 | case NodeTypeVariableDeclaration: |
| 2914 | 2911 | { |
| 2915 | 2912 | // determine which other top level declarations this variable declaration depends on. |
| 2916 | alloc_codegen_node(node); | |
| 2917 | DeclNode *decl_node = &node->codegen_node->decl_node; | |
| 2913 | TopLevelDecl *decl_node = &node->data.variable_declaration.top_level_decl; | |
| 2914 | decl_node->deps.init(1); | |
| 2918 | 2915 | if (node->data.variable_declaration.type) { |
| 2919 | 2916 | collect_type_decl_deps(g, import, node->data.variable_declaration.type, decl_node); |
| 2920 | 2917 | } |
| ... | ... | @@ -2922,8 +2919,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 2922 | 2919 | collect_expr_decl_deps(g, import, node->data.variable_declaration.expr, decl_node); |
| 2923 | 2920 | } |
| 2924 | 2921 | Buf *name = &node->data.variable_declaration.symbol; |
| 2925 | node->codegen_node->decl_node.name = name; | |
| 2926 | node->codegen_node->decl_node.import = import; | |
| 2922 | decl_node->name = name; | |
| 2923 | decl_node->import = import; | |
| 2927 | 2924 | if (decl_node->deps.size() > 0) { |
| 2928 | 2925 | g->unresolved_top_level_decls.put(name, node); |
| 2929 | 2926 | } else { |
| ... | ... | @@ -2934,8 +2931,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 2934 | 2931 | case NodeTypeFnProto: |
| 2935 | 2932 | { |
| 2936 | 2933 | // determine which other top level declarations this function prototype depends on. |
| 2937 | alloc_codegen_node(node); | |
| 2938 | DeclNode *decl_node = &node->codegen_node->decl_node; | |
| 2934 | TopLevelDecl *decl_node = &node->data.fn_proto.top_level_decl; | |
| 2935 | decl_node->deps.init(1); | |
| 2939 | 2936 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { |
| 2940 | 2937 | AstNode *param_node = node->data.fn_proto.params.at(i); |
| 2941 | 2938 | assert(param_node->type == NodeTypeParamDecl); |
| ... | ... | @@ -2943,8 +2940,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 2943 | 2940 | } |
| 2944 | 2941 | |
| 2945 | 2942 | Buf *name = &node->data.fn_proto.name; |
| 2946 | node->codegen_node->decl_node.name = name; | |
| 2947 | node->codegen_node->decl_node.import = import; | |
| 2943 | decl_node->name = name; | |
| 2944 | decl_node->import = import; | |
| 2948 | 2945 | if (decl_node->deps.size() > 0) { |
| 2949 | 2946 | g->unresolved_top_level_decls.put(name, node); |
| 2950 | 2947 | } else { |
| ... | ... | @@ -2999,7 +2996,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 2999 | 2996 | } |
| 3000 | 2997 | |
| 3001 | 2998 | static void recursive_resolve_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 3002 | auto it = node->codegen_node->decl_node.deps.entry_iterator(); | |
| 2999 | auto it = get_resolved_top_level_decl(node)->deps.entry_iterator(); | |
| 3003 | 3000 | for (;;) { |
| 3004 | 3001 | auto *entry = it.next(); |
| 3005 | 3002 | if (!entry) |
| ... | ... | @@ -3012,23 +3009,24 @@ static void recursive_resolve_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 3012 | 3009 | |
| 3013 | 3010 | AstNode *child_node = unresolved_entry->value; |
| 3014 | 3011 | |
| 3015 | if (child_node->codegen_node->decl_node.in_current_deps) { | |
| 3012 | if (get_resolved_top_level_decl(child_node)->in_current_deps) { | |
| 3016 | 3013 | // dependency loop. we'll let the fact that it's not in the respective |
| 3017 | 3014 | // table cause an error in resolve_top_level_decl. |
| 3018 | 3015 | continue; |
| 3019 | 3016 | } |
| 3020 | 3017 | |
| 3021 | 3018 | // set temporary flag |
| 3022 | child_node->codegen_node->decl_node.in_current_deps = true; | |
| 3019 | TopLevelDecl *top_level_decl = get_resolved_top_level_decl(child_node); | |
| 3020 | top_level_decl->in_current_deps = true; | |
| 3023 | 3021 | |
| 3024 | recursive_resolve_decl(g, child_node->codegen_node->decl_node.import, child_node); | |
| 3022 | recursive_resolve_decl(g, top_level_decl->import, child_node); | |
| 3025 | 3023 | |
| 3026 | 3024 | // unset temporary flag |
| 3027 | child_node->codegen_node->decl_node.in_current_deps = false; | |
| 3025 | top_level_decl->in_current_deps = false; | |
| 3028 | 3026 | } |
| 3029 | 3027 | |
| 3030 | 3028 | resolve_top_level_decl(g, import, node); |
| 3031 | g->unresolved_top_level_decls.remove(node->codegen_node->decl_node.name); | |
| 3029 | g->unresolved_top_level_decls.remove(get_resolved_top_level_decl(node)->name); | |
| 3032 | 3030 | } |
| 3033 | 3031 | |
| 3034 | 3032 | static void resolve_top_level_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| ... | ... | @@ -3051,12 +3049,13 @@ static void resolve_top_level_declarations_root(CodeGen *g, ImportTableEntry *im |
| 3051 | 3049 | |
| 3052 | 3050 | } |
| 3053 | 3051 | // set temporary flag |
| 3054 | decl_node->codegen_node->decl_node.in_current_deps = true; | |
| 3052 | TopLevelDecl *top_level_decl = get_resolved_top_level_decl(decl_node); | |
| 3053 | top_level_decl->in_current_deps = true; | |
| 3055 | 3054 | |
| 3056 | recursive_resolve_decl(g, decl_node->codegen_node->decl_node.import, decl_node); | |
| 3055 | recursive_resolve_decl(g, top_level_decl->import, decl_node); | |
| 3057 | 3056 | |
| 3058 | 3057 | // unset temporary flag |
| 3059 | decl_node->codegen_node->decl_node.in_current_deps = false; | |
| 3058 | top_level_decl->in_current_deps = false; | |
| 3060 | 3059 | } |
| 3061 | 3060 | } |
| 3062 | 3061 | |
| ... | ... | @@ -3089,7 +3088,7 @@ void semantic_analyze(CodeGen *g) { |
| 3089 | 3088 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); |
| 3090 | 3089 | } |
| 3091 | 3090 | |
| 3092 | ImportTableEntry *target_import = child->codegen_node->data.import_node.import; | |
| 3091 | ImportTableEntry *target_import = child->data.use.import; | |
| 3093 | 3092 | assert(target_import); |
| 3094 | 3093 | |
| 3095 | 3094 | target_import->importers.append({import, child}); |
| ... | ... | @@ -3144,9 +3143,186 @@ void semantic_analyze(CodeGen *g) { |
| 3144 | 3143 | } |
| 3145 | 3144 | } |
| 3146 | 3145 | |
| 3147 | void alloc_codegen_node(AstNode *node) { | |
| 3148 | assert(!node->codegen_node); | |
| 3149 | node->codegen_node = allocate<CodeGenNode>(1); | |
| 3150 | node->codegen_node->decl_node.deps.init(1); | |
| 3146 | Expr *get_resolved_expr(AstNode *node) { | |
| 3147 | switch (node->type) { | |
| 3148 | case NodeTypeReturnExpr: | |
| 3149 | return &node->data.return_expr.resolved_expr; | |
| 3150 | case NodeTypeBinOpExpr: | |
| 3151 | return &node->data.bin_op_expr.resolved_expr; | |
| 3152 | case NodeTypeCastExpr: | |
| 3153 | return &node->data.cast_expr.resolved_expr; | |
| 3154 | case NodeTypePrefixOpExpr: | |
| 3155 | return &node->data.prefix_op_expr.resolved_expr; | |
| 3156 | case NodeTypeFnCallExpr: | |
| 3157 | return &node->data.fn_call_expr.resolved_expr; | |
| 3158 | case NodeTypeArrayAccessExpr: | |
| 3159 | return &node->data.array_access_expr.resolved_expr; | |
| 3160 | case NodeTypeSliceExpr: | |
| 3161 | return &node->data.slice_expr.resolved_expr; | |
| 3162 | case NodeTypeFieldAccessExpr: | |
| 3163 | return &node->data.field_access_expr.resolved_expr; | |
| 3164 | case NodeTypeIfBoolExpr: | |
| 3165 | return &node->data.if_bool_expr.resolved_expr; | |
| 3166 | case NodeTypeIfVarExpr: | |
| 3167 | return &node->data.if_var_expr.resolved_expr; | |
| 3168 | case NodeTypeWhileExpr: | |
| 3169 | return &node->data.while_expr.resolved_expr; | |
| 3170 | case NodeTypeAsmExpr: | |
| 3171 | return &node->data.asm_expr.resolved_expr; | |
| 3172 | case NodeTypeStructValueExpr: | |
| 3173 | return &node->data.struct_val_expr.resolved_expr; | |
| 3174 | case NodeTypeNumberLiteral: | |
| 3175 | return &node->data.number_literal.resolved_expr; | |
| 3176 | case NodeTypeStringLiteral: | |
| 3177 | return &node->data.string_literal.resolved_expr; | |
| 3178 | case NodeTypeBlock: | |
| 3179 | return &node->data.block.resolved_expr; | |
| 3180 | case NodeTypeVoid: | |
| 3181 | return &node->data.void_expr.resolved_expr; | |
| 3182 | case NodeTypeUnreachable: | |
| 3183 | return &node->data.unreachable_expr.resolved_expr; | |
| 3184 | case NodeTypeSymbol: | |
| 3185 | return &node->data.symbol_expr.resolved_expr; | |
| 3186 | case NodeTypeVariableDeclaration: | |
| 3187 | return &node->data.variable_declaration.resolved_expr; | |
| 3188 | case NodeTypeCharLiteral: | |
| 3189 | return &node->data.char_literal.resolved_expr; | |
| 3190 | case NodeTypeBoolLiteral: | |
| 3191 | return &node->data.bool_literal.resolved_expr; | |
| 3192 | case NodeTypeNullLiteral: | |
| 3193 | return &node->data.null_literal.resolved_expr; | |
| 3194 | case NodeTypeGoto: | |
| 3195 | return &node->data.goto_expr.resolved_expr; | |
| 3196 | case NodeTypeBreak: | |
| 3197 | return &node->data.break_expr.resolved_expr; | |
| 3198 | case NodeTypeContinue: | |
| 3199 | return &node->data.continue_expr.resolved_expr; | |
| 3200 | case NodeTypeCompilerFnExpr: | |
| 3201 | return &node->data.compiler_fn_expr.resolved_expr; | |
| 3202 | case NodeTypeCompilerFnType: | |
| 3203 | return &node->data.compiler_fn_type.resolved_expr; | |
| 3204 | case NodeTypeLabel: | |
| 3205 | return &node->data.label.resolved_expr; | |
| 3206 | case NodeTypeRoot: | |
| 3207 | case NodeTypeRootExportDecl: | |
| 3208 | case NodeTypeFnProto: | |
| 3209 | case NodeTypeFnDef: | |
| 3210 | case NodeTypeFnDecl: | |
| 3211 | case NodeTypeParamDecl: | |
| 3212 | case NodeTypeType: | |
| 3213 | case NodeTypeExternBlock: | |
| 3214 | case NodeTypeDirective: | |
| 3215 | case NodeTypeUse: | |
| 3216 | case NodeTypeStructDecl: | |
| 3217 | case NodeTypeStructField: | |
| 3218 | case NodeTypeStructValueField: | |
| 3219 | case NodeTypeEnumDecl: | |
| 3220 | case NodeTypeEnumField: | |
| 3221 | zig_unreachable(); | |
| 3222 | } | |
| 3223 | } | |
| 3224 | ||
| 3225 | NumLitCodeGen *get_resolved_num_lit(AstNode *node) { | |
| 3226 | switch (node->type) { | |
| 3227 | case NodeTypeNumberLiteral: | |
| 3228 | return &node->data.number_literal.codegen; | |
| 3229 | case NodeTypeCompilerFnType: | |
| 3230 | return &node->data.compiler_fn_type.resolved_num_lit; | |
| 3231 | case NodeTypeReturnExpr: | |
| 3232 | case NodeTypeBinOpExpr: | |
| 3233 | case NodeTypeCastExpr: | |
| 3234 | case NodeTypePrefixOpExpr: | |
| 3235 | case NodeTypeFnCallExpr: | |
| 3236 | case NodeTypeArrayAccessExpr: | |
| 3237 | case NodeTypeSliceExpr: | |
| 3238 | case NodeTypeFieldAccessExpr: | |
| 3239 | case NodeTypeIfBoolExpr: | |
| 3240 | case NodeTypeIfVarExpr: | |
| 3241 | case NodeTypeWhileExpr: | |
| 3242 | case NodeTypeAsmExpr: | |
| 3243 | case NodeTypeStructValueExpr: | |
| 3244 | case NodeTypeRoot: | |
| 3245 | case NodeTypeRootExportDecl: | |
| 3246 | case NodeTypeFnProto: | |
| 3247 | case NodeTypeFnDef: | |
| 3248 | case NodeTypeFnDecl: | |
| 3249 | case NodeTypeParamDecl: | |
| 3250 | case NodeTypeType: | |
| 3251 | case NodeTypeBlock: | |
| 3252 | case NodeTypeExternBlock: | |
| 3253 | case NodeTypeDirective: | |
| 3254 | case NodeTypeVariableDeclaration: | |
| 3255 | case NodeTypeStringLiteral: | |
| 3256 | case NodeTypeCharLiteral: | |
| 3257 | case NodeTypeUnreachable: | |
| 3258 | case NodeTypeSymbol: | |
| 3259 | case NodeTypeUse: | |
| 3260 | case NodeTypeVoid: | |
| 3261 | case NodeTypeBoolLiteral: | |
| 3262 | case NodeTypeNullLiteral: | |
| 3263 | case NodeTypeLabel: | |
| 3264 | case NodeTypeGoto: | |
| 3265 | case NodeTypeBreak: | |
| 3266 | case NodeTypeContinue: | |
| 3267 | case NodeTypeStructDecl: | |
| 3268 | case NodeTypeStructField: | |
| 3269 | case NodeTypeStructValueField: | |
| 3270 | case NodeTypeEnumDecl: | |
| 3271 | case NodeTypeEnumField: | |
| 3272 | case NodeTypeCompilerFnExpr: | |
| 3273 | zig_unreachable(); | |
| 3274 | } | |
| 3151 | 3275 | } |
| 3152 | 3276 | |
| 3277 | TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { | |
| 3278 | switch (node->type) { | |
| 3279 | case NodeTypeVariableDeclaration: | |
| 3280 | return &node->data.variable_declaration.top_level_decl; | |
| 3281 | case NodeTypeFnProto: | |
| 3282 | return &node->data.fn_proto.top_level_decl; | |
| 3283 | case NodeTypeStructDecl: | |
| 3284 | return &node->data.struct_decl.top_level_decl; | |
| 3285 | case NodeTypeNumberLiteral: | |
| 3286 | case NodeTypeReturnExpr: | |
| 3287 | case NodeTypeBinOpExpr: | |
| 3288 | case NodeTypeCastExpr: | |
| 3289 | case NodeTypePrefixOpExpr: | |
| 3290 | case NodeTypeFnCallExpr: | |
| 3291 | case NodeTypeArrayAccessExpr: | |
| 3292 | case NodeTypeSliceExpr: | |
| 3293 | case NodeTypeFieldAccessExpr: | |
| 3294 | case NodeTypeIfBoolExpr: | |
| 3295 | case NodeTypeIfVarExpr: | |
| 3296 | case NodeTypeWhileExpr: | |
| 3297 | case NodeTypeAsmExpr: | |
| 3298 | case NodeTypeStructValueExpr: | |
| 3299 | case NodeTypeRoot: | |
| 3300 | case NodeTypeRootExportDecl: | |
| 3301 | case NodeTypeFnDef: | |
| 3302 | case NodeTypeFnDecl: | |
| 3303 | case NodeTypeParamDecl: | |
| 3304 | case NodeTypeType: | |
| 3305 | case NodeTypeBlock: | |
| 3306 | case NodeTypeExternBlock: | |
| 3307 | case NodeTypeDirective: | |
| 3308 | case NodeTypeStringLiteral: | |
| 3309 | case NodeTypeCharLiteral: | |
| 3310 | case NodeTypeUnreachable: | |
| 3311 | case NodeTypeSymbol: | |
| 3312 | case NodeTypeUse: | |
| 3313 | case NodeTypeVoid: | |
| 3314 | case NodeTypeBoolLiteral: | |
| 3315 | case NodeTypeNullLiteral: | |
| 3316 | case NodeTypeLabel: | |
| 3317 | case NodeTypeGoto: | |
| 3318 | case NodeTypeBreak: | |
| 3319 | case NodeTypeContinue: | |
| 3320 | case NodeTypeStructField: | |
| 3321 | case NodeTypeStructValueField: | |
| 3322 | case NodeTypeEnumDecl: | |
| 3323 | case NodeTypeEnumField: | |
| 3324 | case NodeTypeCompilerFnExpr: | |
| 3325 | case NodeTypeCompilerFnType: | |
| 3326 | zig_unreachable(); | |
| 3327 | } | |
| 3328 | } |
src/analyze.hpp+4-402| ... | ... | @@ -8,414 +8,16 @@ |
| 8 | 8 | #ifndef ZIG_ANALYZE_HPP |
| 9 | 9 | #define ZIG_ANALYZE_HPP |
| 10 | 10 | |
| 11 | #include "codegen.hpp" | |
| 12 | #include "hash_map.hpp" | |
| 13 | #include "zig_llvm.hpp" | |
| 14 | #include "errmsg.hpp" | |
| 15 | ||
| 16 | struct FnTableEntry; | |
| 17 | struct BlockContext; | |
| 18 | struct TypeTableEntry; | |
| 19 | struct VariableTableEntry; | |
| 20 | struct CastNode; | |
| 21 | struct StructValExprNode; | |
| 22 | ||
| 23 | struct TypeTableEntryPointer { | |
| 24 | TypeTableEntry *child_type; | |
| 25 | bool is_const; | |
| 26 | bool is_noalias; | |
| 27 | }; | |
| 28 | ||
| 29 | struct TypeTableEntryInt { | |
| 30 | bool is_signed; | |
| 31 | }; | |
| 32 | ||
| 33 | struct TypeTableEntryArray { | |
| 34 | TypeTableEntry *child_type; | |
| 35 | uint64_t len; | |
| 36 | }; | |
| 37 | ||
| 38 | struct TypeStructField { | |
| 39 | Buf *name; | |
| 40 | TypeTableEntry *type_entry; | |
| 41 | }; | |
| 42 | ||
| 43 | struct TypeTableEntryStruct { | |
| 44 | AstNode *decl_node; | |
| 45 | bool is_packed; | |
| 46 | int field_count; | |
| 47 | TypeStructField *fields; | |
| 48 | uint64_t size_bytes; | |
| 49 | bool is_invalid; // true if any fields are invalid | |
| 50 | bool is_unknown_size_array; | |
| 51 | // reminder: hash tables must be initialized before use | |
| 52 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | |
| 53 | ||
| 54 | // set this flag temporarily to detect infinite loops | |
| 55 | bool embedded_in_current; | |
| 56 | bool reported_infinite_err; | |
| 57 | }; | |
| 58 | ||
| 59 | struct TypeTableEntryNumLit { | |
| 60 | NumLit kind; | |
| 61 | }; | |
| 62 | ||
| 63 | struct TypeTableEntryMaybe { | |
| 64 | TypeTableEntry *child_type; | |
| 65 | }; | |
| 66 | ||
| 67 | enum TypeTableEntryId { | |
| 68 | TypeTableEntryIdInvalid, | |
| 69 | TypeTableEntryIdVoid, | |
| 70 | TypeTableEntryIdBool, | |
| 71 | TypeTableEntryIdUnreachable, | |
| 72 | TypeTableEntryIdInt, | |
| 73 | TypeTableEntryIdFloat, | |
| 74 | TypeTableEntryIdPointer, | |
| 75 | TypeTableEntryIdArray, | |
| 76 | TypeTableEntryIdStruct, | |
| 77 | TypeTableEntryIdNumberLiteral, | |
| 78 | TypeTableEntryIdMaybe, | |
| 79 | }; | |
| 80 | ||
| 81 | struct TypeTableEntry { | |
| 82 | TypeTableEntryId id; | |
| 83 | ||
| 84 | LLVMTypeRef type_ref; | |
| 85 | LLVMZigDIType *di_type; | |
| 86 | uint64_t size_in_bits; | |
| 87 | uint64_t align_in_bits; | |
| 88 | ||
| 89 | Buf name; | |
| 90 | ||
| 91 | union { | |
| 92 | TypeTableEntryPointer pointer; | |
| 93 | TypeTableEntryInt integral; | |
| 94 | TypeTableEntryArray array; | |
| 95 | TypeTableEntryStruct structure; | |
| 96 | TypeTableEntryNumLit num_lit; | |
| 97 | TypeTableEntryMaybe maybe; | |
| 98 | } data; | |
| 99 | ||
| 100 | // use these fields to make sure we don't duplicate type table entries for the same type | |
| 101 | TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias | |
| 102 | TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias | |
| 103 | HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size; | |
| 104 | TypeTableEntry *maybe_parent; | |
| 105 | ||
| 106 | }; | |
| 107 | ||
| 108 | struct ImporterInfo { | |
| 109 | ImportTableEntry *import; | |
| 110 | AstNode *source_node; | |
| 111 | }; | |
| 112 | ||
| 113 | struct ImportTableEntry { | |
| 114 | AstNode *root; | |
| 115 | Buf *path; // relative to root_source_dir | |
| 116 | LLVMZigDIFile *di_file; | |
| 117 | Buf *source_code; | |
| 118 | ZigList<int> *line_offsets; | |
| 119 | BlockContext *block_context; | |
| 120 | ZigList<ImporterInfo> importers; | |
| 121 | ||
| 122 | // reminder: hash tables must be initialized before use | |
| 123 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | |
| 124 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; | |
| 125 | }; | |
| 126 | ||
| 127 | struct LabelTableEntry { | |
| 128 | AstNode *label_node; | |
| 129 | LLVMBasicBlockRef basic_block; | |
| 130 | bool used; | |
| 131 | bool entered_from_fallthrough; | |
| 132 | }; | |
| 133 | ||
| 134 | enum FnAttrId { | |
| 135 | FnAttrIdNaked, | |
| 136 | FnAttrIdAlwaysInline, | |
| 137 | }; | |
| 138 | ||
| 139 | struct FnTableEntry { | |
| 140 | LLVMValueRef fn_value; | |
| 141 | AstNode *proto_node; | |
| 142 | AstNode *fn_def_node; | |
| 143 | bool is_extern; | |
| 144 | bool internal_linkage; | |
| 145 | unsigned calling_convention; | |
| 146 | ImportTableEntry *import_entry; | |
| 147 | ZigList<FnAttrId> fn_attr_list; | |
| 148 | // Required to be a pre-order traversal of the AST. (parents must come before children) | |
| 149 | ZigList<BlockContext *> all_block_contexts; | |
| 150 | TypeTableEntry *member_of_struct; | |
| 151 | Buf symbol_name; | |
| 152 | ||
| 153 | // reminder: hash tables must be initialized before use | |
| 154 | HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; | |
| 155 | }; | |
| 156 | ||
| 157 | enum BuiltinFnId { | |
| 158 | BuiltinFnIdInvalid, | |
| 159 | BuiltinFnIdArithmeticWithOverflow, | |
| 160 | BuiltinFnIdMemcpy, | |
| 161 | BuiltinFnIdMemset, | |
| 162 | }; | |
| 163 | ||
| 164 | struct BuiltinFnEntry { | |
| 165 | BuiltinFnId id; | |
| 166 | Buf name; | |
| 167 | int param_count; | |
| 168 | TypeTableEntry *return_type; | |
| 169 | TypeTableEntry **param_types; | |
| 170 | LLVMValueRef fn_val; | |
| 171 | }; | |
| 172 | ||
| 173 | struct CodeGen { | |
| 174 | LLVMModuleRef module; | |
| 175 | ZigList<ErrorMsg*> errors; | |
| 176 | LLVMBuilderRef builder; | |
| 177 | LLVMZigDIBuilder *dbuilder; | |
| 178 | LLVMZigDICompileUnit *compile_unit; | |
| 179 | ||
| 180 | ZigList<Buf *> lib_search_paths; | |
| 181 | ||
| 182 | // reminder: hash tables must be initialized before use | |
| 183 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; | |
| 184 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; | |
| 185 | HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; | |
| 186 | HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table; | |
| 187 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table; | |
| 188 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls; | |
| 189 | ||
| 190 | uint32_t next_unresolved_index; | |
| 191 | ||
| 192 | struct { | |
| 193 | TypeTableEntry *entry_bool; | |
| 194 | TypeTableEntry *entry_u8; | |
| 195 | TypeTableEntry *entry_u16; | |
| 196 | TypeTableEntry *entry_u32; | |
| 197 | TypeTableEntry *entry_u64; | |
| 198 | TypeTableEntry *entry_i8; | |
| 199 | TypeTableEntry *entry_i16; | |
| 200 | TypeTableEntry *entry_i32; | |
| 201 | TypeTableEntry *entry_i64; | |
| 202 | TypeTableEntry *entry_isize; | |
| 203 | TypeTableEntry *entry_usize; | |
| 204 | TypeTableEntry *entry_f32; | |
| 205 | TypeTableEntry *entry_f64; | |
| 206 | TypeTableEntry *entry_c_string_literal; | |
| 207 | TypeTableEntry *entry_void; | |
| 208 | TypeTableEntry *entry_unreachable; | |
| 209 | TypeTableEntry *entry_invalid; | |
| 210 | } builtin_types; | |
| 211 | ||
| 212 | TypeTableEntry *num_lit_types[NumLitCount]; | |
| 213 | ||
| 214 | LLVMTargetDataRef target_data_ref; | |
| 215 | unsigned pointer_size_bytes; | |
| 216 | bool is_static; | |
| 217 | bool strip_debug_symbols; | |
| 218 | bool have_exported_main; | |
| 219 | bool link_libc; | |
| 220 | Buf *libc_path; | |
| 221 | CodeGenBuildType build_type; | |
| 222 | LLVMTargetMachineRef target_machine; | |
| 223 | LLVMZigDIFile *dummy_di_file; | |
| 224 | bool is_native_target; | |
| 225 | Buf *root_source_dir; | |
| 226 | Buf *root_out_name; | |
| 227 | ||
| 228 | // The function definitions this module includes. There must be a corresponding | |
| 229 | // fn_protos entry. | |
| 230 | ZigList<FnTableEntry *> fn_defs; | |
| 231 | // The function prototypes this module includes. In the case of external declarations, | |
| 232 | // there will not be a corresponding fn_defs entry. | |
| 233 | ZigList<FnTableEntry *> fn_protos; | |
| 234 | ZigList<VariableTableEntry *> global_vars; | |
| 235 | ||
| 236 | OutType out_type; | |
| 237 | FnTableEntry *cur_fn; | |
| 238 | BlockContext *cur_block_context; | |
| 239 | ZigList<LLVMBasicBlockRef> break_block_stack; | |
| 240 | ZigList<LLVMBasicBlockRef> continue_block_stack; | |
| 241 | bool c_stdint_used; | |
| 242 | AstNode *root_export_decl; | |
| 243 | int version_major; | |
| 244 | int version_minor; | |
| 245 | int version_patch; | |
| 246 | bool verbose; | |
| 247 | ErrColor err_color; | |
| 248 | ImportTableEntry *root_import; | |
| 249 | ImportTableEntry *bootstrap_import; | |
| 250 | LLVMValueRef memcpy_fn_val; | |
| 251 | bool error_during_imports; | |
| 252 | }; | |
| 253 | ||
| 254 | struct VariableTableEntry { | |
| 255 | Buf name; | |
| 256 | TypeTableEntry *type; | |
| 257 | LLVMValueRef value_ref; | |
| 258 | bool is_const; | |
| 259 | bool is_ptr; // if true, value_ref is a pointer | |
| 260 | AstNode *decl_node; | |
| 261 | LLVMZigDILocalVariable *di_loc_var; | |
| 262 | int arg_index; | |
| 263 | }; | |
| 264 | ||
| 265 | struct BlockContext { | |
| 266 | AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot | |
| 267 | FnTableEntry *fn_entry; // null at the module scope | |
| 268 | BlockContext *parent; // null when this is the root | |
| 269 | HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table; | |
| 270 | ZigList<CastNode *> cast_expr_alloca_list; | |
| 271 | ZigList<StructValExprNode *> struct_val_expr_alloca_list; | |
| 272 | AstNode *parent_loop_node; | |
| 273 | AstNode *next_child_parent_loop_node; | |
| 274 | LLVMZigDIScope *di_scope; | |
| 275 | }; | |
| 276 | ||
| 277 | struct TypeNode { | |
| 278 | TypeTableEntry *entry; | |
| 279 | }; | |
| 280 | ||
| 281 | struct FnProtoNode { | |
| 282 | FnTableEntry *fn_table_entry; | |
| 283 | bool skip; | |
| 284 | }; | |
| 285 | ||
| 286 | struct FnDefNode { | |
| 287 | TypeTableEntry *implicit_return_type; | |
| 288 | BlockContext *block_context; | |
| 289 | }; | |
| 290 | ||
| 291 | ||
| 292 | struct AssignNode { | |
| 293 | VariableTableEntry *var_entry; | |
| 294 | }; | |
| 295 | ||
| 296 | struct BlockNode { | |
| 297 | BlockContext *block_context; | |
| 298 | }; | |
| 299 | ||
| 300 | struct StructDeclNode { | |
| 301 | TypeTableEntry *type_entry; | |
| 302 | }; | |
| 303 | ||
| 304 | struct FieldAccessNode { | |
| 305 | int field_index; | |
| 306 | TypeStructField *type_struct_field; | |
| 307 | }; | |
| 308 | ||
| 309 | enum CastOp { | |
| 310 | CastOpNothing, | |
| 311 | CastOpPtrToInt, | |
| 312 | CastOpIntWidenOrShorten, | |
| 313 | CastOpToUnknownSizeArray, | |
| 314 | CastOpMaybeWrap, | |
| 315 | CastOpPointerReinterpret, | |
| 316 | }; | |
| 317 | ||
| 318 | struct CastNode { | |
| 319 | CastOp op; | |
| 320 | // if op is CastOpArrayToString, this will be a pointer to | |
| 321 | // the string struct on the stack | |
| 322 | LLVMValueRef ptr; | |
| 323 | TypeTableEntry *after_type; | |
| 324 | AstNode *source_node; | |
| 325 | }; | |
| 326 | ||
| 327 | struct ExprNode { | |
| 328 | TypeTableEntry *type_entry; | |
| 329 | // the context in which this expression is evaluated. | |
| 330 | // for blocks, this points to the containing scope, not the block's own scope for its children. | |
| 331 | BlockContext *block_context; | |
| 332 | ||
| 333 | // may be null for no cast | |
| 334 | CastNode implicit_cast; // happens first | |
| 335 | CastNode implicit_maybe_cast; // happens second | |
| 336 | }; | |
| 337 | ||
| 338 | struct NumberLiteralNode { | |
| 339 | TypeTableEntry *resolved_type; | |
| 340 | }; | |
| 341 | ||
| 342 | struct VarDeclNode { | |
| 343 | TypeTableEntry *type; | |
| 344 | }; | |
| 345 | ||
| 346 | struct StructValFieldNode { | |
| 347 | int index; | |
| 348 | }; | |
| 349 | ||
| 350 | struct StructValExprNode { | |
| 351 | TypeTableEntry *type_entry; | |
| 352 | LLVMValueRef ptr; | |
| 353 | AstNode *source_node; | |
| 354 | }; | |
| 355 | ||
| 356 | struct IfVarNode { | |
| 357 | BlockContext *block_context; | |
| 358 | }; | |
| 359 | ||
| 360 | struct ParamDeclNode { | |
| 361 | VariableTableEntry *variable; | |
| 362 | }; | |
| 363 | ||
| 364 | struct ImportNode { | |
| 365 | ImportTableEntry *import; | |
| 366 | }; | |
| 367 | ||
| 368 | struct WhileNode { | |
| 369 | bool condition_always_true; | |
| 370 | bool contains_break; | |
| 371 | }; | |
| 372 | ||
| 373 | struct FnCallNode { | |
| 374 | BuiltinFnEntry *builtin_fn; | |
| 375 | }; | |
| 376 | ||
| 377 | struct DeclNode { | |
| 378 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> deps; | |
| 379 | Buf *name; | |
| 380 | ImportTableEntry *import; | |
| 381 | // set this flag temporarily to detect infinite loops | |
| 382 | bool in_current_deps; | |
| 383 | }; | |
| 384 | ||
| 385 | // TODO get rid of this structure and put the data directly in the appropriate AST node | |
| 386 | struct CodeGenNode { | |
| 387 | union { | |
| 388 | TypeNode type_node; // for NodeTypeType | |
| 389 | FnDefNode fn_def_node; // for NodeTypeFnDef | |
| 390 | FnProtoNode fn_proto_node; // for NodeTypeFnProto | |
| 391 | LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel | |
| 392 | AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign | |
| 393 | BlockNode block_node; // for NodeTypeBlock | |
| 394 | StructDeclNode struct_decl_node; // for NodeTypeStructDecl | |
| 395 | FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr | |
| 396 | CastNode cast_node; // for NodeTypeCastExpr | |
| 397 | // note: I've been using this field on some non-number literal nodes too. | |
| 398 | NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral | |
| 399 | VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration | |
| 400 | StructValFieldNode struct_val_field_node; // for NodeTypeStructValueField | |
| 401 | // note: I've been using this field on some non-struct val expressions too. | |
| 402 | StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr | |
| 403 | IfVarNode if_var_node; // for NodeTypeStructValueExpr | |
| 404 | ParamDeclNode param_decl_node; // for NodeTypeParamDecl | |
| 405 | ImportNode import_node; // for NodeTypeUse | |
| 406 | WhileNode while_node; // for NodeTypeWhileExpr | |
| 407 | FnCallNode fn_call_node; // for NodeTypeFnCallExpr | |
| 408 | } data; | |
| 409 | ExprNode expr_node; // for all the expression nodes | |
| 410 | DeclNode decl_node; // for all top level decls | |
| 411 | }; | |
| 11 | #include "all_types.hpp" | |
| 412 | 12 | |
| 413 | 13 | void semantic_analyze(CodeGen *g); |
| 414 | 14 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); |
| 415 | void alloc_codegen_node(AstNode *node); | |
| 416 | 15 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); |
| 417 | 16 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_noalias); |
| 418 | 17 | VariableTableEntry *find_variable(BlockContext *context, Buf *name); |
| 419 | 18 | BlockContext *new_block_context(AstNode *node, BlockContext *parent); |
| 19 | Expr *get_resolved_expr(AstNode *node); | |
| 20 | NumLitCodeGen *get_resolved_num_lit(AstNode *node); | |
| 21 | TopLevelDecl *get_resolved_top_level_decl(AstNode *node); | |
| 420 | 22 | |
| 421 | 23 | #endif |
src/codegen.cpp+50-61| ... | ... | @@ -75,9 +75,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b |
| 75 | 75 | |
| 76 | 76 | static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) { |
| 77 | 77 | assert(type_node->type == NodeTypeType); |
| 78 | assert(type_node->codegen_node); | |
| 79 | assert(type_node->codegen_node->data.type_node.entry); | |
| 80 | return type_node->codegen_node->data.type_node.entry; | |
| 78 | return type_node->data.type.entry; | |
| 81 | 79 | } |
| 82 | 80 | |
| 83 | 81 | static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { |
| ... | ... | @@ -138,15 +136,16 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) { |
| 138 | 136 | } |
| 139 | 137 | |
| 140 | 138 | static TypeTableEntry *get_expr_type(AstNode *node) { |
| 141 | TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.after_type; | |
| 142 | return cast_type ? cast_type : node->codegen_node->expr_node.type_entry; | |
| 139 | Expr *expr = get_resolved_expr(node); | |
| 140 | TypeTableEntry *cast_type = expr->implicit_cast.after_type; | |
| 141 | return cast_type ? cast_type : expr->type_entry; | |
| 143 | 142 | } |
| 144 | 143 | |
| 145 | 144 | static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 146 | 145 | assert(node->type == NodeTypeFnCallExpr); |
| 147 | 146 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; |
| 148 | 147 | assert(fn_ref_expr->type == NodeTypeSymbol); |
| 149 | BuiltinFnEntry *builtin_fn = node->codegen_node->data.fn_call_node.builtin_fn; | |
| 148 | BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn; | |
| 150 | 149 | |
| 151 | 150 | switch (builtin_fn->id) { |
| 152 | 151 | case BuiltinFnIdInvalid: |
| ... | ... | @@ -265,7 +264,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 265 | 264 | // Assume that the expression evaluates to a simple name and return the buf |
| 266 | 265 | // TODO after we support function pointers we can make this generic |
| 267 | 266 | assert(fn_ref_expr->type == NodeTypeSymbol); |
| 268 | Buf *name = &fn_ref_expr->data.symbol; | |
| 267 | Buf *name = &fn_ref_expr->data.symbol_expr.symbol; | |
| 269 | 268 | |
| 270 | 269 | struct_type = nullptr; |
| 271 | 270 | first_param_expr = nullptr; |
| ... | ... | @@ -388,8 +387,8 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou |
| 388 | 387 | |
| 389 | 388 | LLVMValueRef struct_ptr; |
| 390 | 389 | if (struct_expr_node->type == NodeTypeSymbol) { |
| 391 | VariableTableEntry *var = find_variable(struct_expr_node->codegen_node->expr_node.block_context, | |
| 392 | &struct_expr_node->data.symbol); | |
| 390 | VariableTableEntry *var = find_variable(get_resolved_expr(struct_expr_node)->block_context, | |
| 391 | &struct_expr_node->data.symbol_expr.symbol); | |
| 393 | 392 | assert(var); |
| 394 | 393 | |
| 395 | 394 | if (var->is_ptr && var->type->id == TypeTableEntryIdPointer) { |
| ... | ... | @@ -413,14 +412,12 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou |
| 413 | 412 | assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind); |
| 414 | 413 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind); |
| 415 | 414 | |
| 416 | FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node; | |
| 415 | assert(node->data.field_access_expr.field_index >= 0); | |
| 417 | 416 | |
| 418 | assert(codegen_field_access->field_index >= 0); | |
| 419 | ||
| 420 | *out_type_entry = codegen_field_access->type_struct_field->type_entry; | |
| 417 | *out_type_entry = node->data.field_access_expr.type_struct_field->type_entry; | |
| 421 | 418 | |
| 422 | 419 | add_debug_source_node(g, node); |
| 423 | return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, ""); | |
| 420 | return LLVMBuildStructGEP(g->builder, struct_ptr, node->data.field_access_expr.field_index, ""); | |
| 424 | 421 | } |
| 425 | 422 | |
| 426 | 423 | static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { |
| ... | ... | @@ -429,7 +426,7 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { |
| 429 | 426 | AstNode *array_ref_node = node->data.slice_expr.array_ref_expr; |
| 430 | 427 | TypeTableEntry *array_type = get_expr_type(array_ref_node); |
| 431 | 428 | |
| 432 | LLVMValueRef tmp_struct_ptr = node->codegen_node->data.struct_val_expr_node.ptr; | |
| 429 | LLVMValueRef tmp_struct_ptr = node->data.slice_expr.resolved_struct_val_expr.ptr; | |
| 433 | 430 | LLVMValueRef array_ptr = gen_array_base_ptr(g, array_ref_node); |
| 434 | 431 | |
| 435 | 432 | if (array_type->id == TypeTableEntryIdArray) { |
| ... | ... | @@ -545,8 +542,8 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, |
| 545 | 542 | LLVMValueRef target_ref; |
| 546 | 543 | |
| 547 | 544 | if (node->type == NodeTypeSymbol) { |
| 548 | VariableTableEntry *var = find_variable(expr_node->codegen_node->expr_node.block_context, | |
| 549 | &node->data.symbol); | |
| 545 | VariableTableEntry *var = find_variable(get_resolved_expr(expr_node)->block_context, | |
| 546 | &node->data.symbol_expr.symbol); | |
| 550 | 547 | assert(var); |
| 551 | 548 | // semantic checking ensures no variables are constant |
| 552 | 549 | assert(!var->is_const); |
| ... | ... | @@ -630,7 +627,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 630 | 627 | } |
| 631 | 628 | |
| 632 | 629 | static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_val, |
| 633 | TypeTableEntry *actual_type, TypeTableEntry *wanted_type, CastNode *cast_node) | |
| 630 | TypeTableEntry *actual_type, TypeTableEntry *wanted_type, Cast *cast_node) | |
| 634 | 631 | { |
| 635 | 632 | switch (cast_node->op) { |
| 636 | 633 | case CastOpNothing: |
| ... | ... | @@ -705,7 +702,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 705 | 702 | TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr); |
| 706 | 703 | TypeTableEntry *wanted_type = get_expr_type(node); |
| 707 | 704 | |
| 708 | CastNode *cast_node = &node->codegen_node->data.cast_node; | |
| 705 | Cast *cast_node = &node->data.cast_expr.cast; | |
| 709 | 706 | |
| 710 | 707 | return gen_bare_cast(g, node, expr_val, actual_type, wanted_type, cast_node); |
| 711 | 708 | |
| ... | ... | @@ -1218,7 +1215,7 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { |
| 1218 | 1215 | assert(node->data.if_var_expr.var_decl.expr); |
| 1219 | 1216 | |
| 1220 | 1217 | BlockContext *old_block_context = g->cur_block_context; |
| 1221 | BlockContext *new_block_context = node->codegen_node->data.if_var_node.block_context; | |
| 1218 | BlockContext *new_block_context = node->data.if_var_expr.block_context; | |
| 1222 | 1219 | |
| 1223 | 1220 | LLVMValueRef init_val; |
| 1224 | 1221 | gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, new_block_context, true, &init_val); |
| ... | ... | @@ -1242,7 +1239,7 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i |
| 1242 | 1239 | assert(block_node->type == NodeTypeBlock); |
| 1243 | 1240 | |
| 1244 | 1241 | BlockContext *old_block_context = g->cur_block_context; |
| 1245 | g->cur_block_context = block_node->codegen_node->data.block_node.block_context; | |
| 1242 | g->cur_block_context = block_node->data.block.block_context; | |
| 1246 | 1243 | |
| 1247 | 1244 | LLVMValueRef return_value; |
| 1248 | 1245 | for (int i = 0; i < block_node->data.block.statements.length; i += 1) { |
| ... | ... | @@ -1347,7 +1344,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { |
| 1347 | 1344 | |
| 1348 | 1345 | if (!is_return) { |
| 1349 | 1346 | VariableTableEntry *variable = find_variable( |
| 1350 | node->codegen_node->expr_node.block_context, | |
| 1347 | get_resolved_expr(node)->block_context, | |
| 1351 | 1348 | &asm_output->variable_name); |
| 1352 | 1349 | assert(variable); |
| 1353 | 1350 | param_types[param_index] = LLVMTypeOf(variable->value_ref); |
| ... | ... | @@ -1396,7 +1393,7 @@ static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) { |
| 1396 | 1393 | TypeTableEntry *type_entry = get_expr_type(node); |
| 1397 | 1394 | assert(type_entry->id == TypeTableEntryIdMaybe); |
| 1398 | 1395 | |
| 1399 | LLVMValueRef tmp_struct_ptr = node->codegen_node->data.struct_val_expr_node.ptr; | |
| 1396 | LLVMValueRef tmp_struct_ptr = node->data.null_literal.resolved_struct_val_expr.ptr; | |
| 1400 | 1397 | |
| 1401 | 1398 | add_debug_source_node(g, node); |
| 1402 | 1399 | LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); |
| ... | ... | @@ -1416,12 +1413,13 @@ static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) { |
| 1416 | 1413 | int field_count = type_entry->data.structure.field_count; |
| 1417 | 1414 | assert(field_count == node->data.struct_val_expr.fields.length); |
| 1418 | 1415 | |
| 1419 | StructValExprNode *struct_val_expr_node = &node->codegen_node->data.struct_val_expr_node; | |
| 1416 | StructValExprCodeGen *struct_val_expr_node = &node->data.struct_val_expr.codegen; | |
| 1420 | 1417 | LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr; |
| 1421 | 1418 | |
| 1422 | 1419 | for (int i = 0; i < field_count; i += 1) { |
| 1423 | 1420 | AstNode *field_node = node->data.struct_val_expr.fields.at(i); |
| 1424 | int index = field_node->codegen_node->data.struct_val_field_node.index; | |
| 1421 | assert(field_node->type == NodeTypeStructValueField); | |
| 1422 | int index = field_node->data.struct_val_field.index; | |
| 1425 | 1423 | TypeStructField *type_struct_field = &type_entry->data.structure.fields[index]; |
| 1426 | 1424 | assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name)); |
| 1427 | 1425 | |
| ... | ... | @@ -1439,8 +1437,8 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { |
| 1439 | 1437 | assert(node->data.while_expr.condition); |
| 1440 | 1438 | assert(node->data.while_expr.body); |
| 1441 | 1439 | |
| 1442 | bool condition_always_true = node->codegen_node->data.while_node.condition_always_true; | |
| 1443 | bool contains_break = node->codegen_node->data.while_node.contains_break; | |
| 1440 | bool condition_always_true = node->data.while_expr.condition_always_true; | |
| 1441 | bool contains_break = node->data.while_expr.contains_break; | |
| 1444 | 1442 | if (condition_always_true) { |
| 1445 | 1443 | // generate a forever loop |
| 1446 | 1444 | |
| ... | ... | @@ -1559,17 +1557,17 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa |
| 1559 | 1557 | static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { |
| 1560 | 1558 | LLVMValueRef init_val; |
| 1561 | 1559 | return gen_var_decl_raw(g, node, &node->data.variable_declaration, |
| 1562 | node->codegen_node->expr_node.block_context, false, &init_val); | |
| 1560 | get_resolved_expr(node)->block_context, false, &init_val); | |
| 1563 | 1561 | } |
| 1564 | 1562 | |
| 1565 | 1563 | static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node, |
| 1566 | NumberLiteralNode *codegen_num_lit, AstNodeNumberLiteral *num_lit_node) | |
| 1564 | NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node) | |
| 1567 | 1565 | { |
| 1568 | 1566 | TypeTableEntry *type_entry = codegen_num_lit->resolved_type; |
| 1569 | 1567 | assert(type_entry); |
| 1570 | 1568 | |
| 1571 | 1569 | // override the expression type for number literals |
| 1572 | source_node->codegen_node->expr_node.type_entry = type_entry; | |
| 1570 | get_resolved_expr(source_node)->type_entry = type_entry; | |
| 1573 | 1571 | |
| 1574 | 1572 | if (type_entry->id == TypeTableEntryIdInt) { |
| 1575 | 1573 | // here the union has int64_t and uint64_t and we purposefully read |
| ... | ... | @@ -1594,7 +1592,7 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) { |
| 1594 | 1592 | Buf *name = &node->data.compiler_fn_type.name; |
| 1595 | 1593 | TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type); |
| 1596 | 1594 | if (buf_eql_str(name, "sizeof")) { |
| 1597 | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; | |
| 1595 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); | |
| 1598 | 1596 | AstNodeNumberLiteral num_lit_node; |
| 1599 | 1597 | num_lit_node.kind = type_entry->data.num_lit.kind; |
| 1600 | 1598 | num_lit_node.overflow = false; |
| ... | ... | @@ -1632,7 +1630,7 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) { |
| 1632 | 1630 | static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) { |
| 1633 | 1631 | assert(node->type == NodeTypeNumberLiteral); |
| 1634 | 1632 | |
| 1635 | NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node; | |
| 1633 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); | |
| 1636 | 1634 | assert(codegen_num_lit); |
| 1637 | 1635 | |
| 1638 | 1636 | return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal); |
| ... | ... | @@ -1664,7 +1662,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1664 | 1662 | case NodeTypeVoid: |
| 1665 | 1663 | return nullptr; |
| 1666 | 1664 | case NodeTypeBoolLiteral: |
| 1667 | if (node->data.bool_literal) | |
| 1665 | if (node->data.bool_literal.value) | |
| 1668 | 1666 | return LLVMConstAllOnes(LLVMInt1Type()); |
| 1669 | 1667 | else |
| 1670 | 1668 | return LLVMConstNull(LLVMInt1Type()); |
| ... | ... | @@ -1696,8 +1694,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1696 | 1694 | case NodeTypeSymbol: |
| 1697 | 1695 | { |
| 1698 | 1696 | VariableTableEntry *variable = find_variable( |
| 1699 | node->codegen_node->expr_node.block_context, | |
| 1700 | &node->data.symbol); | |
| 1697 | get_resolved_expr(node)->block_context, | |
| 1698 | &node->data.symbol_expr.symbol); | |
| 1701 | 1699 | assert(variable); |
| 1702 | 1700 | if (variable->type->id == TypeTableEntryIdVoid) { |
| 1703 | 1701 | return nullptr; |
| ... | ... | @@ -1721,14 +1719,14 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1721 | 1719 | return gen_block(g, node, nullptr); |
| 1722 | 1720 | case NodeTypeGoto: |
| 1723 | 1721 | add_debug_source_node(g, node); |
| 1724 | return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block); | |
| 1722 | return LLVMBuildBr(g->builder, node->data.goto_expr.label_entry->basic_block); | |
| 1725 | 1723 | case NodeTypeBreak: |
| 1726 | 1724 | return gen_break(g, node); |
| 1727 | 1725 | case NodeTypeContinue: |
| 1728 | 1726 | return gen_continue(g, node); |
| 1729 | 1727 | case NodeTypeLabel: |
| 1730 | 1728 | { |
| 1731 | LabelTableEntry *label_entry = node->codegen_node->data.label_entry; | |
| 1729 | LabelTableEntry *label_entry = node->data.label.label_entry; | |
| 1732 | 1730 | assert(label_entry); |
| 1733 | 1731 | LLVMBasicBlockRef basic_block = label_entry->basic_block; |
| 1734 | 1732 | if (label_entry->entered_from_fallthrough) { |
| ... | ... | @@ -1770,19 +1768,19 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 1770 | 1768 | return val; |
| 1771 | 1769 | } |
| 1772 | 1770 | |
| 1773 | assert(node->codegen_node); | |
| 1771 | Expr *expr = get_resolved_expr(node); | |
| 1774 | 1772 | |
| 1775 | TypeTableEntry *before_type = node->codegen_node->expr_node.type_entry; | |
| 1773 | TypeTableEntry *before_type = expr->type_entry; | |
| 1776 | 1774 | if (before_type && before_type->id == TypeTableEntryIdUnreachable) { |
| 1777 | 1775 | return val; |
| 1778 | 1776 | } |
| 1779 | CastNode *cast_node = &node->codegen_node->expr_node.implicit_cast; | |
| 1777 | Cast *cast_node = &expr->implicit_cast; | |
| 1780 | 1778 | if (cast_node->after_type) { |
| 1781 | 1779 | val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node); |
| 1782 | 1780 | before_type = cast_node->after_type; |
| 1783 | 1781 | } |
| 1784 | 1782 | |
| 1785 | cast_node = &node->codegen_node->expr_node.implicit_maybe_cast; | |
| 1783 | cast_node = &expr->implicit_maybe_cast; | |
| 1786 | 1784 | if (cast_node->after_type) { |
| 1787 | 1785 | val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node); |
| 1788 | 1786 | } |
| ... | ... | @@ -1798,7 +1796,7 @@ static void build_label_blocks(CodeGen *g, AstNode *block_node) { |
| 1798 | 1796 | continue; |
| 1799 | 1797 | |
| 1800 | 1798 | Buf *name = &label_node->data.label.name; |
| 1801 | label_node->codegen_node->data.label_entry->basic_block = LLVMAppendBasicBlock( | |
| 1799 | label_node->data.label.label_entry->basic_block = LLVMAppendBasicBlock( | |
| 1802 | 1800 | g->cur_fn->fn_value, buf_ptr(name)); |
| 1803 | 1801 | } |
| 1804 | 1802 | |
| ... | ... | @@ -1944,13 +1942,7 @@ static void do_code_gen(CodeGen *g) { |
| 1944 | 1942 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn, "entry"); |
| 1945 | 1943 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 1946 | 1944 | |
| 1947 | CodeGenNode *codegen_node = fn_def_node->codegen_node; | |
| 1948 | assert(codegen_node); | |
| 1949 | ||
| 1950 | FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node; | |
| 1951 | assert(codegen_fn_def); | |
| 1952 | ||
| 1953 | codegen_fn_def->block_context->di_scope = LLVMZigSubprogramToScope(subprogram); | |
| 1945 | fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram); | |
| 1954 | 1946 | |
| 1955 | 1947 | int non_void_param_count = count_non_void_params(g, &fn_proto->params); |
| 1956 | 1948 | assert(non_void_param_count == (int)LLVMCountParams(fn)); |
| ... | ... | @@ -1963,7 +1955,7 @@ static void do_code_gen(CodeGen *g) { |
| 1963 | 1955 | assert(param_decl->type == NodeTypeParamDecl); |
| 1964 | 1956 | if (is_param_decl_type_void(g, param_decl)) |
| 1965 | 1957 | continue; |
| 1966 | VariableTableEntry *parameter_variable = fn_def_node->codegen_node->data.fn_def_node.block_context->variable_table.get(&param_decl->data.param_decl.name); | |
| 1958 | VariableTableEntry *parameter_variable = fn_def_node->data.fn_def.block_context->variable_table.get(&param_decl->data.param_decl.name); | |
| 1967 | 1959 | parameter_variable->value_ref = params[non_void_index]; |
| 1968 | 1960 | non_void_index += 1; |
| 1969 | 1961 | } |
| ... | ... | @@ -2019,14 +2011,14 @@ static void do_code_gen(CodeGen *g) { |
| 2019 | 2011 | |
| 2020 | 2012 | // allocate structs which are the result of casts |
| 2021 | 2013 | for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) { |
| 2022 | CastNode *cast_node = block_context->cast_expr_alloca_list.at(cea_i); | |
| 2014 | Cast *cast_node = block_context->cast_expr_alloca_list.at(cea_i); | |
| 2023 | 2015 | add_debug_source_node(g, cast_node->source_node); |
| 2024 | 2016 | cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->after_type->type_ref, ""); |
| 2025 | 2017 | } |
| 2026 | 2018 | |
| 2027 | 2019 | // allocate structs which are struct value expressions |
| 2028 | 2020 | for (int alloca_i = 0; alloca_i < block_context->struct_val_expr_alloca_list.length; alloca_i += 1) { |
| 2029 | StructValExprNode *struct_val_expr_node = block_context->struct_val_expr_alloca_list.at(alloca_i); | |
| 2021 | StructValExprCodeGen *struct_val_expr_node = block_context->struct_val_expr_alloca_list.at(alloca_i); | |
| 2030 | 2022 | add_debug_source_node(g, struct_val_expr_node->source_node); |
| 2031 | 2023 | struct_val_expr_node->ptr = LLVMBuildAlloca(g->builder, |
| 2032 | 2024 | struct_val_expr_node->type_entry->type_ref, ""); |
| ... | ... | @@ -2041,15 +2033,15 @@ static void do_code_gen(CodeGen *g) { |
| 2041 | 2033 | if (is_param_decl_type_void(g, param_decl)) |
| 2042 | 2034 | continue; |
| 2043 | 2035 | |
| 2044 | VariableTableEntry *variable = param_decl->codegen_node->data.param_decl_node.variable; | |
| 2036 | VariableTableEntry *variable = param_decl->data.param_decl.variable; | |
| 2045 | 2037 | |
| 2046 | 2038 | LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(param_decl->line + 1, param_decl->column + 1, |
| 2047 | codegen_fn_def->block_context->di_scope); | |
| 2039 | fn_def_node->data.fn_def.block_context->di_scope); | |
| 2048 | 2040 | LLVMZigInsertDeclareAtEnd(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc, |
| 2049 | 2041 | entry_block); |
| 2050 | 2042 | } |
| 2051 | 2043 | |
| 2052 | TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type; | |
| 2044 | TypeTableEntry *implicit_return_type = fn_def_node->data.fn_def.implicit_return_type; | |
| 2053 | 2045 | gen_block(g, fn_def_node->data.fn_def.body, implicit_return_type); |
| 2054 | 2046 | |
| 2055 | 2047 | } |
| ... | ... | @@ -2549,8 +2541,6 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, |
| 2549 | 2541 | Buf *import_code = buf_alloc(); |
| 2550 | 2542 | bool found_it = false; |
| 2551 | 2543 | |
| 2552 | alloc_codegen_node(top_level_decl); | |
| 2553 | ||
| 2554 | 2544 | for (int path_i = 0; path_i < g->lib_search_paths.length; path_i += 1) { |
| 2555 | 2545 | Buf *search_path = g->lib_search_paths.at(path_i); |
| 2556 | 2546 | os_path_join(search_path, import_target_path, &full_path); |
| ... | ... | @@ -2570,7 +2560,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, |
| 2570 | 2560 | auto entry = g->import_table.maybe_get(abs_full_path); |
| 2571 | 2561 | if (entry) { |
| 2572 | 2562 | found_it = true; |
| 2573 | top_level_decl->codegen_node->data.import_node.import = entry->value; | |
| 2563 | top_level_decl->data.use.import = entry->value; | |
| 2574 | 2564 | } else { |
| 2575 | 2565 | if ((err = os_fetch_file_path(abs_full_path, import_code))) { |
| 2576 | 2566 | if (err == ErrorFileNotFound) { |
| ... | ... | @@ -2582,7 +2572,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, |
| 2582 | 2572 | goto done_looking_at_imports; |
| 2583 | 2573 | } |
| 2584 | 2574 | } |
| 2585 | top_level_decl->codegen_node->data.import_node.import = codegen_add_code(g, | |
| 2575 | top_level_decl->data.use.import = codegen_add_code(g, | |
| 2586 | 2576 | abs_full_path, search_path, &top_level_decl->data.use.path, import_code); |
| 2587 | 2577 | found_it = true; |
| 2588 | 2578 | } |
| ... | ... | @@ -2682,9 +2672,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou |
| 2682 | 2672 | |
| 2683 | 2673 | static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) { |
| 2684 | 2674 | assert(type_node->type == NodeTypeType); |
| 2685 | assert(type_node->codegen_node); | |
| 2686 | 2675 | |
| 2687 | TypeTableEntry *type_entry = type_node->codegen_node->data.type_node.entry; | |
| 2676 | TypeTableEntry *type_entry = type_node->data.type.entry; | |
| 2688 | 2677 | assert(type_entry); |
| 2689 | 2678 | |
| 2690 | 2679 | if (type_entry == g->builtin_types.entry_u8) { |
src/codegen.hpp-13| ... | ... | @@ -11,21 +11,8 @@ |
| 11 | 11 | #include "parser.hpp" |
| 12 | 12 | #include "errmsg.hpp" |
| 13 | 13 | |
| 14 | struct CodeGen; | |
| 15 | ||
| 16 | enum OutType { | |
| 17 | OutTypeUnknown, | |
| 18 | OutTypeExe, | |
| 19 | OutTypeLib, | |
| 20 | OutTypeObj, | |
| 21 | }; | |
| 22 | ||
| 23 | 14 | CodeGen *codegen_create(Buf *root_source_dir); |
| 24 | 15 | |
| 25 | enum CodeGenBuildType { | |
| 26 | CodeGenBuildTypeDebug, | |
| 27 | CodeGenBuildTypeRelease, | |
| 28 | }; | |
| 29 | 16 | void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type); |
| 30 | 17 | void codegen_set_is_static(CodeGen *codegen, bool is_static); |
| 31 | 18 | void codegen_set_strip(CodeGen *codegen, bool strip); |
src/parser.cpp+9-9| ... | ... | @@ -356,8 +356,7 @@ void ast_print(AstNode *node, int indent) { |
| 356 | 356 | fprintf(stderr, "Unreachable\n"); |
| 357 | 357 | break; |
| 358 | 358 | case NodeTypeSymbol: |
| 359 | fprintf(stderr, "Symbol %s\n", | |
| 360 | buf_ptr(&node->data.symbol)); | |
| 359 | fprintf(stderr, "Symbol %s\n", buf_ptr(&node->data.symbol_expr.symbol)); | |
| 361 | 360 | break; |
| 362 | 361 | case NodeTypeUse: |
| 363 | 362 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path)); |
| ... | ... | @@ -366,7 +365,8 @@ void ast_print(AstNode *node, int indent) { |
| 366 | 365 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 367 | 366 | break; |
| 368 | 367 | case NodeTypeBoolLiteral: |
| 369 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false"); | |
| 368 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), | |
| 369 | node->data.bool_literal.value ? "true" : "false"); | |
| 370 | 370 | break; |
| 371 | 371 | case NodeTypeNullLiteral: |
| 372 | 372 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| ... | ... | @@ -401,7 +401,7 @@ void ast_print(AstNode *node, int indent) { |
| 401 | 401 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name)); |
| 402 | 402 | break; |
| 403 | 403 | case NodeTypeGoto: |
| 404 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name)); | |
| 404 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.goto_expr.name)); | |
| 405 | 405 | break; |
| 406 | 406 | case NodeTypeBreak: |
| 407 | 407 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| ... | ... | @@ -1369,12 +1369,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1369 | 1369 | return node; |
| 1370 | 1370 | } else if (token->id == TokenIdKeywordTrue) { |
| 1371 | 1371 | AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token); |
| 1372 | node->data.bool_literal = true; | |
| 1372 | node->data.bool_literal.value = true; | |
| 1373 | 1373 | *token_index += 1; |
| 1374 | 1374 | return node; |
| 1375 | 1375 | } else if (token->id == TokenIdKeywordFalse) { |
| 1376 | 1376 | AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token); |
| 1377 | node->data.bool_literal = false; | |
| 1377 | node->data.bool_literal.value = false; | |
| 1378 | 1378 | *token_index += 1; |
| 1379 | 1379 | return node; |
| 1380 | 1380 | } else if (token->id == TokenIdKeywordNull) { |
| ... | ... | @@ -1385,7 +1385,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1385 | 1385 | *token_index += 1; |
| 1386 | 1386 | Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); |
| 1387 | 1387 | AstNode *name_node = ast_create_node(pc, NodeTypeSymbol, name_tok); |
| 1388 | ast_buf_from_token(pc, name_tok, &name_node->data.symbol); | |
| 1388 | ast_buf_from_token(pc, name_tok, &name_node->data.symbol_expr.symbol); | |
| 1389 | 1389 | |
| 1390 | 1390 | AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token); |
| 1391 | 1391 | node->data.fn_call_expr.fn_ref_expr = name_node; |
| ... | ... | @@ -1401,7 +1401,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1401 | 1401 | } else { |
| 1402 | 1402 | *token_index += 1; |
| 1403 | 1403 | AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); |
| 1404 | ast_buf_from_token(pc, token, &node->data.symbol); | |
| 1404 | ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol); | |
| 1405 | 1405 | return node; |
| 1406 | 1406 | } |
| 1407 | 1407 | } else if (token->id == TokenIdKeywordGoto) { |
| ... | ... | @@ -1412,7 +1412,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1412 | 1412 | *token_index += 1; |
| 1413 | 1413 | ast_expect_token(pc, dest_symbol, TokenIdSymbol); |
| 1414 | 1414 | |
| 1415 | ast_buf_from_token(pc, dest_symbol, &node->data.go_to.name); | |
| 1415 | ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name); | |
| 1416 | 1416 | return node; |
| 1417 | 1417 | } else if (token->id == TokenIdKeywordBreak) { |
| 1418 | 1418 | AstNode *node = ast_create_node(pc, NodeTypeBreak, token); |
src/parser.hpp+1-441| ... | ... | @@ -8,450 +8,10 @@ |
| 8 | 8 | #ifndef ZIG_PARSER_HPP |
| 9 | 9 | #define ZIG_PARSER_HPP |
| 10 | 10 | |
| 11 | #include "list.hpp" | |
| 12 | #include "buffer.hpp" | |
| 11 | #include "all_types.hpp" | |
| 13 | 12 | #include "tokenizer.hpp" |
| 14 | 13 | #include "errmsg.hpp" |
| 15 | 14 | |
| 16 | struct AstNode; | |
| 17 | struct CodeGenNode; | |
| 18 | struct ImportTableEntry; | |
| 19 | struct AsmToken; | |
| 20 | ||
| 21 | enum NodeType { | |
| 22 | NodeTypeRoot, | |
| 23 | NodeTypeRootExportDecl, | |
| 24 | NodeTypeFnProto, | |
| 25 | NodeTypeFnDef, | |
| 26 | NodeTypeFnDecl, | |
| 27 | NodeTypeParamDecl, | |
| 28 | NodeTypeType, | |
| 29 | NodeTypeBlock, | |
| 30 | NodeTypeExternBlock, | |
| 31 | NodeTypeDirective, | |
| 32 | NodeTypeReturnExpr, | |
| 33 | NodeTypeVariableDeclaration, | |
| 34 | NodeTypeBinOpExpr, | |
| 35 | NodeTypeCastExpr, | |
| 36 | NodeTypeNumberLiteral, | |
| 37 | NodeTypeStringLiteral, | |
| 38 | NodeTypeCharLiteral, | |
| 39 | NodeTypeUnreachable, | |
| 40 | NodeTypeSymbol, | |
| 41 | NodeTypePrefixOpExpr, | |
| 42 | NodeTypeFnCallExpr, | |
| 43 | NodeTypeArrayAccessExpr, | |
| 44 | NodeTypeSliceExpr, | |
| 45 | NodeTypeFieldAccessExpr, | |
| 46 | NodeTypeUse, | |
| 47 | NodeTypeVoid, | |
| 48 | NodeTypeBoolLiteral, | |
| 49 | NodeTypeNullLiteral, | |
| 50 | NodeTypeIfBoolExpr, | |
| 51 | NodeTypeIfVarExpr, | |
| 52 | NodeTypeWhileExpr, | |
| 53 | NodeTypeLabel, | |
| 54 | NodeTypeGoto, | |
| 55 | NodeTypeBreak, | |
| 56 | NodeTypeContinue, | |
| 57 | NodeTypeAsmExpr, | |
| 58 | NodeTypeStructDecl, | |
| 59 | NodeTypeStructField, | |
| 60 | NodeTypeStructValueExpr, | |
| 61 | NodeTypeStructValueField, | |
| 62 | NodeTypeEnumDecl, | |
| 63 | NodeTypeEnumField, | |
| 64 | NodeTypeCompilerFnExpr, | |
| 65 | NodeTypeCompilerFnType, | |
| 66 | }; | |
| 67 | ||
| 68 | struct AstNodeRoot { | |
| 69 | ZigList<AstNode *> top_level_decls; | |
| 70 | }; | |
| 71 | ||
| 72 | enum VisibMod { | |
| 73 | VisibModPrivate, | |
| 74 | VisibModPub, | |
| 75 | VisibModExport, | |
| 76 | }; | |
| 77 | ||
| 78 | struct AstNodeFnProto { | |
| 79 | ZigList<AstNode *> *directives; | |
| 80 | VisibMod visib_mod; | |
| 81 | Buf name; | |
| 82 | ZigList<AstNode *> params; | |
| 83 | AstNode *return_type; | |
| 84 | bool is_var_args; | |
| 85 | ||
| 86 | // the extern block this fn proto is inside. can be null. | |
| 87 | // populated by semantic analyzer. | |
| 88 | AstNode *extern_node; | |
| 89 | // the struct decl node this fn proto is inside. can be null. | |
| 90 | // populated by semantic analyzer. | |
| 91 | AstNode *struct_node; | |
| 92 | // the function definition this fn proto is inside. can be null. | |
| 93 | // populated by semantic analyzer. | |
| 94 | AstNode *fn_def_node; | |
| 95 | }; | |
| 96 | ||
| 97 | struct AstNodeFnDef { | |
| 98 | AstNode *fn_proto; | |
| 99 | AstNode *body; | |
| 100 | }; | |
| 101 | ||
| 102 | struct AstNodeFnDecl { | |
| 103 | AstNode *fn_proto; | |
| 104 | }; | |
| 105 | ||
| 106 | struct AstNodeParamDecl { | |
| 107 | Buf name; | |
| 108 | AstNode *type; | |
| 109 | }; | |
| 110 | ||
| 111 | enum AstNodeTypeType { | |
| 112 | AstNodeTypeTypePrimitive, | |
| 113 | AstNodeTypeTypePointer, | |
| 114 | AstNodeTypeTypeArray, | |
| 115 | AstNodeTypeTypeMaybe, | |
| 116 | AstNodeTypeTypeCompilerExpr, | |
| 117 | }; | |
| 118 | ||
| 119 | struct AstNodeType { | |
| 120 | AstNodeTypeType type; | |
| 121 | Buf primitive_name; | |
| 122 | AstNode *child_type; | |
| 123 | AstNode *array_size; // can be null | |
| 124 | bool is_const; | |
| 125 | bool is_noalias; | |
| 126 | AstNode *compiler_expr; | |
| 127 | }; | |
| 128 | ||
| 129 | struct AstNodeBlock { | |
| 130 | ZigList<AstNode *> statements; | |
| 131 | }; | |
| 132 | ||
| 133 | struct AstNodeReturnExpr { | |
| 134 | // might be null in case of return void; | |
| 135 | AstNode *expr; | |
| 136 | }; | |
| 137 | ||
| 138 | struct AstNodeVariableDeclaration { | |
| 139 | Buf symbol; | |
| 140 | bool is_const; | |
| 141 | VisibMod visib_mod; | |
| 142 | // one or both of type and expr will be non null | |
| 143 | AstNode *type; | |
| 144 | AstNode *expr; | |
| 145 | }; | |
| 146 | ||
| 147 | enum BinOpType { | |
| 148 | BinOpTypeInvalid, | |
| 149 | BinOpTypeAssign, | |
| 150 | BinOpTypeAssignTimes, | |
| 151 | BinOpTypeAssignDiv, | |
| 152 | BinOpTypeAssignMod, | |
| 153 | BinOpTypeAssignPlus, | |
| 154 | BinOpTypeAssignMinus, | |
| 155 | BinOpTypeAssignBitShiftLeft, | |
| 156 | BinOpTypeAssignBitShiftRight, | |
| 157 | BinOpTypeAssignBitAnd, | |
| 158 | BinOpTypeAssignBitXor, | |
| 159 | BinOpTypeAssignBitOr, | |
| 160 | BinOpTypeAssignBoolAnd, | |
| 161 | BinOpTypeAssignBoolOr, | |
| 162 | BinOpTypeBoolOr, | |
| 163 | BinOpTypeBoolAnd, | |
| 164 | BinOpTypeCmpEq, | |
| 165 | BinOpTypeCmpNotEq, | |
| 166 | BinOpTypeCmpLessThan, | |
| 167 | BinOpTypeCmpGreaterThan, | |
| 168 | BinOpTypeCmpLessOrEq, | |
| 169 | BinOpTypeCmpGreaterOrEq, | |
| 170 | BinOpTypeBinOr, | |
| 171 | BinOpTypeBinXor, | |
| 172 | BinOpTypeBinAnd, | |
| 173 | BinOpTypeBitShiftLeft, | |
| 174 | BinOpTypeBitShiftRight, | |
| 175 | BinOpTypeAdd, | |
| 176 | BinOpTypeSub, | |
| 177 | BinOpTypeMult, | |
| 178 | BinOpTypeDiv, | |
| 179 | BinOpTypeMod, | |
| 180 | BinOpTypeUnwrapMaybe, | |
| 181 | }; | |
| 182 | ||
| 183 | struct AstNodeBinOpExpr { | |
| 184 | AstNode *op1; | |
| 185 | BinOpType bin_op; | |
| 186 | AstNode *op2; | |
| 187 | }; | |
| 188 | ||
| 189 | struct AstNodeFnCallExpr { | |
| 190 | AstNode *fn_ref_expr; | |
| 191 | ZigList<AstNode *> params; | |
| 192 | bool is_builtin; | |
| 193 | }; | |
| 194 | ||
| 195 | struct AstNodeArrayAccessExpr { | |
| 196 | AstNode *array_ref_expr; | |
| 197 | AstNode *subscript; | |
| 198 | }; | |
| 199 | ||
| 200 | struct AstNodeSliceExpr { | |
| 201 | AstNode *array_ref_expr; | |
| 202 | AstNode *start; | |
| 203 | AstNode *end; | |
| 204 | bool is_const; | |
| 205 | }; | |
| 206 | ||
| 207 | struct AstNodeFieldAccessExpr { | |
| 208 | AstNode *struct_expr; | |
| 209 | Buf field_name; | |
| 210 | }; | |
| 211 | ||
| 212 | struct AstNodeExternBlock { | |
| 213 | ZigList<AstNode *> *directives; | |
| 214 | ZigList<AstNode *> fn_decls; | |
| 215 | }; | |
| 216 | ||
| 217 | struct AstNodeDirective { | |
| 218 | Buf name; | |
| 219 | Buf param; | |
| 220 | }; | |
| 221 | ||
| 222 | struct AstNodeRootExportDecl { | |
| 223 | Buf type; | |
| 224 | Buf name; | |
| 225 | ZigList<AstNode *> *directives; | |
| 226 | }; | |
| 227 | ||
| 228 | struct AstNodeCastExpr { | |
| 229 | AstNode *expr; | |
| 230 | AstNode *type; | |
| 231 | }; | |
| 232 | ||
| 233 | enum PrefixOp { | |
| 234 | PrefixOpInvalid, | |
| 235 | PrefixOpBoolNot, | |
| 236 | PrefixOpBinNot, | |
| 237 | PrefixOpNegation, | |
| 238 | PrefixOpAddressOf, | |
| 239 | PrefixOpConstAddressOf, | |
| 240 | PrefixOpDereference, | |
| 241 | }; | |
| 242 | ||
| 243 | struct AstNodePrefixOpExpr { | |
| 244 | PrefixOp prefix_op; | |
| 245 | AstNode *primary_expr; | |
| 246 | }; | |
| 247 | ||
| 248 | struct AstNodeUse { | |
| 249 | Buf path; | |
| 250 | ZigList<AstNode *> *directives; | |
| 251 | }; | |
| 252 | ||
| 253 | struct AstNodeIfBoolExpr { | |
| 254 | AstNode *condition; | |
| 255 | AstNode *then_block; | |
| 256 | AstNode *else_node; // null, block node, or other if expr node | |
| 257 | }; | |
| 258 | ||
| 259 | struct AstNodeIfVarExpr { | |
| 260 | AstNodeVariableDeclaration var_decl; | |
| 261 | AstNode *then_block; | |
| 262 | AstNode *else_node; // null, block node, or other if expr node | |
| 263 | }; | |
| 264 | ||
| 265 | struct AstNodeWhileExpr { | |
| 266 | AstNode *condition; | |
| 267 | AstNode *body; | |
| 268 | }; | |
| 269 | ||
| 270 | struct AstNodeLabel { | |
| 271 | Buf name; | |
| 272 | }; | |
| 273 | ||
| 274 | struct AstNodeGoto { | |
| 275 | Buf name; | |
| 276 | }; | |
| 277 | ||
| 278 | struct AsmOutput { | |
| 279 | Buf asm_symbolic_name; | |
| 280 | Buf constraint; | |
| 281 | Buf variable_name; | |
| 282 | AstNode *return_type; // null unless "=r" and return | |
| 283 | }; | |
| 284 | ||
| 285 | struct AsmInput { | |
| 286 | Buf asm_symbolic_name; | |
| 287 | Buf constraint; | |
| 288 | AstNode *expr; | |
| 289 | }; | |
| 290 | ||
| 291 | struct SrcPos { | |
| 292 | int line; | |
| 293 | int column; | |
| 294 | }; | |
| 295 | ||
| 296 | struct AstNodeAsmExpr { | |
| 297 | bool is_volatile; | |
| 298 | Buf asm_template; | |
| 299 | ZigList<SrcPos> offset_map; | |
| 300 | ZigList<AsmToken> token_list; | |
| 301 | ZigList<AsmOutput*> output_list; | |
| 302 | ZigList<AsmInput*> input_list; | |
| 303 | ZigList<Buf*> clobber_list; | |
| 304 | int return_count; // populated by analyze | |
| 305 | }; | |
| 306 | ||
| 307 | struct AstNodeStructDecl { | |
| 308 | Buf name; | |
| 309 | ZigList<AstNode *> fields; | |
| 310 | ZigList<AstNode *> fns; | |
| 311 | ZigList<AstNode *> *directives; | |
| 312 | VisibMod visib_mod; | |
| 313 | }; | |
| 314 | ||
| 315 | struct AstNodeStructField { | |
| 316 | Buf name; | |
| 317 | AstNode *type; | |
| 318 | ZigList<AstNode *> *directives; | |
| 319 | }; | |
| 320 | ||
| 321 | struct AstNodeEnumDecl { | |
| 322 | Buf name; | |
| 323 | ZigList<AstNode *> fields; | |
| 324 | ZigList<AstNode *> *directives; | |
| 325 | VisibMod visib_mod; | |
| 326 | }; | |
| 327 | ||
| 328 | struct AstNodeEnumField { | |
| 329 | Buf name; | |
| 330 | ZigList<AstNode *> fields; // length 0 means simple enum | |
| 331 | AstNode *val_expr; | |
| 332 | }; | |
| 333 | ||
| 334 | struct AstNodeStringLiteral { | |
| 335 | Buf buf; | |
| 336 | bool c; | |
| 337 | }; | |
| 338 | ||
| 339 | struct AstNodeCharLiteral { | |
| 340 | uint8_t value; | |
| 341 | }; | |
| 342 | ||
| 343 | enum NumLit { | |
| 344 | NumLitF32, | |
| 345 | NumLitF64, | |
| 346 | NumLitF128, | |
| 347 | NumLitU8, | |
| 348 | NumLitU16, | |
| 349 | NumLitU32, | |
| 350 | NumLitU64, | |
| 351 | NumLitI8, | |
| 352 | NumLitI16, | |
| 353 | NumLitI32, | |
| 354 | NumLitI64, | |
| 355 | ||
| 356 | NumLitCount | |
| 357 | }; | |
| 358 | ||
| 359 | struct AstNodeNumberLiteral { | |
| 360 | NumLit kind; | |
| 361 | ||
| 362 | // overflow is true if when parsing the number, we discovered it would not | |
| 363 | // fit without losing data in a uint64_t, int64_t, or double | |
| 364 | bool overflow; | |
| 365 | ||
| 366 | union { | |
| 367 | uint64_t x_uint; | |
| 368 | int64_t x_int; | |
| 369 | double x_float; | |
| 370 | } data; | |
| 371 | }; | |
| 372 | ||
| 373 | struct AstNodeStructValueField { | |
| 374 | Buf name; | |
| 375 | AstNode *expr; | |
| 376 | }; | |
| 377 | ||
| 378 | struct AstNodeStructValueExpr { | |
| 379 | AstNode *type; | |
| 380 | ZigList<AstNode *> fields; | |
| 381 | }; | |
| 382 | ||
| 383 | struct AstNodeCompilerFnExpr { | |
| 384 | Buf name; | |
| 385 | AstNode *expr; | |
| 386 | }; | |
| 387 | ||
| 388 | struct AstNodeCompilerFnType { | |
| 389 | Buf name; | |
| 390 | AstNode *type; | |
| 391 | }; | |
| 392 | ||
| 393 | struct AstNode { | |
| 394 | enum NodeType type; | |
| 395 | int line; | |
| 396 | int column; | |
| 397 | uint32_t create_index; // for determinism purposes | |
| 398 | CodeGenNode *codegen_node; | |
| 399 | ImportTableEntry *owner; | |
| 400 | union { | |
| 401 | AstNodeRoot root; | |
| 402 | AstNodeRootExportDecl root_export_decl; | |
| 403 | AstNodeFnDef fn_def; | |
| 404 | AstNodeFnDecl fn_decl; | |
| 405 | AstNodeFnProto fn_proto; | |
| 406 | AstNodeType type; | |
| 407 | AstNodeParamDecl param_decl; | |
| 408 | AstNodeBlock block; | |
| 409 | AstNodeReturnExpr return_expr; | |
| 410 | AstNodeVariableDeclaration variable_declaration; | |
| 411 | AstNodeBinOpExpr bin_op_expr; | |
| 412 | AstNodeExternBlock extern_block; | |
| 413 | AstNodeDirective directive; | |
| 414 | AstNodeCastExpr cast_expr; | |
| 415 | AstNodePrefixOpExpr prefix_op_expr; | |
| 416 | AstNodeFnCallExpr fn_call_expr; | |
| 417 | AstNodeArrayAccessExpr array_access_expr; | |
| 418 | AstNodeSliceExpr slice_expr; | |
| 419 | AstNodeUse use; | |
| 420 | AstNodeIfBoolExpr if_bool_expr; | |
| 421 | AstNodeIfVarExpr if_var_expr; | |
| 422 | AstNodeWhileExpr while_expr; | |
| 423 | AstNodeLabel label; | |
| 424 | AstNodeGoto go_to; | |
| 425 | AstNodeAsmExpr asm_expr; | |
| 426 | AstNodeFieldAccessExpr field_access_expr; | |
| 427 | AstNodeStructDecl struct_decl; | |
| 428 | AstNodeStructField struct_field; | |
| 429 | AstNodeEnumDecl enum_decl; | |
| 430 | AstNodeEnumField enum_field; | |
| 431 | AstNodeStringLiteral string_literal; | |
| 432 | AstNodeCharLiteral char_literal; | |
| 433 | AstNodeNumberLiteral number_literal; | |
| 434 | AstNodeStructValueExpr struct_val_expr; | |
| 435 | AstNodeStructValueField struct_val_field; | |
| 436 | AstNodeCompilerFnExpr compiler_fn_expr; | |
| 437 | AstNodeCompilerFnType compiler_fn_type; | |
| 438 | Buf symbol; | |
| 439 | bool bool_literal; | |
| 440 | } data; | |
| 441 | }; | |
| 442 | ||
| 443 | enum AsmTokenId { | |
| 444 | AsmTokenIdTemplate, | |
| 445 | AsmTokenIdPercent, | |
| 446 | AsmTokenIdVar, | |
| 447 | }; | |
| 448 | ||
| 449 | struct AsmToken { | |
| 450 | enum AsmTokenId id; | |
| 451 | int start; | |
| 452 | int end; | |
| 453 | }; | |
| 454 | ||
| 455 | 15 | __attribute__ ((format (printf, 2, 3))) |
| 456 | 16 | void ast_token_error(Token *token, const char *format, ...); |
| 457 | 17 |