| author | |
| committer | |
| log | a10277bd949d47370e427d4457d93e907de9a6f7 |
| tree | 4f5ca4247559c679a5a04ea0816c2c78f90211ed |
| parent | 4c16eaa6401786e6c2de84d7c9f231107d6f2cb7 |
parsing code for structs, strings, and c string literals
partial semantic analyzing code for structs, strings, and c string literals15 files changed, 599 insertions(+), 107 deletions(-)
doc/langref.md+14-8| ... | ... | @@ -32,7 +32,11 @@ zig | C equivalent | Description |
| 32 | 32 | ``` |
| 33 | 33 | Root : many(TopLevelDecl) token(EOF) |
| 34 | 34 | |
| 35 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | |
| 35 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | |
| 36 | ||
| 37 | StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace) | |
| 38 | ||
| 39 | StructField : token(Symbol) token(Colon) Type token(Comma) | |
| 36 | 40 | |
| 37 | 41 | Use : many(Directive) token(Use) token(String) token(Semicolon) |
| 38 | 42 | |
| ... | ... | @@ -126,7 +130,9 @@ CastExpression : PrefixOpExpression token(as) Type | PrefixOpExpression |
| 126 | 130 | |
| 127 | 131 | PrefixOpExpression : PrefixOp SuffixOpExpression | SuffixOpExpression |
| 128 | 132 | |
| 129 | SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression) | |
| 133 | SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression) | |
| 134 | ||
| 135 | FieldAccessExpression : token(Dot) token(Symbol) | |
| 130 | 136 | |
| 131 | 137 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) |
| 132 | 138 | |
| ... | ... | @@ -146,7 +152,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) |
| 146 | 152 | ## Operator Precedence |
| 147 | 153 | |
| 148 | 154 | ``` |
| 149 | x() x[] | |
| 155 | x() x[] x.y | |
| 150 | 156 | !x -x ~x |
| 151 | 157 | as |
| 152 | 158 | * / % |
| ... | ... | @@ -165,11 +171,11 @@ as |
| 165 | 171 | |
| 166 | 172 | ### Characters and Strings |
| 167 | 173 | |
| 168 | | Example | Characters | Escapes | Null Terminated | |
| 169 | ------------------------------------------------------------------------------- | |
| 170 | Byte | 'H' | All ASCII | Byte | No | |
| 171 | UTF-8 Bytes | "hello" | All Unicode | Byte & Unicode | No | |
| 172 | UTF-8 C string | c"hello" | All Unicode | Byte & Unicode | Yes | |
| 174 | | Example | Characters | Escapes | Null Term | Type | |
| 175 | --------------------------------------------------------------------------------- | |
| 176 | Byte | 'H' | All ASCII | Byte | No | u8 | |
| 177 | UTF-8 Bytes | "hello" | All Unicode | Byte & Unicode | No | [5; u8] | |
| 178 | UTF-8 C string | c"hello" | All Unicode | Byte & Unicode | Yes | *const u8 | |
| 173 | 179 | |
| 174 | 180 | ### Byte Escapes |
| 175 | 181 |
doc/vim/syntax/zig.vim+1-1| ... | ... | @@ -9,7 +9,7 @@ endif |
| 9 | 9 | |
| 10 | 10 | syn keyword zigKeyword fn return mut const extern unreachable export pub as use while asm |
| 11 | 11 | syn keyword zigKeyword if else let void goto type enum struct continue break match volatile |
| 12 | syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 | |
| 12 | syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string | |
| 13 | 13 | |
| 14 | 14 | syn keyword zigConstant null |
| 15 | 15 |
example/hello_world/hello2.zig+1-1| ... | ... | @@ -3,6 +3,6 @@ export executable "hello"; |
| 3 | 3 | use "std.zig"; |
| 4 | 4 | |
| 5 | 5 | export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 { |
| 6 | print_str("Hello, world!\n", 14 as isize); | |
| 6 | print_str("Hello, world!\n"); | |
| 7 | 7 | return 0; |
| 8 | 8 | } |
example/structs/structs.zig created+27| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | export executable "structs"; | |
| 2 | ||
| 3 | use "std.zig"; | |
| 4 | ||
| 5 | export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 { | |
| 6 | let mut foo : Foo; | |
| 7 | ||
| 8 | foo.a = foo.a + 1; | |
| 9 | ||
| 10 | foo.b = foo.a == 1; | |
| 11 | ||
| 12 | test_foo(foo); | |
| 13 | ||
| 14 | return 0; | |
| 15 | } | |
| 16 | ||
| 17 | struct Foo { | |
| 18 | a : i32, | |
| 19 | b : bool, | |
| 20 | c : f32, | |
| 21 | } | |
| 22 | ||
| 23 | fn test_foo(foo : Foo) { | |
| 24 | if foo.b { | |
| 25 | print_str("OK"); | |
| 26 | } | |
| 27 | } |
src/analyze.cpp+200-22| ... | ... | @@ -13,6 +13,11 @@ |
| 13 | 13 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 14 | 14 | TypeTableEntry *expected_type, AstNode *node); |
| 15 | 15 | |
| 16 | static void alloc_codegen_node(AstNode *node) { | |
| 17 | assert(!node->codegen_node); | |
| 18 | node->codegen_node = allocate<CodeGenNode>(1); | |
| 19 | } | |
| 20 | ||
| 16 | 21 | static AstNode *first_executing_node(AstNode *node) { |
| 17 | 22 | switch (node->type) { |
| 18 | 23 | case NodeTypeFnCallExpr: |
| ... | ... | @@ -44,6 +49,9 @@ static AstNode *first_executing_node(AstNode *node) { |
| 44 | 49 | case NodeTypeLabel: |
| 45 | 50 | case NodeTypeGoto: |
| 46 | 51 | case NodeTypeAsmExpr: |
| 52 | case NodeTypeFieldAccessExpr: | |
| 53 | case NodeTypeStructDecl: | |
| 54 | case NodeTypeStructField: | |
| 47 | 55 | return node; |
| 48 | 56 | } |
| 49 | 57 | zig_panic("unreachable"); |
| ... | ... | @@ -129,6 +137,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, in |
| 129 | 137 | entry->di_type = LLVMZigCreateDebugArrayType(g->dbuilder, entry->size_in_bits, |
| 130 | 138 | entry->align_in_bits, child_type->di_type, array_size); |
| 131 | 139 | entry->data.array.child_type = child_type; |
| 140 | entry->data.array.len = array_size; | |
| 132 | 141 | |
| 133 | 142 | g->type_table.put(&entry->name, entry); |
| 134 | 143 | child_type->arrays_by_size.put(array_size, entry); |
| ... | ... | @@ -143,8 +152,7 @@ static int parse_int(Buf *number) { |
| 143 | 152 | |
| 144 | 153 | static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { |
| 145 | 154 | assert(node->type == NodeTypeType); |
| 146 | assert(!node->codegen_node); | |
| 147 | node->codegen_node = allocate<CodeGenNode>(1); | |
| 155 | alloc_codegen_node(node); | |
| 148 | 156 | TypeNode *type_node = &node->codegen_node->data.type_node; |
| 149 | 157 | switch (node->data.type.type) { |
| 150 | 158 | case AstNodeTypeTypePrimitive: |
| ... | ... | @@ -259,8 +267,7 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_ |
| 259 | 267 | Buf *name = &label_node->data.label.name; |
| 260 | 268 | fn_table_entry->label_table.put(name, label_entry); |
| 261 | 269 | |
| 262 | assert(!label_node->codegen_node); | |
| 263 | label_node->codegen_node = allocate<CodeGenNode>(1); | |
| 270 | alloc_codegen_node(label_node); | |
| 264 | 271 | label_node->codegen_node->data.label_entry = label_entry; |
| 265 | 272 | } |
| 266 | 273 | } |
| ... | ... | @@ -302,8 +309,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 302 | 309 | g->fn_table.put(name, fn_table_entry); |
| 303 | 310 | } |
| 304 | 311 | |
| 305 | assert(!fn_proto->codegen_node); | |
| 306 | fn_proto->codegen_node = allocate<CodeGenNode>(1); | |
| 312 | alloc_codegen_node(fn_proto); | |
| 307 | 313 | fn_proto->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; |
| 308 | 314 | } |
| 309 | 315 | break; |
| ... | ... | @@ -319,8 +325,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 319 | 325 | if (entry) { |
| 320 | 326 | add_node_error(g, node, |
| 321 | 327 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 322 | assert(!node->codegen_node); | |
| 323 | node->codegen_node = allocate<CodeGenNode>(1); | |
| 328 | alloc_codegen_node(node); | |
| 324 | 329 | node->codegen_node->data.fn_def_node.skip = true; |
| 325 | 330 | skip = true; |
| 326 | 331 | } else if (is_pub) { |
| ... | ... | @@ -328,8 +333,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 328 | 333 | if (entry) { |
| 329 | 334 | add_node_error(g, node, |
| 330 | 335 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| 331 | assert(!node->codegen_node); | |
| 332 | node->codegen_node = allocate<CodeGenNode>(1); | |
| 336 | alloc_codegen_node(node); | |
| 333 | 337 | node->codegen_node->data.fn_def_node.skip = true; |
| 334 | 338 | skip = true; |
| 335 | 339 | } |
| ... | ... | @@ -358,8 +362,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 358 | 362 | resolve_function_proto(g, proto_node, fn_table_entry); |
| 359 | 363 | |
| 360 | 364 | |
| 361 | assert(!proto_node->codegen_node); | |
| 362 | proto_node->codegen_node = allocate<CodeGenNode>(1); | |
| 365 | alloc_codegen_node(proto_node); | |
| 363 | 366 | proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; |
| 364 | 367 | |
| 365 | 368 | preview_function_labels(g, node->data.fn_def.body, fn_table_entry); |
| ... | ... | @@ -409,6 +412,31 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 409 | 412 | buf_sprintf("root export declaration only valid in root source file")); |
| 410 | 413 | } |
| 411 | 414 | break; |
| 415 | case NodeTypeStructDecl: | |
| 416 | { | |
| 417 | StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node; | |
| 418 | TypeTableEntry *type_entry = struct_codegen->type_entry; | |
| 419 | ||
| 420 | int field_count = node->data.struct_decl.fields.length;; | |
| 421 | type_entry->data.structure.field_count = field_count; | |
| 422 | type_entry->data.structure.fields = allocate<TypeStructField>(field_count); | |
| 423 | ||
| 424 | LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count); | |
| 425 | ||
| 426 | for (int i = 0; i < field_count; i += 1) { | |
| 427 | AstNode *field_node = node->data.struct_decl.fields.at(i); | |
| 428 | TypeStructField *type_struct_field = &type_entry->data.structure.fields[i]; | |
| 429 | type_struct_field->name = &field_node->data.struct_field.name; | |
| 430 | type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type); | |
| 431 | ||
| 432 | element_types[i] = type_struct_field->type_entry->type_ref; | |
| 433 | } | |
| 434 | // TODO align_in_bits and size_in_bits | |
| 435 | // TODO set up ditype for the struct | |
| 436 | LLVMStructSetBody(type_entry->type_ref, element_types, field_count, false); | |
| 437 | ||
| 438 | break; | |
| 439 | } | |
| 412 | 440 | case NodeTypeUse: |
| 413 | 441 | // nothing to do here |
| 414 | 442 | break; |
| ... | ... | @@ -436,6 +464,68 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 436 | 464 | case NodeTypeLabel: |
| 437 | 465 | case NodeTypeGoto: |
| 438 | 466 | case NodeTypeAsmExpr: |
| 467 | case NodeTypeFieldAccessExpr: | |
| 468 | case NodeTypeStructField: | |
| 469 | zig_unreachable(); | |
| 470 | } | |
| 471 | } | |
| 472 | ||
| 473 | static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) { | |
| 474 | switch (node->type) { | |
| 475 | case NodeTypeStructDecl: | |
| 476 | { | |
| 477 | alloc_codegen_node(node); | |
| 478 | StructDeclNode *struct_codegen = &node->codegen_node->data.struct_decl_node; | |
| 479 | ||
| 480 | Buf *name = &node->data.struct_decl.name; | |
| 481 | auto table_entry = g->type_table.maybe_get(name); | |
| 482 | if (table_entry) { | |
| 483 | struct_codegen->type_entry = table_entry->value; | |
| 484 | add_node_error(g, node, | |
| 485 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | |
| 486 | } else { | |
| 487 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); | |
| 488 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name)); | |
| 489 | buf_init_from_buf(&entry->name, name); | |
| 490 | // put off adding the debug type until we do the full struct body | |
| 491 | // this type is incomplete until we do another pass | |
| 492 | g->type_table.put(&entry->name, entry); | |
| 493 | struct_codegen->type_entry = entry; | |
| 494 | } | |
| 495 | break; | |
| 496 | } | |
| 497 | case NodeTypeExternBlock: | |
| 498 | case NodeTypeFnDef: | |
| 499 | case NodeTypeRootExportDecl: | |
| 500 | case NodeTypeUse: | |
| 501 | // nothing to do | |
| 502 | break; | |
| 503 | case NodeTypeDirective: | |
| 504 | case NodeTypeParamDecl: | |
| 505 | case NodeTypeFnProto: | |
| 506 | case NodeTypeType: | |
| 507 | case NodeTypeFnDecl: | |
| 508 | case NodeTypeReturnExpr: | |
| 509 | case NodeTypeVariableDeclaration: | |
| 510 | case NodeTypeRoot: | |
| 511 | case NodeTypeBlock: | |
| 512 | case NodeTypeBinOpExpr: | |
| 513 | case NodeTypeFnCallExpr: | |
| 514 | case NodeTypeArrayAccessExpr: | |
| 515 | case NodeTypeNumberLiteral: | |
| 516 | case NodeTypeStringLiteral: | |
| 517 | case NodeTypeUnreachable: | |
| 518 | case NodeTypeVoid: | |
| 519 | case NodeTypeBoolLiteral: | |
| 520 | case NodeTypeSymbol: | |
| 521 | case NodeTypeCastExpr: | |
| 522 | case NodeTypePrefixOpExpr: | |
| 523 | case NodeTypeIfExpr: | |
| 524 | case NodeTypeLabel: | |
| 525 | case NodeTypeGoto: | |
| 526 | case NodeTypeAsmExpr: | |
| 527 | case NodeTypeFieldAccessExpr: | |
| 528 | case NodeTypeStructField: | |
| 439 | 529 | zig_unreachable(); |
| 440 | 530 | } |
| 441 | 531 | } |
| ... | ... | @@ -460,7 +550,9 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) { |
| 460 | 550 | return fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; |
| 461 | 551 | } |
| 462 | 552 | |
| 463 | static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *expected_type, TypeTableEntry *actual_type) { | |
| 553 | static void check_type_compatibility(CodeGen *g, AstNode *node, | |
| 554 | TypeTableEntry *expected_type, TypeTableEntry *actual_type) | |
| 555 | { | |
| 464 | 556 | if (expected_type == nullptr) |
| 465 | 557 | return; // anything will do |
| 466 | 558 | if (expected_type == actual_type) |
| ... | ... | @@ -471,7 +563,7 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry * |
| 471 | 563 | return; // sorry toots; gotta run. good luck with that expected type. |
| 472 | 564 | |
| 473 | 565 | add_node_error(g, node, |
| 474 | buf_sprintf("type mismatch. expected %s. got %s", | |
| 566 | buf_sprintf("expected type '%s', got '%s'", | |
| 475 | 567 | buf_ptr(&expected_type->name), |
| 476 | 568 | buf_ptr(&actual_type->name))); |
| 477 | 569 | } |
| ... | ... | @@ -507,6 +599,55 @@ LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) { |
| 507 | 599 | } |
| 508 | 600 | } |
| 509 | 601 | |
| 602 | static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name) { | |
| 603 | for (int i = 0; i < struct_type->data.structure.field_count; i += 1) { | |
| 604 | TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; | |
| 605 | if (buf_eql_buf(type_struct_field->name, name)) { | |
| 606 | return type_struct_field; | |
| 607 | } | |
| 608 | } | |
| 609 | return nullptr; | |
| 610 | } | |
| 611 | ||
| 612 | static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | |
| 613 | AstNode *node) | |
| 614 | { | |
| 615 | TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, | |
| 616 | node->data.field_access_expr.struct_expr); | |
| 617 | ||
| 618 | TypeTableEntry *return_type; | |
| 619 | ||
| 620 | if (struct_type->id == TypeTableEntryIdStruct) { | |
| 621 | Buf *field_name = &node->data.field_access_expr.field_name; | |
| 622 | TypeStructField *type_struct_field = get_struct_field(struct_type, field_name); | |
| 623 | if (type_struct_field) { | |
| 624 | return_type = type_struct_field->type_entry; | |
| 625 | } else { | |
| 626 | add_node_error(g, node, | |
| 627 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&struct_type->name))); | |
| 628 | return_type = g->builtin_types.entry_invalid; | |
| 629 | } | |
| 630 | } else if (struct_type->id == TypeTableEntryIdArray) { | |
| 631 | Buf *name = &node->data.field_access_expr.field_name; | |
| 632 | if (buf_eql_str(name, "len")) { | |
| 633 | return_type = g->builtin_types.entry_usize; | |
| 634 | } else { | |
| 635 | add_node_error(g, node, | |
| 636 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), | |
| 637 | buf_ptr(&struct_type->name))); | |
| 638 | return_type = g->builtin_types.entry_invalid; | |
| 639 | } | |
| 640 | } else { | |
| 641 | if (struct_type->id != TypeTableEntryIdInvalid) { | |
| 642 | add_node_error(g, node, | |
| 643 | buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name))); | |
| 644 | } | |
| 645 | return_type = g->builtin_types.entry_invalid; | |
| 646 | } | |
| 647 | ||
| 648 | return return_type; | |
| 649 | } | |
| 650 | ||
| 510 | 651 | static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 511 | 652 | AstNode *node) |
| 512 | 653 | { |
| ... | ... | @@ -554,8 +695,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 554 | 695 | TypeTableEntry *expected_type, AstNode *node) |
| 555 | 696 | { |
| 556 | 697 | TypeTableEntry *return_type = nullptr; |
| 557 | assert(!node->codegen_node); | |
| 558 | node->codegen_node = allocate<CodeGenNode>(1); | |
| 698 | alloc_codegen_node(node); | |
| 559 | 699 | switch (node->type) { |
| 560 | 700 | case NodeTypeBlock: |
| 561 | 701 | { |
| ... | ... | @@ -698,9 +838,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 698 | 838 | } |
| 699 | 839 | } else if (lhs_node->type == NodeTypeArrayAccessExpr) { |
| 700 | 840 | expected_rhs_type = analyze_array_access_expr(g, import, context, lhs_node); |
| 841 | } else if (lhs_node->type == NodeTypeFieldAccessExpr) { | |
| 842 | expected_rhs_type = analyze_field_access_expr(g, import, context, lhs_node); | |
| 701 | 843 | } else { |
| 702 | 844 | add_node_error(g, lhs_node, |
| 703 | buf_sprintf("expected a bare identifier")); | |
| 845 | buf_sprintf("assignment target must be variable, field, or array element")); | |
| 704 | 846 | } |
| 705 | 847 | analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2); |
| 706 | 848 | return_type = g->builtin_types.entry_void; |
| ... | ... | @@ -835,15 +977,21 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 835 | 977 | // for reading array access; assignment handled elsewhere |
| 836 | 978 | return_type = analyze_array_access_expr(g, import, context, node); |
| 837 | 979 | break; |
| 980 | case NodeTypeFieldAccessExpr: | |
| 981 | return_type = analyze_field_access_expr(g, import, context, node); | |
| 982 | break; | |
| 838 | 983 | case NodeTypeNumberLiteral: |
| 839 | 984 | // TODO: generic literal int type |
| 840 | 985 | return_type = g->builtin_types.entry_i32; |
| 841 | 986 | break; |
| 842 | 987 | |
| 843 | 988 | case NodeTypeStringLiteral: |
| 844 | return_type = g->builtin_types.entry_string_literal; | |
| 989 | if (node->data.string_literal.c) { | |
| 990 | return_type = g->builtin_types.entry_c_string_literal; | |
| 991 | } else { | |
| 992 | return_type = get_array_type(g, g->builtin_types.entry_u8, buf_len(&node->data.string_literal.buf)); | |
| 993 | } | |
| 845 | 994 | break; |
| 846 | ||
| 847 | 995 | case NodeTypeUnreachable: |
| 848 | 996 | return_type = g->builtin_types.entry_unreachable; |
| 849 | 997 | break; |
| ... | ... | @@ -884,7 +1032,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 884 | 1032 | { |
| 885 | 1033 | return_type = wanted_type; |
| 886 | 1034 | } else { |
| 887 | zig_panic("TODO analyze_expression cast expr"); | |
| 1035 | add_node_error(g, node, | |
| 1036 | buf_sprintf("TODO handle cast from '%s' to '%s'", | |
| 1037 | buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name))); | |
| 1038 | return_type = g->builtin_types.entry_invalid; | |
| 888 | 1039 | } |
| 889 | 1040 | break; |
| 890 | 1041 | } |
| ... | ... | @@ -946,6 +1097,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 946 | 1097 | case NodeTypeFnDef: |
| 947 | 1098 | case NodeTypeUse: |
| 948 | 1099 | case NodeTypeLabel: |
| 1100 | case NodeTypeStructDecl: | |
| 1101 | case NodeTypeStructField: | |
| 949 | 1102 | zig_unreachable(); |
| 950 | 1103 | } |
| 951 | 1104 | assert(return_type); |
| ... | ... | @@ -970,8 +1123,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 970 | 1123 | AstNode *fn_proto_node = node->data.fn_def.fn_proto; |
| 971 | 1124 | assert(fn_proto_node->type == NodeTypeFnProto); |
| 972 | 1125 | |
| 973 | assert(!node->codegen_node); | |
| 974 | node->codegen_node = allocate<CodeGenNode>(1); | |
| 1126 | alloc_codegen_node(node); | |
| 975 | 1127 | BlockContext *context = new_block_context(node, nullptr); |
| 976 | 1128 | node->codegen_node->data.fn_def_node.block_context = context; |
| 977 | 1129 | |
| ... | ... | @@ -1044,6 +1196,9 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 1044 | 1196 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); |
| 1045 | 1197 | } |
| 1046 | 1198 | break; |
| 1199 | case NodeTypeStructDecl: | |
| 1200 | // nothing to do | |
| 1201 | break; | |
| 1047 | 1202 | case NodeTypeDirective: |
| 1048 | 1203 | case NodeTypeParamDecl: |
| 1049 | 1204 | case NodeTypeFnProto: |
| ... | ... | @@ -1068,6 +1223,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 1068 | 1223 | case NodeTypeLabel: |
| 1069 | 1224 | case NodeTypeGoto: |
| 1070 | 1225 | case NodeTypeAsmExpr: |
| 1226 | case NodeTypeFieldAccessExpr: | |
| 1227 | case NodeTypeStructField: | |
| 1071 | 1228 | zig_unreachable(); |
| 1072 | 1229 | } |
| 1073 | 1230 | } |
| ... | ... | @@ -1082,6 +1239,16 @@ static void find_function_declarations_root(CodeGen *g, ImportTableEntry *import |
| 1082 | 1239 | |
| 1083 | 1240 | } |
| 1084 | 1241 | |
| 1242 | static void preview_types_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { | |
| 1243 | assert(node->type == NodeTypeRoot); | |
| 1244 | ||
| 1245 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { | |
| 1246 | AstNode *child = node->data.root.top_level_decls.at(i); | |
| 1247 | preview_types(g, import, child); | |
| 1248 | } | |
| 1249 | ||
| 1250 | } | |
| 1251 | ||
| 1085 | 1252 | static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 1086 | 1253 | assert(node->type == NodeTypeRoot); |
| 1087 | 1254 | |
| ... | ... | @@ -1092,6 +1259,17 @@ static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, A |
| 1092 | 1259 | } |
| 1093 | 1260 | |
| 1094 | 1261 | void semantic_analyze(CodeGen *g) { |
| 1262 | { | |
| 1263 | auto it = g->import_table.entry_iterator(); | |
| 1264 | for (;;) { | |
| 1265 | auto *entry = it.next(); | |
| 1266 | if (!entry) | |
| 1267 | break; | |
| 1268 | ||
| 1269 | ImportTableEntry *import = entry->value; | |
| 1270 | preview_types_root(g, import, import->root); | |
| 1271 | } | |
| 1272 | } | |
| 1095 | 1273 | { |
| 1096 | 1274 | auto it = g->import_table.entry_iterator(); |
| 1097 | 1275 | for (;;) { |
src/analyze.hpp+22-1| ... | ... | @@ -28,6 +28,18 @@ struct TypeTableEntryInt { |
| 28 | 28 | |
| 29 | 29 | struct TypeTableEntryArray { |
| 30 | 30 | TypeTableEntry *child_type; |
| 31 | uint64_t len; | |
| 32 | }; | |
| 33 | ||
| 34 | struct TypeStructField { | |
| 35 | Buf *name; | |
| 36 | TypeTableEntry *type_entry; | |
| 37 | }; | |
| 38 | ||
| 39 | struct TypeTableEntryStruct { | |
| 40 | bool is_packed; | |
| 41 | int field_count; | |
| 42 | TypeStructField *fields; | |
| 31 | 43 | }; |
| 32 | 44 | |
| 33 | 45 | enum TypeTableEntryId { |
| ... | ... | @@ -39,6 +51,7 @@ enum TypeTableEntryId { |
| 39 | 51 | TypeTableEntryIdFloat, |
| 40 | 52 | TypeTableEntryIdPointer, |
| 41 | 53 | TypeTableEntryIdArray, |
| 54 | TypeTableEntryIdStruct, | |
| 42 | 55 | }; |
| 43 | 56 | |
| 44 | 57 | struct TypeTableEntry { |
| ... | ... | @@ -55,6 +68,7 @@ struct TypeTableEntry { |
| 55 | 68 | TypeTableEntryPointer pointer; |
| 56 | 69 | TypeTableEntryInt integral; |
| 57 | 70 | TypeTableEntryArray array; |
| 71 | TypeTableEntryStruct structure; | |
| 58 | 72 | } data; |
| 59 | 73 | |
| 60 | 74 | // use these fields to make sure we don't duplicate type table entries for the same type |
| ... | ... | @@ -122,8 +136,10 @@ struct CodeGen { |
| 122 | 136 | TypeTableEntry *entry_u8; |
| 123 | 137 | TypeTableEntry *entry_i32; |
| 124 | 138 | TypeTableEntry *entry_isize; |
| 139 | TypeTableEntry *entry_usize; | |
| 125 | 140 | TypeTableEntry *entry_f32; |
| 126 | TypeTableEntry *entry_string_literal; | |
| 141 | TypeTableEntry *entry_c_string_literal; | |
| 142 | TypeTableEntry *entry_string; | |
| 127 | 143 | TypeTableEntry *entry_void; |
| 128 | 144 | TypeTableEntry *entry_unreachable; |
| 129 | 145 | TypeTableEntry *entry_invalid; |
| ... | ... | @@ -211,6 +227,10 @@ struct BlockNode { |
| 211 | 227 | BlockContext *block_context; |
| 212 | 228 | }; |
| 213 | 229 | |
| 230 | struct StructDeclNode { | |
| 231 | TypeTableEntry *type_entry; | |
| 232 | }; | |
| 233 | ||
| 214 | 234 | struct CodeGenNode { |
| 215 | 235 | union { |
| 216 | 236 | TypeNode type_node; // for NodeTypeType |
| ... | ... | @@ -219,6 +239,7 @@ struct CodeGenNode { |
| 219 | 239 | LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel |
| 220 | 240 | AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign |
| 221 | 241 | BlockNode block_node; // for NodeTypeBlock |
| 242 | StructDeclNode struct_decl_node; // for NodeTypeStructDecl | |
| 222 | 243 | } data; |
| 223 | 244 | ExprNode expr_node; // for all the expression nodes |
| 224 | 245 | }; |
src/codegen.cpp+83-8| ... | ... | @@ -106,12 +106,12 @@ static void add_debug_source_node(CodeGen *g, AstNode *node) { |
| 106 | 106 | g->cur_block_context->di_scope); |
| 107 | 107 | } |
| 108 | 108 | |
| 109 | static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) { | |
| 109 | static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) { | |
| 110 | 110 | auto entry = g->str_table.maybe_get(str); |
| 111 | 111 | if (entry) { |
| 112 | 112 | return entry->value; |
| 113 | 113 | } |
| 114 | LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), false); | |
| 114 | LLVMValueRef text = LLVMConstString(buf_ptr(str), buf_len(str), !c); | |
| 115 | 115 | LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(text), ""); |
| 116 | 116 | LLVMSetLinkage(global_value, LLVMPrivateLinkage); |
| 117 | 117 | LLVMSetInitializer(global_value, text); |
| ... | ... | @@ -204,6 +204,28 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) { |
| 204 | 204 | return LLVMBuildLoad(g->builder, ptr, ""); |
| 205 | 205 | } |
| 206 | 206 | |
| 207 | static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) { | |
| 208 | assert(node->type == NodeTypeFieldAccessExpr); | |
| 209 | ||
| 210 | TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr); | |
| 211 | LLVMValueRef struct_ptr = gen_expr(g, node->data.field_access_expr.struct_expr); | |
| 212 | Buf *name = &node->data.field_access_expr.field_name; | |
| 213 | ||
| 214 | // TODO add struct support | |
| 215 | (void)struct_ptr; | |
| 216 | ||
| 217 | if (struct_type->id == TypeTableEntryIdArray) { | |
| 218 | if (buf_eql_str(name, "len")) { | |
| 219 | return LLVMConstInt(g->builtin_types.entry_usize->type_ref, | |
| 220 | struct_type->data.array.len, false); | |
| 221 | } else { | |
| 222 | zig_panic("gen_field_access_expr bad array field"); | |
| 223 | } | |
| 224 | } else { | |
| 225 | zig_panic("gen_field_access_expr bad struct type"); | |
| 226 | } | |
| 227 | } | |
| 228 | ||
| 207 | 229 | static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 208 | 230 | assert(node->type == NodeTypePrefixOpExpr); |
| 209 | 231 | assert(node->data.prefix_op_expr.primary_expr); |
| ... | ... | @@ -785,6 +807,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 785 | 807 | return gen_fn_call_expr(g, node); |
| 786 | 808 | case NodeTypeArrayAccessExpr: |
| 787 | 809 | return gen_array_access_expr(g, node); |
| 810 | case NodeTypeFieldAccessExpr: | |
| 811 | return gen_field_access_expr(g, node); | |
| 788 | 812 | case NodeTypeUnreachable: |
| 789 | 813 | add_debug_source_node(g, node); |
| 790 | 814 | return LLVMBuildUnreachable(g->builder); |
| ... | ... | @@ -809,8 +833,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 809 | 833 | } |
| 810 | 834 | case NodeTypeStringLiteral: |
| 811 | 835 | { |
| 812 | Buf *str = &node->data.string; | |
| 813 | LLVMValueRef str_val = find_or_create_string(g, str); | |
| 836 | Buf *str = &node->data.string_literal.buf; | |
| 837 | LLVMValueRef str_val = find_or_create_string(g, str, node->data.string_literal.c); | |
| 814 | 838 | LLVMValueRef indices[] = { |
| 815 | 839 | LLVMConstInt(LLVMInt32Type(), 0, false), |
| 816 | 840 | LLVMConstInt(LLVMInt32Type(), 0, false) |
| ... | ... | @@ -864,6 +888,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 864 | 888 | case NodeTypeExternBlock: |
| 865 | 889 | case NodeTypeDirective: |
| 866 | 890 | case NodeTypeUse: |
| 891 | case NodeTypeStructDecl: | |
| 892 | case NodeTypeStructField: | |
| 867 | 893 | zig_unreachable(); |
| 868 | 894 | } |
| 869 | 895 | zig_unreachable(); |
| ... | ... | @@ -1072,7 +1098,7 @@ static void do_code_gen(CodeGen *g) { |
| 1072 | 1098 | #endif |
| 1073 | 1099 | } |
| 1074 | 1100 | |
| 1075 | static void define_primitive_types(CodeGen *g) { | |
| 1101 | static void define_builtin_types(CodeGen *g) { | |
| 1076 | 1102 | { |
| 1077 | 1103 | // if this type is anywhere in the AST, we should never hit codegen. |
| 1078 | 1104 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInvalid); |
| ... | ... | @@ -1103,7 +1129,7 @@ static void define_primitive_types(CodeGen *g) { |
| 1103 | 1129 | g->type_table.put(&entry->name, entry); |
| 1104 | 1130 | g->builtin_types.entry_u8 = entry; |
| 1105 | 1131 | } |
| 1106 | g->builtin_types.entry_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | |
| 1132 | g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | |
| 1107 | 1133 | { |
| 1108 | 1134 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); |
| 1109 | 1135 | entry->type_ref = LLVMInt32Type(); |
| ... | ... | @@ -1130,6 +1156,19 @@ static void define_primitive_types(CodeGen *g) { |
| 1130 | 1156 | g->type_table.put(&entry->name, entry); |
| 1131 | 1157 | g->builtin_types.entry_isize = entry; |
| 1132 | 1158 | } |
| 1159 | { | |
| 1160 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); | |
| 1161 | entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8); | |
| 1162 | buf_init_from_str(&entry->name, "usize"); | |
| 1163 | entry->size_in_bits = g->pointer_size_bytes * 8; | |
| 1164 | entry->align_in_bits = g->pointer_size_bytes * 8; | |
| 1165 | entry->data.integral.is_signed = false; | |
| 1166 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), | |
| 1167 | entry->size_in_bits, entry->align_in_bits, | |
| 1168 | LLVMZigEncoding_DW_ATE_unsigned()); | |
| 1169 | g->type_table.put(&entry->name, entry); | |
| 1170 | g->builtin_types.entry_usize = entry; | |
| 1171 | } | |
| 1133 | 1172 | { |
| 1134 | 1173 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); |
| 1135 | 1174 | entry->type_ref = LLVMFloatType(); |
| ... | ... | @@ -1160,6 +1199,43 @@ static void define_primitive_types(CodeGen *g) { |
| 1160 | 1199 | g->type_table.put(&entry->name, entry); |
| 1161 | 1200 | g->builtin_types.entry_unreachable = entry; |
| 1162 | 1201 | } |
| 1202 | { | |
| 1203 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); | |
| 1204 | ||
| 1205 | TypeTableEntry *const_pointer_to_u8 = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | |
| 1206 | ||
| 1207 | unsigned element_count = 2; | |
| 1208 | LLVMTypeRef element_types[] = { | |
| 1209 | const_pointer_to_u8->type_ref, | |
| 1210 | g->builtin_types.entry_usize->type_ref | |
| 1211 | }; | |
| 1212 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), "string"); | |
| 1213 | LLVMStructSetBody(entry->type_ref, element_types, element_count, false); | |
| 1214 | ||
| 1215 | buf_init_from_str(&entry->name, "string"); | |
| 1216 | entry->size_in_bits = g->pointer_size_bytes * 2 * 8; | |
| 1217 | entry->align_in_bits = g->pointer_size_bytes; | |
| 1218 | entry->data.structure.is_packed = false; | |
| 1219 | entry->data.structure.field_count = element_count; | |
| 1220 | entry->data.structure.fields = allocate<TypeStructField>(element_count); | |
| 1221 | entry->data.structure.fields[0].name = buf_create_from_str("ptr"); | |
| 1222 | entry->data.structure.fields[0].type_entry = const_pointer_to_u8; | |
| 1223 | entry->data.structure.fields[1].name = buf_create_from_str("len"); | |
| 1224 | entry->data.structure.fields[1].type_entry = g->builtin_types.entry_usize; | |
| 1225 | ||
| 1226 | LLVMZigDIType *di_element_types[] = { | |
| 1227 | const_pointer_to_u8->di_type, | |
| 1228 | g->builtin_types.entry_usize->di_type | |
| 1229 | }; | |
| 1230 | LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit); | |
| 1231 | LLVMZigDIFile *difile = nullptr; // TODO make sure this ok | |
| 1232 | entry->di_type = LLVMZigCreateDebugStructType(g->dbuilder, compile_unit_scope, | |
| 1233 | "string", difile, 0, entry->size_in_bits, entry->align_in_bits, 0, | |
| 1234 | nullptr, di_element_types, element_count, 0, nullptr, ""); | |
| 1235 | ||
| 1236 | g->type_table.put(&entry->name, entry); | |
| 1237 | g->builtin_types.entry_string = entry; | |
| 1238 | } | |
| 1163 | 1239 | } |
| 1164 | 1240 | |
| 1165 | 1241 | |
| ... | ... | @@ -1213,8 +1289,6 @@ static void init(CodeGen *g, Buf *source_path) { |
| 1213 | 1289 | LLVMZigSetFastMath(g->builder, true); |
| 1214 | 1290 | |
| 1215 | 1291 | |
| 1216 | define_primitive_types(g); | |
| 1217 | ||
| 1218 | 1292 | Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING); |
| 1219 | 1293 | bool is_optimized = g->build_type == CodeGenBuildTypeRelease; |
| 1220 | 1294 | const char *flags = ""; |
| ... | ... | @@ -1224,6 +1298,7 @@ static void init(CodeGen *g, Buf *source_path) { |
| 1224 | 1298 | buf_ptr(producer), is_optimized, flags, runtime_version, |
| 1225 | 1299 | "", 0, !g->strip_debug_symbols); |
| 1226 | 1300 | |
| 1301 | define_builtin_types(g); | |
| 1227 | 1302 | |
| 1228 | 1303 | } |
| 1229 | 1304 |
src/parser.cpp+126-30| ... | ... | @@ -106,6 +106,12 @@ const char *node_type_str(NodeType node_type) { |
| 106 | 106 | return "Label"; |
| 107 | 107 | case NodeTypeAsmExpr: |
| 108 | 108 | return "AsmExpr"; |
| 109 | case NodeTypeFieldAccessExpr: | |
| 110 | return "FieldAccessExpr"; | |
| 111 | case NodeTypeStructDecl: | |
| 112 | return "StructDecl"; | |
| 113 | case NodeTypeStructField: | |
| 114 | return "StructField"; | |
| 109 | 115 | } |
| 110 | 116 | zig_unreachable(); |
| 111 | 117 | } |
| ... | ... | @@ -259,9 +265,12 @@ void ast_print(AstNode *node, int indent) { |
| 259 | 265 | buf_ptr(&node->data.number)); |
| 260 | 266 | break; |
| 261 | 267 | case NodeTypeStringLiteral: |
| 262 | fprintf(stderr, "StringLiteral '%s'\n", | |
| 263 | buf_ptr(&node->data.string)); | |
| 264 | break; | |
| 268 | { | |
| 269 | const char *c = node->data.string_literal.c ? "c" : ""; | |
| 270 | fprintf(stderr, "StringLiteral %s'%s'\n", c, | |
| 271 | buf_ptr(&node->data.string_literal.buf)); | |
| 272 | break; | |
| 273 | } | |
| 265 | 274 | case NodeTypeUnreachable: |
| 266 | 275 | fprintf(stderr, "Unreachable\n"); |
| 267 | 276 | break; |
| ... | ... | @@ -295,6 +304,19 @@ void ast_print(AstNode *node, int indent) { |
| 295 | 304 | case NodeTypeAsmExpr: |
| 296 | 305 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 297 | 306 | break; |
| 307 | case NodeTypeFieldAccessExpr: | |
| 308 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), | |
| 309 | buf_ptr(&node->data.field_access_expr.field_name)); | |
| 310 | ast_print(node->data.field_access_expr.struct_expr, indent + 2); | |
| 311 | break; | |
| 312 | case NodeTypeStructDecl: | |
| 313 | fprintf(stderr, "%s '%s'\n", | |
| 314 | node_type_str(node->type), buf_ptr(&node->data.struct_decl.name)); | |
| 315 | break; | |
| 316 | case NodeTypeStructField: | |
| 317 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_field.name)); | |
| 318 | ast_print(node->data.struct_field.type, indent + 2); | |
| 319 | break; | |
| 298 | 320 | } |
| 299 | 321 | } |
| 300 | 322 | |
| ... | ... | @@ -475,18 +497,28 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) { |
| 475 | 497 | } |
| 476 | 498 | } |
| 477 | 499 | |
| 478 | static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, ZigList<SrcPos> *offset_map) { | |
| 500 | static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str, | |
| 501 | ZigList<SrcPos> *offset_map) | |
| 502 | { | |
| 479 | 503 | // skip the double quotes at beginning and end |
| 480 | 504 | // convert escape sequences |
| 505 | // detect c string literal | |
| 481 | 506 | |
| 482 | 507 | buf_resize(buf, 0); |
| 483 | 508 | bool escape = false; |
| 484 | bool first = true; | |
| 509 | bool skip_quote; | |
| 485 | 510 | SrcPos pos = {token->start_line, token->start_column}; |
| 486 | 511 | for (int i = token->start_pos; i < token->end_pos - 1; i += 1) { |
| 487 | 512 | uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i); |
| 488 | if (first) { | |
| 489 | first = false; | |
| 513 | if (i == token->start_pos) { | |
| 514 | skip_quote = (c == 'c'); | |
| 515 | if (out_c_str) { | |
| 516 | *out_c_str = skip_quote; | |
| 517 | } else if (skip_quote) { | |
| 518 | ast_error(pc, token, "C string literal not allowed here"); | |
| 519 | } | |
| 520 | } else if (skip_quote) { | |
| 521 | skip_quote = false; | |
| 490 | 522 | } else { |
| 491 | 523 | if (escape) { |
| 492 | 524 | switch (c) { |
| ... | ... | @@ -541,13 +573,20 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma |
| 541 | 573 | static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory); |
| 542 | 574 | static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory); |
| 543 | 575 | |
| 544 | ||
| 545 | 576 | static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { |
| 546 | 577 | if (token->id != token_id) { |
| 547 | 578 | ast_invalid_token_error(pc, token); |
| 548 | 579 | } |
| 549 | 580 | } |
| 550 | 581 | |
| 582 | static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id) { | |
| 583 | Token *token = &pc->tokens->at(*token_index); | |
| 584 | ast_expect_token(pc, token, token_id); | |
| 585 | *token_index += 1; | |
| 586 | return token; | |
| 587 | } | |
| 588 | ||
| 589 | ||
| 551 | 590 | static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_token_index) { |
| 552 | 591 | Token *number_sign = &pc->tokens->at(token_index); |
| 553 | 592 | token_index += 1; |
| ... | ... | @@ -569,7 +608,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_ |
| 569 | 608 | token_index += 1; |
| 570 | 609 | ast_expect_token(pc, param_str, TokenIdStringLiteral); |
| 571 | 610 | |
| 572 | parse_string_literal(pc, param_str, &node->data.directive.param, nullptr); | |
| 611 | parse_string_literal(pc, param_str, &node->data.directive.param, nullptr, nullptr); | |
| 573 | 612 | |
| 574 | 613 | Token *r_paren = &pc->tokens->at(token_index); |
| 575 | 614 | token_index += 1; |
| ... | ... | @@ -782,7 +821,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 782 | 821 | return node; |
| 783 | 822 | } else if (token->id == TokenIdStringLiteral) { |
| 784 | 823 | AstNode *node = ast_create_node(pc, NodeTypeStringLiteral, token); |
| 785 | parse_string_literal(pc, token, &node->data.string, nullptr); | |
| 824 | parse_string_literal(pc, token, &node->data.string_literal.buf, &node->data.string_literal.c, nullptr); | |
| 786 | 825 | *token_index += 1; |
| 787 | 826 | return node; |
| 788 | 827 | } else if (token->id == TokenIdKeywordUnreachable) { |
| ... | ... | @@ -832,9 +871,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 832 | 871 | } |
| 833 | 872 | |
| 834 | 873 | /* |
| 835 | SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression) | |
| 874 | SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression) | |
| 836 | 875 | FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) |
| 837 | 876 | ArrayAccessExpression : token(LBracket) Expression token(RBracket) |
| 877 | FieldAccessExpression : token(Dot) token(Symbol) | |
| 838 | 878 | */ |
| 839 | 879 | static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 840 | 880 | AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); |
| ... | ... | @@ -861,6 +901,16 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo |
| 861 | 901 | *token_index += 1; |
| 862 | 902 | ast_expect_token(pc, r_bracket, TokenIdRBracket); |
| 863 | 903 | |
| 904 | return node; | |
| 905 | } else if (token->id == TokenIdDot) { | |
| 906 | *token_index += 1; | |
| 907 | ||
| 908 | Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol); | |
| 909 | ||
| 910 | AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, token); | |
| 911 | node->data.field_access_expr.struct_expr = primary_expr; | |
| 912 | ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name); | |
| 913 | ||
| 864 | 914 | return node; |
| 865 | 915 | } else { |
| 866 | 916 | return primary_expr; |
| ... | ... | @@ -1397,14 +1447,6 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand |
| 1397 | 1447 | return node; |
| 1398 | 1448 | } |
| 1399 | 1449 | |
| 1400 | static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id) { | |
| 1401 | Token *token = &pc->tokens->at(*token_index); | |
| 1402 | ast_expect_token(pc, token, token_id); | |
| 1403 | *token_index += 1; | |
| 1404 | return token; | |
| 1405 | } | |
| 1406 | ||
| 1407 | ||
| 1408 | 1450 | /* |
| 1409 | 1451 | AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen) |
| 1410 | 1452 | */ |
| ... | ... | @@ -1421,7 +1463,7 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode |
| 1421 | 1463 | |
| 1422 | 1464 | AsmInput *asm_input = allocate<AsmInput>(1); |
| 1423 | 1465 | ast_buf_from_token(pc, alias, &asm_input->asm_symbolic_name); |
| 1424 | parse_string_literal(pc, constraint, &asm_input->constraint, nullptr); | |
| 1466 | parse_string_literal(pc, constraint, &asm_input->constraint, nullptr, nullptr); | |
| 1425 | 1467 | asm_input->expr = expr_node; |
| 1426 | 1468 | node->data.asm_expr.input_list.append(asm_input); |
| 1427 | 1469 | } |
| ... | ... | @@ -1442,7 +1484,7 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod |
| 1442 | 1484 | |
| 1443 | 1485 | AsmOutput *asm_output = allocate<AsmOutput>(1); |
| 1444 | 1486 | ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name); |
| 1445 | parse_string_literal(pc, constraint, &asm_output->constraint, nullptr); | |
| 1487 | parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr); | |
| 1446 | 1488 | ast_buf_from_token(pc, out_symbol, &asm_output->variable_name); |
| 1447 | 1489 | node->data.asm_expr.output_list.append(asm_output); |
| 1448 | 1490 | } |
| ... | ... | @@ -1464,7 +1506,7 @@ static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode * |
| 1464 | 1506 | *token_index += 1; |
| 1465 | 1507 | |
| 1466 | 1508 | Buf *clobber_buf = buf_alloc(); |
| 1467 | parse_string_literal(pc, string_tok, clobber_buf, nullptr); | |
| 1509 | parse_string_literal(pc, string_tok, clobber_buf, nullptr, nullptr); | |
| 1468 | 1510 | node->data.asm_expr.clobber_list.append(clobber_buf); |
| 1469 | 1511 | |
| 1470 | 1512 | Token *comma = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1565,7 +1607,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand |
| 1565 | 1607 | ast_expect_token(pc, template_tok, TokenIdStringLiteral); |
| 1566 | 1608 | *token_index += 1; |
| 1567 | 1609 | |
| 1568 | parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template, | |
| 1610 | parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template, nullptr, | |
| 1569 | 1611 | &node->data.asm_expr.offset_map); |
| 1570 | 1612 | parse_asm_template(pc, node); |
| 1571 | 1613 | |
| ... | ... | @@ -1877,7 +1919,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b |
| 1877 | 1919 | *token_index += 1; |
| 1878 | 1920 | ast_expect_token(pc, export_name, TokenIdStringLiteral); |
| 1879 | 1921 | |
| 1880 | parse_string_literal(pc, export_name, &node->data.root_export_decl.name, nullptr); | |
| 1922 | parse_string_literal(pc, export_name, &node->data.root_export_decl.name, nullptr, nullptr); | |
| 1881 | 1923 | |
| 1882 | 1924 | Token *semicolon = &pc->tokens->at(*token_index); |
| 1883 | 1925 | *token_index += 1; |
| ... | ... | @@ -1889,9 +1931,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b |
| 1889 | 1931 | /* |
| 1890 | 1932 | Use : many(Directive) token(Use) token(String) token(Semicolon) |
| 1891 | 1933 | */ |
| 1892 | static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory) { | |
| 1893 | assert(mandatory == false); | |
| 1894 | ||
| 1934 | static AstNode *ast_parse_use(ParseContext *pc, int *token_index) { | |
| 1895 | 1935 | Token *use_kw = &pc->tokens->at(*token_index); |
| 1896 | 1936 | if (use_kw->id != TokenIdKeywordUse) |
| 1897 | 1937 | return nullptr; |
| ... | ... | @@ -1907,7 +1947,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory |
| 1907 | 1947 | |
| 1908 | 1948 | AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw); |
| 1909 | 1949 | |
| 1910 | parse_string_literal(pc, use_name, &node->data.use.path, nullptr); | |
| 1950 | parse_string_literal(pc, use_name, &node->data.use.path, nullptr, nullptr); | |
| 1911 | 1951 | |
| 1912 | 1952 | node->data.use.directives = pc->directive_list; |
| 1913 | 1953 | pc->directive_list = nullptr; |
| ... | ... | @@ -1916,7 +1956,57 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory |
| 1916 | 1956 | } |
| 1917 | 1957 | |
| 1918 | 1958 | /* |
| 1919 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | |
| 1959 | StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace) | |
| 1960 | StructField : token(Symbol) token(Colon) Type token(Comma) | |
| 1961 | */ | |
| 1962 | static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { | |
| 1963 | Token *struct_kw = &pc->tokens->at(*token_index); | |
| 1964 | if (struct_kw->id != TokenIdKeywordStruct) | |
| 1965 | return nullptr; | |
| 1966 | *token_index += 1; | |
| 1967 | ||
| 1968 | Token *struct_name = &pc->tokens->at(*token_index); | |
| 1969 | *token_index += 1; | |
| 1970 | ast_expect_token(pc, struct_name, TokenIdSymbol); | |
| 1971 | ||
| 1972 | AstNode *node = ast_create_node(pc, NodeTypeStructDecl, struct_kw); | |
| 1973 | ast_buf_from_token(pc, struct_name, &node->data.struct_decl.name); | |
| 1974 | ||
| 1975 | ast_eat_token(pc, token_index, TokenIdLBrace); | |
| 1976 | ||
| 1977 | for (;;) { | |
| 1978 | Token *token = &pc->tokens->at(*token_index); | |
| 1979 | ||
| 1980 | if (token->id == TokenIdRBrace) { | |
| 1981 | *token_index += 1; | |
| 1982 | break; | |
| 1983 | } else if (token->id == TokenIdSymbol) { | |
| 1984 | AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token); | |
| 1985 | *token_index += 1; | |
| 1986 | ||
| 1987 | ast_buf_from_token(pc, token, &field_node->data.struct_field.name); | |
| 1988 | ||
| 1989 | ast_eat_token(pc, token_index, TokenIdColon); | |
| 1990 | ||
| 1991 | field_node->data.struct_field.type = ast_parse_type(pc, *token_index, token_index); | |
| 1992 | ||
| 1993 | ast_eat_token(pc, token_index, TokenIdComma); | |
| 1994 | ||
| 1995 | node->data.struct_decl.fields.append(field_node); | |
| 1996 | } else { | |
| 1997 | ast_invalid_token_error(pc, token); | |
| 1998 | } | |
| 1999 | } | |
| 2000 | ||
| 2001 | ||
| 2002 | node->data.struct_decl.directives = pc->directive_list; | |
| 2003 | pc->directive_list = nullptr; | |
| 2004 | ||
| 2005 | return node; | |
| 2006 | } | |
| 2007 | ||
| 2008 | /* | |
| 2009 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | |
| 1920 | 2010 | */ |
| 1921 | 2011 | static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) { |
| 1922 | 2012 | for (;;) { |
| ... | ... | @@ -1943,12 +2033,18 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis |
| 1943 | 2033 | continue; |
| 1944 | 2034 | } |
| 1945 | 2035 | |
| 1946 | AstNode *use_node = ast_parse_use(pc, token_index, false); | |
| 2036 | AstNode *use_node = ast_parse_use(pc, token_index); | |
| 1947 | 2037 | if (use_node) { |
| 1948 | 2038 | top_level_decls->append(use_node); |
| 1949 | 2039 | continue; |
| 1950 | 2040 | } |
| 1951 | 2041 | |
| 2042 | AstNode *struct_node = ast_parse_struct_decl(pc, token_index); | |
| 2043 | if (struct_node) { | |
| 2044 | top_level_decls->append(struct_node); | |
| 2045 | continue; | |
| 2046 | } | |
| 2047 | ||
| 1952 | 2048 | if (pc->directive_list->length > 0) { |
| 1953 | 2049 | ast_error(pc, directive_token, "invalid directive"); |
| 1954 | 2050 | } |
src/parser.hpp+28-1| ... | ... | @@ -40,6 +40,7 @@ enum NodeType { |
| 40 | 40 | NodeTypePrefixOpExpr, |
| 41 | 41 | NodeTypeFnCallExpr, |
| 42 | 42 | NodeTypeArrayAccessExpr, |
| 43 | NodeTypeFieldAccessExpr, | |
| 43 | 44 | NodeTypeUse, |
| 44 | 45 | NodeTypeVoid, |
| 45 | 46 | NodeTypeBoolLiteral, |
| ... | ... | @@ -47,6 +48,8 @@ enum NodeType { |
| 47 | 48 | NodeTypeLabel, |
| 48 | 49 | NodeTypeGoto, |
| 49 | 50 | NodeTypeAsmExpr, |
| 51 | NodeTypeStructDecl, | |
| 52 | NodeTypeStructField, | |
| 50 | 53 | }; |
| 51 | 54 | |
| 52 | 55 | struct AstNodeRoot { |
| ... | ... | @@ -152,6 +155,11 @@ struct AstNodeArrayAccessExpr { |
| 152 | 155 | AstNode *subscript; |
| 153 | 156 | }; |
| 154 | 157 | |
| 158 | struct AstNodeFieldAccessExpr { | |
| 159 | AstNode *struct_expr; | |
| 160 | Buf field_name; | |
| 161 | }; | |
| 162 | ||
| 155 | 163 | struct AstNodeExternBlock { |
| 156 | 164 | ZigList<AstNode *> *directives; |
| 157 | 165 | ZigList<AstNode *> fn_decls; |
| ... | ... | @@ -231,6 +239,22 @@ struct AstNodeAsmExpr { |
| 231 | 239 | ZigList<Buf*> clobber_list; |
| 232 | 240 | }; |
| 233 | 241 | |
| 242 | struct AstNodeStructDecl { | |
| 243 | Buf name; | |
| 244 | ZigList<AstNode *> fields; | |
| 245 | ZigList<AstNode *> *directives; | |
| 246 | }; | |
| 247 | ||
| 248 | struct AstNodeStructField { | |
| 249 | Buf name; | |
| 250 | AstNode *type; | |
| 251 | }; | |
| 252 | ||
| 253 | struct AstNodeStringLiteral { | |
| 254 | Buf buf; | |
| 255 | bool c; | |
| 256 | }; | |
| 257 | ||
| 234 | 258 | struct AstNode { |
| 235 | 259 | enum NodeType type; |
| 236 | 260 | int line; |
| ... | ... | @@ -260,8 +284,11 @@ struct AstNode { |
| 260 | 284 | AstNodeLabel label; |
| 261 | 285 | AstNodeGoto go_to; |
| 262 | 286 | AstNodeAsmExpr asm_expr; |
| 287 | AstNodeFieldAccessExpr field_access_expr; | |
| 288 | AstNodeStructDecl struct_decl; | |
| 289 | AstNodeStructField struct_field; | |
| 290 | AstNodeStringLiteral string_literal; | |
| 263 | 291 | Buf number; |
| 264 | Buf string; | |
| 265 | 292 | Buf symbol; |
| 266 | 293 | bool bool_literal; |
| 267 | 294 | } data; |
src/tokenizer.cpp+31-3| ... | ... | @@ -28,10 +28,9 @@ |
| 28 | 28 | case '8': \ |
| 29 | 29 | case '9' |
| 30 | 30 | |
| 31 | #define ALPHA \ | |
| 31 | #define ALPHA_EXCEPT_C \ | |
| 32 | 32 | 'a': \ |
| 33 | 33 | case 'b': \ |
| 34 | case 'c': \ | |
| 35 | 34 | case 'd': \ |
| 36 | 35 | case 'e': \ |
| 37 | 36 | case 'f': \ |
| ... | ... | @@ -82,6 +81,10 @@ |
| 82 | 81 | case 'Y': \ |
| 83 | 82 | case 'Z' |
| 84 | 83 | |
| 84 | #define ALPHA \ | |
| 85 | ALPHA_EXCEPT_C: \ | |
| 86 | case 'c' | |
| 87 | ||
| 85 | 88 | #define SYMBOL_CHAR \ |
| 86 | 89 | ALPHA: \ |
| 87 | 90 | case DIGIT: \ |
| ... | ... | @@ -90,6 +93,7 @@ |
| 90 | 93 | enum TokenizeState { |
| 91 | 94 | TokenizeStateStart, |
| 92 | 95 | TokenizeStateSymbol, |
| 96 | TokenizeStateSymbolFirst, | |
| 93 | 97 | TokenizeStateNumber, |
| 94 | 98 | TokenizeStateString, |
| 95 | 99 | TokenizeStateSawDash, |
| ... | ... | @@ -201,6 +205,8 @@ static void end_token(Tokenize *t) { |
| 201 | 205 | t->cur_tok->id = TokenIdKeywordVolatile; |
| 202 | 206 | } else if (mem_eql_str(token_mem, token_len, "asm")) { |
| 203 | 207 | t->cur_tok->id = TokenIdKeywordAsm; |
| 208 | } else if (mem_eql_str(token_mem, token_len, "struct")) { | |
| 209 | t->cur_tok->id = TokenIdKeywordStruct; | |
| 204 | 210 | } |
| 205 | 211 | |
| 206 | 212 | t->cur_tok = nullptr; |
| ... | ... | @@ -224,7 +230,11 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 224 | 230 | switch (c) { |
| 225 | 231 | case WHITESPACE: |
| 226 | 232 | break; |
| 227 | case ALPHA: | |
| 233 | case 'c': | |
| 234 | t.state = TokenizeStateSymbolFirst; | |
| 235 | begin_token(&t, TokenIdSymbol); | |
| 236 | break; | |
| 237 | case ALPHA_EXCEPT_C: | |
| 228 | 238 | case '_': |
| 229 | 239 | t.state = TokenizeStateSymbol; |
| 230 | 240 | begin_token(&t, TokenIdSymbol); |
| ... | ... | @@ -526,6 +536,22 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 526 | 536 | break; |
| 527 | 537 | } |
| 528 | 538 | break; |
| 539 | case TokenizeStateSymbolFirst: | |
| 540 | switch (c) { | |
| 541 | case '"': | |
| 542 | t.cur_tok->id = TokenIdStringLiteral; | |
| 543 | t.state = TokenizeStateString; | |
| 544 | break; | |
| 545 | case SYMBOL_CHAR: | |
| 546 | t.state = TokenizeStateSymbol; | |
| 547 | break; | |
| 548 | default: | |
| 549 | t.pos -= 1; | |
| 550 | end_token(&t); | |
| 551 | t.state = TokenizeStateStart; | |
| 552 | continue; | |
| 553 | } | |
| 554 | break; | |
| 529 | 555 | case TokenizeStateSymbol: |
| 530 | 556 | switch (c) { |
| 531 | 557 | case SYMBOL_CHAR: |
| ... | ... | @@ -589,6 +615,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 589 | 615 | tokenize_error(&t, "unterminated string"); |
| 590 | 616 | break; |
| 591 | 617 | case TokenizeStateSymbol: |
| 618 | case TokenizeStateSymbolFirst: | |
| 592 | 619 | case TokenizeStateNumber: |
| 593 | 620 | case TokenizeStateSawDash: |
| 594 | 621 | case TokenizeStatePipe: |
| ... | ... | @@ -643,6 +670,7 @@ static const char * token_name(Token *token) { |
| 643 | 670 | case TokenIdKeywordGoto: return "Goto"; |
| 644 | 671 | case TokenIdKeywordVolatile: return "Volatile"; |
| 645 | 672 | case TokenIdKeywordAsm: return "Asm"; |
| 673 | case TokenIdKeywordStruct: return "Struct"; | |
| 646 | 674 | case TokenIdLParen: return "LParen"; |
| 647 | 675 | case TokenIdRParen: return "RParen"; |
| 648 | 676 | case TokenIdComma: return "Comma"; |
src/tokenizer.hpp+1| ... | ... | @@ -32,6 +32,7 @@ enum TokenId { |
| 32 | 32 | TokenIdKeywordGoto, |
| 33 | 33 | TokenIdKeywordAsm, |
| 34 | 34 | TokenIdKeywordVolatile, |
| 35 | TokenIdKeywordStruct, | |
| 35 | 36 | TokenIdLParen, |
| 36 | 37 | TokenIdRParen, |
| 37 | 38 | TokenIdComma, |
src/zig_llvm.cpp+25| ... | ... | @@ -161,6 +161,31 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder, uint64_t |
| 161 | 161 | return reinterpret_cast<LLVMZigDIType*>(di_type); |
| 162 | 162 | } |
| 163 | 163 | |
| 164 | ||
| 165 | LLVMZigDIType *LLVMZigCreateDebugStructType(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope, | |
| 166 | const char *name, LLVMZigDIFile *file, unsigned line_number, uint64_t size_in_bits, | |
| 167 | uint64_t align_in_bits, unsigned flags, LLVMZigDIType *derived_from, | |
| 168 | LLVMZigDIType **types_array, int types_array_len, unsigned run_time_lang, LLVMZigDIType *vtable_holder, | |
| 169 | const char *unique_id) | |
| 170 | { | |
| 171 | SmallVector<Metadata *, 8> fields; | |
| 172 | for (int i = 0; i < types_array_len; i += 1) { | |
| 173 | DIType *ditype = reinterpret_cast<DIType*>(types_array[i]); | |
| 174 | fields.push_back(ditype); | |
| 175 | } | |
| 176 | DIType *di_type = reinterpret_cast<DIBuilder*>(dibuilder)->createStructType( | |
| 177 | reinterpret_cast<DIScope*>(scope), | |
| 178 | name, | |
| 179 | reinterpret_cast<DIFile*>(file), | |
| 180 | line_number, size_in_bits, align_in_bits, flags, | |
| 181 | reinterpret_cast<DIType*>(derived_from), | |
| 182 | reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateArray(fields), | |
| 183 | run_time_lang, | |
| 184 | reinterpret_cast<DIType*>(vtable_holder), | |
| 185 | unique_id); | |
| 186 | return reinterpret_cast<LLVMZigDIType*>(di_type); | |
| 187 | } | |
| 188 | ||
| 164 | 189 | LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped, |
| 165 | 190 | LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags) |
| 166 | 191 | { |
src/zig_llvm.hpp+5| ... | ... | @@ -49,6 +49,11 @@ LLVMZigDIType *LLVMZigCreateDebugArrayType(LLVMZigDIBuilder *dibuilder, |
| 49 | 49 | uint64_t size_in_bits, uint64_t align_in_bits, LLVMZigDIType *elem_type, |
| 50 | 50 | int elem_count); |
| 51 | 51 | |
| 52 | LLVMZigDIType *LLVMZigCreateDebugStructType(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope, | |
| 53 | const char *name, LLVMZigDIFile *file, unsigned line_number, uint64_t size_in_bits, | |
| 54 | uint64_t align_in_bits, unsigned flags, LLVMZigDIType *derived_from, | |
| 55 | LLVMZigDIType **types_array, int types_array_len, unsigned run_time_lang, LLVMZigDIType *vtable_holder, | |
| 56 | const char *unique_id); | |
| 52 | 57 | |
| 53 | 58 | LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped, |
| 54 | 59 | LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags); |
std/std.zig+5-2| ... | ... | @@ -17,8 +17,11 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize { |
| 17 | 17 | // TODO zig strings instead of C strings |
| 18 | 18 | // TODO handle buffering and flushing |
| 19 | 19 | // TODO non-i32 integer literals so we can remove the casts |
| 20 | pub fn print_str(str : *const u8, len: isize) { | |
| 20 | // TODO constants for SYS_write and stdout_fileno | |
| 21 | //pub fn print_str(str : string) -> isize { | |
| 22 | pub fn print_str(str : *const u8, len: isize) -> isize { | |
| 21 | 23 | let SYS_write = 1; |
| 22 | 24 | let stdout_fileno = 1; |
| 23 | syscall3(SYS_write as isize, stdout_fileno as isize, str as isize, len); | |
| 25 | //return syscall3(SYS_write as isize, stdout_fileno as isize, str.ptr as isize, str.len as isize); | |
| 26 | return syscall3(SYS_write as isize, stdout_fileno as isize, str as isize, len); | |
| 24 | 27 | } |
test/run_tests.cpp+30-30| ... | ... | @@ -104,7 +104,7 @@ static void add_compiling_test_cases(void) { |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | 106 | export fn _start() -> unreachable { |
| 107 | puts("Hello, world!"); | |
| 107 | puts(c"Hello, world!"); | |
| 108 | 108 | exit(0); |
| 109 | 109 | } |
| 110 | 110 | )SOURCE", "Hello, world!\n"); |
| ... | ... | @@ -126,7 +126,7 @@ static void add_compiling_test_cases(void) { |
| 126 | 126 | } |
| 127 | 127 | |
| 128 | 128 | fn this_is_a_function() -> unreachable { |
| 129 | puts("OK"); | |
| 129 | puts(c"OK"); | |
| 130 | 130 | exit(0); |
| 131 | 131 | } |
| 132 | 132 | )SOURCE", "OK\n"); |
| ... | ... | @@ -146,7 +146,7 @@ static void add_compiling_test_cases(void) { |
| 146 | 146 | /// this is a documentation comment |
| 147 | 147 | /// doc comment line 2 |
| 148 | 148 | export fn _start() -> unreachable { |
| 149 | puts(/* mid-line comment /* nested */ */ "OK"); | |
| 149 | puts(/* mid-line comment /* nested */ */ c"OK"); | |
| 150 | 150 | exit(0); |
| 151 | 151 | } |
| 152 | 152 | )SOURCE", "OK\n"); |
| ... | ... | @@ -180,7 +180,7 @@ static void add_compiling_test_cases(void) { |
| 180 | 180 | // purposefully conflicting function with main source file |
| 181 | 181 | // but it's private so it should be OK |
| 182 | 182 | fn private_function() { |
| 183 | puts("OK"); | |
| 183 | puts(c"OK"); | |
| 184 | 184 | } |
| 185 | 185 | |
| 186 | 186 | pub fn print_text() { |
| ... | ... | @@ -198,17 +198,17 @@ static void add_compiling_test_cases(void) { |
| 198 | 198 | |
| 199 | 199 | export fn _start() -> unreachable { |
| 200 | 200 | if 1 != 0 { |
| 201 | puts("1 is true"); | |
| 201 | puts(c"1 is true"); | |
| 202 | 202 | } else { |
| 203 | puts("1 is false"); | |
| 203 | puts(c"1 is false"); | |
| 204 | 204 | } |
| 205 | 205 | if 0 != 0 { |
| 206 | puts("0 is true"); | |
| 206 | puts(c"0 is true"); | |
| 207 | 207 | } else if 1 - 1 != 0 { |
| 208 | puts("1 - 1 is true"); | |
| 208 | puts(c"1 - 1 is true"); | |
| 209 | 209 | } |
| 210 | 210 | if !(0 != 0) { |
| 211 | puts("!0 is true"); | |
| 211 | puts(c"!0 is true"); | |
| 212 | 212 | } |
| 213 | 213 | exit(0); |
| 214 | 214 | } |
| ... | ... | @@ -227,7 +227,7 @@ static void add_compiling_test_cases(void) { |
| 227 | 227 | |
| 228 | 228 | export fn _start() -> unreachable { |
| 229 | 229 | if add(22, 11) == 33 { |
| 230 | puts("pass"); | |
| 230 | puts(c"pass"); | |
| 231 | 231 | } |
| 232 | 232 | exit(0); |
| 233 | 233 | } |
| ... | ... | @@ -244,7 +244,7 @@ static void add_compiling_test_cases(void) { |
| 244 | 244 | if a == 0 { |
| 245 | 245 | goto done; |
| 246 | 246 | } |
| 247 | puts("loop"); | |
| 247 | puts(c"loop"); | |
| 248 | 248 | loop(a - 1); |
| 249 | 249 | |
| 250 | 250 | done: |
| ... | ... | @@ -268,7 +268,7 @@ export fn _start() -> unreachable { |
| 268 | 268 | let a : i32 = 1; |
| 269 | 269 | let b = 2; |
| 270 | 270 | if (a + b == 3) { |
| 271 | puts("OK"); | |
| 271 | puts(c"OK"); | |
| 272 | 272 | } |
| 273 | 273 | exit(0); |
| 274 | 274 | } |
| ... | ... | @@ -282,10 +282,10 @@ extern { |
| 282 | 282 | } |
| 283 | 283 | |
| 284 | 284 | export fn _start() -> unreachable { |
| 285 | if (true) { puts("OK 1"); } | |
| 286 | if (false) { puts("BAD 1"); } | |
| 287 | if (!true) { puts("BAD 2"); } | |
| 288 | if (!false) { puts("OK 2"); } | |
| 285 | if (true) { puts(c"OK 1"); } | |
| 286 | if (false) { puts(c"BAD 1"); } | |
| 287 | if (!true) { puts(c"BAD 2"); } | |
| 288 | if (!false) { puts(c"OK 2"); } | |
| 289 | 289 | exit(0); |
| 290 | 290 | } |
| 291 | 291 | )SOURCE", "OK 1\nOK 2\n"); |
| ... | ... | @@ -300,14 +300,14 @@ extern { |
| 300 | 300 | export fn _start() -> unreachable { |
| 301 | 301 | if (true) { |
| 302 | 302 | let no_conflict = 5; |
| 303 | if (no_conflict == 5) { puts("OK 1"); } | |
| 303 | if (no_conflict == 5) { puts(c"OK 1"); } | |
| 304 | 304 | } |
| 305 | 305 | |
| 306 | 306 | let c = { |
| 307 | 307 | let no_conflict = 10; |
| 308 | 308 | no_conflict |
| 309 | 309 | }; |
| 310 | if (c == 10) { puts("OK 2"); } | |
| 310 | if (c == 10) { puts(c"OK 2"); } | |
| 311 | 311 | exit(0); |
| 312 | 312 | } |
| 313 | 313 | )SOURCE", "OK 1\nOK 2\n"); |
| ... | ... | @@ -327,7 +327,7 @@ export fn _start() -> unreachable { |
| 327 | 327 | fn void_fun(a : i32, b : void, c : i32) { |
| 328 | 328 | let v = b; |
| 329 | 329 | let vv : void = if (a == 1) {v} else {}; |
| 330 | if (a + c == 3) { puts("OK"); } | |
| 330 | if (a + c == 3) { puts(c"OK"); } | |
| 331 | 331 | return vv; |
| 332 | 332 | } |
| 333 | 333 | )SOURCE", "OK\n"); |
| ... | ... | @@ -341,14 +341,14 @@ extern { |
| 341 | 341 | |
| 342 | 342 | export fn _start() -> unreachable { |
| 343 | 343 | let mut zero : i32; |
| 344 | if (zero == 0) { puts("zero"); } | |
| 344 | if (zero == 0) { puts(c"zero"); } | |
| 345 | 345 | |
| 346 | 346 | let mut i = 0; |
| 347 | 347 | loop_start: |
| 348 | 348 | if i == 3 { |
| 349 | 349 | goto done; |
| 350 | 350 | } |
| 351 | puts("loop"); | |
| 351 | puts(c"loop"); | |
| 352 | 352 | i = i + 1; |
| 353 | 353 | goto loop_start; |
| 354 | 354 | done: |
| ... | ... | @@ -391,7 +391,7 @@ loop_2_start: |
| 391 | 391 | loop_2_end: |
| 392 | 392 | |
| 393 | 393 | if accumulator == 15 { |
| 394 | puts("OK"); | |
| 394 | puts(c"OK"); | |
| 395 | 395 | } |
| 396 | 396 | |
| 397 | 397 | exit(0); |
| ... | ... | @@ -403,7 +403,7 @@ loop_2_end: |
| 403 | 403 | use "std.zig"; |
| 404 | 404 | |
| 405 | 405 | export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 { |
| 406 | print_str("Hello, world!\n", 14 as isize); | |
| 406 | print_str(c"Hello, world!\n", 14 as isize); | |
| 407 | 407 | return 0; |
| 408 | 408 | } |
| 409 | 409 | )SOURCE", "Hello, world!\n"); |
| ... | ... | @@ -430,11 +430,11 @@ fn a() {} |
| 430 | 430 | |
| 431 | 431 | add_compile_fail_case("unreachable with return", R"SOURCE( |
| 432 | 432 | fn a() -> unreachable {return;} |
| 433 | )SOURCE", 1, ".tmp_source.zig:2:24: error: type mismatch. expected unreachable. got void"); | |
| 433 | )SOURCE", 1, ".tmp_source.zig:2:24: error: expected type 'unreachable', got 'void'"); | |
| 434 | 434 | |
| 435 | 435 | add_compile_fail_case("control reaches end of non-void function", R"SOURCE( |
| 436 | 436 | fn a() -> i32 {} |
| 437 | )SOURCE", 1, ".tmp_source.zig:2:15: error: type mismatch. expected i32. got void"); | |
| 437 | )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got 'void'"); | |
| 438 | 438 | |
| 439 | 439 | add_compile_fail_case("undefined function call", R"SOURCE( |
| 440 | 440 | fn a() { |
| ... | ... | @@ -514,16 +514,16 @@ fn f(a : i32) { |
| 514 | 514 | |
| 515 | 515 | add_compile_fail_case("variable has wrong type", R"SOURCE( |
| 516 | 516 | fn f() -> i32 { |
| 517 | let a = "a"; | |
| 517 | let a = c"a"; | |
| 518 | 518 | a |
| 519 | 519 | } |
| 520 | )SOURCE", 1, ".tmp_source.zig:2:15: error: type mismatch. expected i32. got *const u8"); | |
| 520 | )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got '*const u8'"); | |
| 521 | 521 | |
| 522 | 522 | add_compile_fail_case("if condition is bool, not int", R"SOURCE( |
| 523 | 523 | fn f() { |
| 524 | 524 | if (0) {} |
| 525 | 525 | } |
| 526 | )SOURCE", 1, ".tmp_source.zig:3:9: error: type mismatch. expected bool. got i32"); | |
| 526 | )SOURCE", 1, ".tmp_source.zig:3:9: error: expected type 'bool', got 'i32'"); | |
| 527 | 527 | |
| 528 | 528 | add_compile_fail_case("assign unreachable", R"SOURCE( |
| 529 | 529 | fn f() { |
| ... | ... | @@ -551,11 +551,11 @@ a_label: |
| 551 | 551 | } |
| 552 | 552 | )SOURCE", 1, ".tmp_source.zig:3:1: error: label 'a_label' defined but not used"); |
| 553 | 553 | |
| 554 | add_compile_fail_case("expected bare identifier", R"SOURCE( | |
| 554 | add_compile_fail_case("bad assignment target", R"SOURCE( | |
| 555 | 555 | fn f() { |
| 556 | 556 | 3 = 3; |
| 557 | 557 | } |
| 558 | )SOURCE", 1, ".tmp_source.zig:3:5: error: expected a bare identifier"); | |
| 558 | )SOURCE", 1, ".tmp_source.zig:3:5: error: assignment target must be variable, field, or array element"); | |
| 559 | 559 | |
| 560 | 560 | add_compile_fail_case("assign to constant variable", R"SOURCE( |
| 561 | 561 | fn f() { |