| author | |
| committer | |
| log | 4184d4c66a26ba10fbc78cc21f2c73db8f0cfcb2 |
| tree | ce96a5cbe63f8bd86ab1cfeb3892e1fea44005d0 |
| parent | df12c1328eb9c2af006dfd9e5cf69046ad6fc235 |
| signature | Commit is signed but in an unrecognized format. |
2 files changed, 151 insertions(+), 31 deletions(-)
lib/std/c/ast.zig+36-16| ... | ... | @@ -48,9 +48,12 @@ pub const Error = union(enum) { |
| 48 | 48 | ExpectedFnBody: SingleTokenError("expected function body, found '{}'"), |
| 49 | 49 | ExpectedDeclarator: SingleTokenError("expected declarator, found '{}'"), |
| 50 | 50 | ExpectedInitializer: SingleTokenError("expected initializer, found '{}'"), |
| 51 | ExpectedEnumField: SingleTokenError("expected enum field, found '{}'"), | |
| 52 | ExpectedType: SingleTokenError("expected enum field, found '{}'"), | |
| 51 | 53 | InvalidTypeSpecifier: InvalidTypeSpecifier, |
| 52 | 54 | DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"), |
| 53 | 55 | DuplicateSpecifier: SingleTokenError("duplicate declaration specifier '{}'"), |
| 56 | MustUseKwToRefer: MustUseKwToRefer, | |
| 54 | 57 | |
| 55 | 58 | pub fn render(self: *const Error, tree: *Tree, stream: var) !void { |
| 56 | 59 | switch (self.*) { |
| ... | ... | @@ -62,9 +65,12 @@ pub const Error = union(enum) { |
| 62 | 65 | .ExpectedDeclarator => |*x| return x.render(tree, stream), |
| 63 | 66 | .ExpectedFnBody => |*x| return x.render(tree, stream), |
| 64 | 67 | .ExpectedInitializer => |*x| return x.render(tree, stream), |
| 68 | .ExpectedEnumField => |*x| return x.render(tree, stream), | |
| 69 | .ExpectedType => |*x| return x.render(tree, stream), | |
| 65 | 70 | .InvalidTypeSpecifier => |*x| return x.render(tree, stream), |
| 66 | 71 | .DuplicateQualifier => |*x| return x.render(tree, stream), |
| 67 | 72 | .DuplicateSpecifier => |*x| return x.render(tree, stream), |
| 73 | .MustUseKwToRefer => |*x| return x.render(tree, stream), | |
| 68 | 74 | } |
| 69 | 75 | } |
| 70 | 76 | |
| ... | ... | @@ -78,9 +84,12 @@ pub const Error = union(enum) { |
| 78 | 84 | .ExpectedDeclarator => |x| return x.token, |
| 79 | 85 | .ExpectedFnBody => |x| return x.token, |
| 80 | 86 | .ExpectedInitializer => |x| return x.token, |
| 87 | .ExpectedEnumField => |x| return x.token, | |
| 88 | .ExpectedType => |*x| return x.token, | |
| 81 | 89 | .InvalidTypeSpecifier => |x| return x.token, |
| 82 | 90 | .DuplicateQualifier => |x| return x.token, |
| 83 | 91 | .DuplicateSpecifier => |x| return x.token, |
| 92 | .MustUseKwToRefer => |*x| return x.name, | |
| 84 | 93 | } |
| 85 | 94 | } |
| 86 | 95 | |
| ... | ... | @@ -111,6 +120,15 @@ pub const Error = union(enum) { |
| 111 | 120 | } |
| 112 | 121 | }; |
| 113 | 122 | |
| 123 | pub const MustUseKwToRefer = struct { | |
| 124 | kw: TokenIndex, | |
| 125 | name: TokenIndex, | |
| 126 | ||
| 127 | pub fn render(self: *const ExpectedToken, tree: *Tree, stream: var) !void { | |
| 128 | return stream.print("must use '{}' tag to refer to type '{}'", .{tree.slice(kw), tree.slice(name)}); | |
| 129 | } | |
| 130 | }; | |
| 131 | ||
| 114 | 132 | fn SingleTokenError(comptime msg: []const u8) type { |
| 115 | 133 | return struct { |
| 116 | 134 | token: TokenIndex, |
| ... | ... | @@ -125,14 +143,13 @@ pub const Error = union(enum) { |
| 125 | 143 | |
| 126 | 144 | pub const Type = struct { |
| 127 | 145 | pub const TypeList = std.SegmentedList(*Type, 4); |
| 128 | @"const": bool, | |
| 129 | atomic: bool, | |
| 130 | @"volatile": bool, | |
| 131 | restrict: bool, | |
| 146 | @"const": bool = false, | |
| 147 | atomic: bool = false, | |
| 148 | @"volatile": bool = false, | |
| 149 | restrict: bool = false, | |
| 132 | 150 | |
| 133 | 151 | id: union(enum) { |
| 134 | 152 | Int: struct { |
| 135 | quals: Qualifiers, | |
| 136 | 153 | id: Id, |
| 137 | 154 | is_signed: bool, |
| 138 | 155 | |
| ... | ... | @@ -145,7 +162,6 @@ pub const Type = struct { |
| 145 | 162 | }; |
| 146 | 163 | }, |
| 147 | 164 | Float: struct { |
| 148 | quals: Qualifiers, | |
| 149 | 165 | id: Id, |
| 150 | 166 | |
| 151 | 167 | pub const Id = enum { |
| ... | ... | @@ -154,10 +170,7 @@ pub const Type = struct { |
| 154 | 170 | LongDouble, |
| 155 | 171 | }; |
| 156 | 172 | }, |
| 157 | Pointer: struct { | |
| 158 | quals: Qualifiers, | |
| 159 | child_type: *Type, | |
| 160 | }, | |
| 173 | Pointer: *Type, | |
| 161 | 174 | Function: struct { |
| 162 | 175 | return_type: *Type, |
| 163 | 176 | param_types: TypeList, |
| ... | ... | @@ -173,6 +186,8 @@ pub const Node = struct { |
| 173 | 186 | |
| 174 | 187 | pub const Id = enum { |
| 175 | 188 | Root, |
| 189 | EnumField, | |
| 190 | RecordField, | |
| 176 | 191 | JumpStmt, |
| 177 | 192 | ExprStmt, |
| 178 | 193 | Label, |
| ... | ... | @@ -350,15 +365,16 @@ pub const Node = struct { |
| 350 | 365 | }; |
| 351 | 366 | |
| 352 | 367 | pub const EnumField = struct { |
| 353 | base: Node = Node{ .id = EnumField }, | |
| 368 | base: Node = Node{ .id = .EnumField }, | |
| 354 | 369 | name: TokenIndex, |
| 355 | 370 | value: ?*Node, |
| 356 | 371 | }; |
| 357 | 372 | |
| 358 | 373 | pub const RecordType = struct { |
| 359 | kind: union(enum) { | |
| 360 | Struct: TokenIndex, | |
| 361 | Union: TokenIndex, | |
| 374 | tok: TokenIndex, | |
| 375 | kind: enum { | |
| 376 | Struct, | |
| 377 | Union, | |
| 362 | 378 | }, |
| 363 | 379 | name: ?TokenIndex, |
| 364 | 380 | body: ?struct { |
| ... | ... | @@ -373,8 +389,12 @@ pub const Node = struct { |
| 373 | 389 | }; |
| 374 | 390 | |
| 375 | 391 | pub const RecordField = struct { |
| 376 | base: Node = Node{ .id = RecordField }, | |
| 377 | // TODO | |
| 392 | base: Node = Node{ .id = .RecordField }, | |
| 393 | type_spec: TypeSpec, | |
| 394 | declarators: DeclaratorList, | |
| 395 | semicolon: TokenIndex, | |
| 396 | ||
| 397 | pub const DeclaratorList = Root.DeclList; | |
| 378 | 398 | }; |
| 379 | 399 | |
| 380 | 400 | pub const TypeQual = struct { |
lib/std/c/parse.zig+115-15| ... | ... | @@ -94,12 +94,11 @@ const Parser = struct { |
| 94 | 94 | } |
| 95 | 95 | |
| 96 | 96 | fn getSymbol(parser: *Parser, tok: TokenIndex) ?*Type { |
| 97 | const token = parser.it.list.at(tok); | |
| 98 | const name = parser.tree.slice(token); | |
| 97 | const name = parser.tree.slice(tok); | |
| 99 | 98 | const syms = parser.symbols.toSliceConst(); |
| 100 | 99 | var i = syms.len; |
| 101 | 100 | while (i > 0) : (i -= 1) { |
| 102 | if (mem.eql(u8, name, syms[i].name)) { | |
| 101 | if (std.mem.eql(u8, name, syms[i].name)) { | |
| 103 | 102 | return syms[i].ty; |
| 104 | 103 | } |
| 105 | 104 | } |
| ... | ... | @@ -492,31 +491,29 @@ const Parser = struct { |
| 492 | 491 | } else if (parser.eatToken(.Keyword_enum)) |tok| { |
| 493 | 492 | if (type_spec.spec != .None) |
| 494 | 493 | break :blk; |
| 495 | type_spec.Enum = try parser.enumSpec(tok); | |
| 494 | type_spec.spec.Enum = try parser.enumSpec(tok); | |
| 496 | 495 | return true; |
| 497 | 496 | } else if (parser.eatToken(.Keyword_union) orelse parser.eatToken(.Keyword_struct)) |tok| { |
| 498 | 497 | if (type_spec.spec != .None) |
| 499 | 498 | break :blk; |
| 500 | type_spec.Record = try parser.recordSpec(); | |
| 499 | type_spec.spec.Record = try parser.recordSpec(tok); | |
| 501 | 500 | return true; |
| 502 | 501 | } else if (parser.eatToken(.Identifier)) |tok| { |
| 503 | 502 | const ty = parser.getSymbol(tok) orelse { |
| 504 | 503 | parser.putBackToken(tok); |
| 505 | 504 | return false; |
| 506 | 505 | }; |
| 507 | switch (ty) { | |
| 506 | switch (ty.id) { | |
| 508 | 507 | .Enum => |e| { |
| 509 | 508 | return parser.err(.{ |
| 510 | .MustUseKwToRefer = .{ .kw = e.identifier, .sym = tok }, | |
| 509 | .MustUseKwToRefer = .{ .kw = e.tok, .name = tok }, | |
| 511 | 510 | }); |
| 512 | 511 | }, |
| 513 | 512 | .Record => |r| { |
| 514 | 513 | return parser.err(.{ |
| 515 | 514 | .MustUseKwToRefer = .{ |
| 516 | .kw = switch (r.kind) { | |
| 517 | .Struct, .Union => |kw| kw, | |
| 518 | }, | |
| 519 | .sym = tok, | |
| 515 | .kw = r.tok, | |
| 516 | .name = tok, | |
| 520 | 517 | }, |
| 521 | 518 | }); |
| 522 | 519 | }, |
| ... | ... | @@ -613,18 +610,121 @@ const Parser = struct { |
| 613 | 610 | } |
| 614 | 611 | |
| 615 | 612 | /// EnumSpec <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)? |
| 616 | fn enumSpecifier(parser: *Parser) !*Node {} | |
| 613 | fn enumSpec(parser: *Parser, tok: TokenIndex) !*Node.EnumType { | |
| 614 | const node = try parser.arena.create(Node.EnumType); | |
| 615 | const name = parser.eatToken(.Identifier); | |
| 616 | node.* = .{ | |
| 617 | .tok = tok, | |
| 618 | .name = name, | |
| 619 | .body = null, | |
| 620 | }; | |
| 621 | const ty = try parser.arena.create(Type); | |
| 622 | ty.* = .{ | |
| 623 | .id = .{ | |
| 624 | .Enum = node, | |
| 625 | }, | |
| 626 | }; | |
| 627 | if (name) |some| | |
| 628 | try parser.symbols.append(.{ | |
| 629 | .name = parser.tree.slice(some), | |
| 630 | .ty = ty, | |
| 631 | }); | |
| 632 | if (parser.eatToken(.LBrace)) |lbrace| { | |
| 633 | var fields = Node.EnumType.FieldList.init(parser.arena); | |
| 634 | try fields.push((try parser.enumField()) orelse return parser.err(.{ | |
| 635 | .ExpectedEnumField = .{ .token = parser.it.index }, | |
| 636 | })); | |
| 637 | while (parser.eatToken(.Comma)) |_| { | |
| 638 | try fields.push((try parser.enumField()) orelse break); | |
| 639 | } | |
| 640 | node.body = .{ | |
| 641 | .lbrace = lbrace, | |
| 642 | .fields = fields, | |
| 643 | .rbrace = try parser.expectToken(.RBrace), | |
| 644 | }; | |
| 645 | } | |
| 646 | return node; | |
| 647 | } | |
| 617 | 648 | |
| 618 | 649 | /// EnumField <- IDENTIFIER (EQUAL ConstExpr)? (COMMA EnumField) COMMA? |
| 619 | fn enumField(parser: *Parser) !*Node {} | |
| 650 | fn enumField(parser: *Parser) !?*Node { | |
| 651 | const name = parser.eatToken(.Identifier) orelse return null; | |
| 652 | const node = try parser.arena.create(Node.EnumField); | |
| 653 | node.* = .{ | |
| 654 | .name = name, | |
| 655 | .value = null, | |
| 656 | }; | |
| 657 | if (parser.eatToken(.Equal)) |eq| { | |
| 658 | node.value = try parser.constExpr(); | |
| 659 | } | |
| 660 | return &node.base; | |
| 661 | } | |
| 620 | 662 | |
| 621 | 663 | /// RecordSpec <- (Keyword_struct / Keyword_union) IDENTIFIER? (LBRACE RecordField+ RBRACE)? |
| 622 | fn recordSpecifier(parser: *Parser) !*Node {} | |
| 664 | fn recordSpec(parser: *Parser, tok: TokenIndex) !*Node.RecordType { | |
| 665 | const node = try parser.arena.create(Node.RecordType); | |
| 666 | const name = parser.eatToken(.Identifier); | |
| 667 | const is_struct = parser.tree.slice(tok)[0] == 's'; | |
| 668 | node.* = .{ | |
| 669 | .tok = tok, | |
| 670 | .kind = if (is_struct) .Struct else .Union, | |
| 671 | .name = name, | |
| 672 | .body = null, | |
| 673 | }; | |
| 674 | const ty = try parser.arena.create(Type); | |
| 675 | ty.* = .{ | |
| 676 | .id = .{ | |
| 677 | .Record = node, | |
| 678 | }, | |
| 679 | }; | |
| 680 | if (name) |some| | |
| 681 | try parser.symbols.append(.{ | |
| 682 | .name = parser.tree.slice(some), | |
| 683 | .ty = ty, | |
| 684 | }); | |
| 685 | if (parser.eatToken(.LBrace)) |lbrace| { | |
| 686 | var fields = Node.RecordType.FieldList.init(parser.arena); | |
| 687 | while (true) { | |
| 688 | if (parser.eatToken(.RBrace)) |rbrace| { | |
| 689 | node.body = .{ | |
| 690 | .lbrace = lbrace, | |
| 691 | .fields = fields, | |
| 692 | .rbrace = rbrace, | |
| 693 | }; | |
| 694 | break; | |
| 695 | } | |
| 696 | try fields.push(try parser.recordField()); | |
| 697 | } | |
| 698 | } | |
| 699 | return node; | |
| 700 | } | |
| 623 | 701 | |
| 624 | 702 | /// RecordField |
| 625 | 703 | /// <- TypeSpec* (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON |
| 626 | 704 | /// \ StaticAssert |
| 627 | fn recordField(parser: *Parser) !*Node {} | |
| 705 | fn recordField(parser: *Parser) Error!*Node { | |
| 706 | if (try parser.staticAssert()) |decl| return decl; | |
| 707 | var got = false; | |
| 708 | var type_spec = Node.TypeSpec{}; | |
| 709 | while (try parser.typeSpec(&type_spec)) got = true; | |
| 710 | if (!got) | |
| 711 | return parser.err(.{ | |
| 712 | .ExpectedType = .{ .token = parser.it.index }, | |
| 713 | }); | |
| 714 | const node = try parser.arena.create(Node.RecordField); | |
| 715 | node.* = .{ | |
| 716 | .type_spec = type_spec, | |
| 717 | .declarators = Node.RecordField.DeclaratorList.init(parser.arena), | |
| 718 | .semicolon = undefined, | |
| 719 | }; | |
| 720 | while (true) { | |
| 721 | try node.declarators.push(try parser.recordDeclarator()); | |
| 722 | if (parser.eatToken(.Comma)) |_| {} else break; | |
| 723 | } | |
| 724 | ||
| 725 | node.semicolon = try parser.expectToken(.Semicolon); | |
| 726 | return &node.base; | |
| 727 | } | |
| 628 | 728 | |
| 629 | 729 | /// TypeName <- TypeSpec* AbstractDeclarator? |
| 630 | 730 | fn typeName(parser: *Parser) !*Node { |