| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| | 2 | const mem = std.mem; |
| 2 | const assert = std.debug.assert; | 3 | const assert = std.debug.assert; |
| 3 | const Allocator = std.mem.Allocator; | 4 | const Allocator = std.mem.Allocator; |
| 4 | const ast = std.c.ast; | 5 | const ast = std.c.ast; |
| ... | @@ -11,9 +12,26 @@ const TokenIterator = ast.Tree.TokenList.Iterator; | ... | @@ -11,9 +12,26 @@ const TokenIterator = ast.Tree.TokenList.Iterator; |
| 11 | | 12 | |
| 12 | pub const Error = error{ParseError} || Allocator.Error; | 13 | pub const Error = error{ParseError} || Allocator.Error; |
| 13 | | 14 | |
| | 15 | pub const Options = struct { |
| | 16 | /// Keep simple macros unexpanded and add the definitions to the ast |
| | 17 | retain_macros: bool = false, |
| | 18 | |
| | 19 | /// Warning or error |
| | 20 | warn_as_err: union(enum) { |
| | 21 | /// All warnings are warnings |
| | 22 | None, |
| | 23 | |
| | 24 | /// Some warnings are errors |
| | 25 | Some: []@TagType(ast.Error), |
| | 26 | |
| | 27 | /// All warnings are errors |
| | 28 | All, |
| | 29 | } = .All, |
| | 30 | }; |
| | 31 | |
| 14 | /// Result should be freed with tree.deinit() when there are | 32 | /// Result should be freed with tree.deinit() when there are |
| 15 | /// no more references to any of the tokens or nodes. | 33 | /// no more references to any of the tokens or nodes. |
| 16 | pub fn parse(allocator: *Allocator, source: []const u8) !*Tree { | 34 | pub fn parse(allocator: *Allocator, source: []const u8, options: Options) !*Tree { |
| 17 | const tree = blk: { | 35 | const tree = blk: { |
| 18 | // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists | 36 | // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists |
| 19 | // from being initialized with a pointer to this `arena`, which is created on | 37 | // from being initialized with a pointer to this `arena`, which is created on |
| ... | @@ -62,6 +80,7 @@ pub fn parse(allocator: *Allocator, source: []const u8) !*Tree { | ... | @@ -62,6 +80,7 @@ pub fn parse(allocator: *Allocator, source: []const u8) !*Tree { |
| 62 | .arena = arena, | 80 | .arena = arena, |
| 63 | .it = &it, | 81 | .it = &it, |
| 64 | .tree = tree, | 82 | .tree = tree, |
| | 83 | .options = options, |
| 65 | }; | 84 | }; |
| 66 | defer parser.symbols.deinit(); | 85 | defer parser.symbols.deinit(); |
| 67 | | 86 | |
| ... | @@ -76,7 +95,7 @@ const Parser = struct { | ... | @@ -76,7 +95,7 @@ const Parser = struct { |
| 76 | | 95 | |
| 77 | /// only used for scopes | 96 | /// only used for scopes |
| 78 | symbols: SymbolList, | 97 | symbols: SymbolList, |
| 79 | warnings: bool = true, | 98 | options: Options, |
| 80 | | 99 | |
| 81 | const SymbolList = std.ArrayList(Symbol); | 100 | const SymbolList = std.ArrayList(Symbol); |
| 82 | | 101 | |
| ... | @@ -94,11 +113,11 @@ const Parser = struct { | ... | @@ -94,11 +113,11 @@ const Parser = struct { |
| 94 | } | 113 | } |
| 95 | | 114 | |
| 96 | fn getSymbol(parser: *Parser, tok: TokenIndex) ?*Type { | 115 | fn getSymbol(parser: *Parser, tok: TokenIndex) ?*Type { |
| 97 | const name = parser.tree.slice(tok); | 116 | const name = parser.tree.tokenSlice(tok); |
| 98 | const syms = parser.symbols.toSliceConst(); | 117 | const syms = parser.symbols.toSliceConst(); |
| 99 | var i = syms.len; | 118 | var i = syms.len; |
| 100 | while (i > 0) : (i -= 1) { | 119 | while (i > 0) : (i -= 1) { |
| 101 | if (std.mem.eql(u8, name, syms[i].name)) { | 120 | if (mem.eql(u8, name, syms[i].name)) { |
| 102 | return syms[i].ty; | 121 | return syms[i].ty; |
| 103 | } | 122 | } |
| 104 | } | 123 | } |
| ... | @@ -249,7 +268,7 @@ const Parser = struct { | ... | @@ -249,7 +268,7 @@ const Parser = struct { |
| 249 | try node.initializers.push((try parser.initializer(dr)) orelse return parser.err(.{ | 268 | try node.initializers.push((try parser.initializer(dr)) orelse return parser.err(.{ |
| 250 | .ExpectedInitializer = .{ .token = parser.it.index }, | 269 | .ExpectedInitializer = .{ .token = parser.it.index }, |
| 251 | })); | 270 | })); |
| 252 | } else | 271 | } else |
| 253 | try node.initializers.push(&dr.base); | 272 | try node.initializers.push(&dr.base); |
| 254 | if (parser.eatToken(.Comma) != null) break; | 273 | if (parser.eatToken(.Comma) != null) break; |
| 255 | dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{ | 274 | dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{ |
| ... | @@ -558,12 +577,18 @@ const Parser = struct { | ... | @@ -558,12 +577,18 @@ const Parser = struct { |
| 558 | return false; | 577 | return false; |
| 559 | }; | 578 | }; |
| 560 | switch (ty.id) { | 579 | switch (ty.id) { |
| 561 | .Enum => |e| { | 580 | .Enum => |e| blk: { |
| | 581 | if (e.name) |some| |
| | 582 | if (!parser.tree.tokenEql(some, tok)) |
| | 583 | break :blk; |
| 562 | return parser.err(.{ | 584 | return parser.err(.{ |
| 563 | .MustUseKwToRefer = .{ .kw = e.tok, .name = tok }, | 585 | .MustUseKwToRefer = .{ .kw = e.tok, .name = tok }, |
| 564 | }); | 586 | }); |
| 565 | }, | 587 | }, |
| 566 | .Record => |r| { | 588 | .Record => |r| blk: { |
| | 589 | if (r.name) |some| |
| | 590 | if (!parser.tree.tokenEql(some, tok)) |
| | 591 | break :blk; |
| 567 | return parser.err(.{ | 592 | return parser.err(.{ |
| 568 | .MustUseKwToRefer = .{ | 593 | .MustUseKwToRefer = .{ |
| 569 | .kw = r.tok, | 594 | .kw = r.tok, |
| ... | @@ -580,11 +605,10 @@ const Parser = struct { | ... | @@ -580,11 +605,10 @@ const Parser = struct { |
| 580 | }; | 605 | }; |
| 581 | return true; | 606 | return true; |
| 582 | }, | 607 | }, |
| 583 | else => { | 608 | else => {}, |
| 584 | parser.putBackToken(tok); | | |
| 585 | return false; | | |
| 586 | }, | | |
| 587 | } | 609 | } |
| | 610 | parser.putBackToken(tok); |
| | 611 | return false; |
| 588 | } | 612 | } |
| 589 | } | 613 | } |
| 590 | return parser.err(.{ | 614 | return parser.err(.{ |
| ... | @@ -680,7 +704,7 @@ const Parser = struct { | ... | @@ -680,7 +704,7 @@ const Parser = struct { |
| 680 | }; | 704 | }; |
| 681 | if (name) |some| | 705 | if (name) |some| |
| 682 | try parser.symbols.append(.{ | 706 | try parser.symbols.append(.{ |
| 683 | .name = parser.tree.slice(some), | 707 | .name = parser.tree.tokenSlice(some), |
| 684 | .ty = ty, | 708 | .ty = ty, |
| 685 | }); | 709 | }); |
| 686 | if (parser.eatToken(.LBrace)) |lbrace| { | 710 | if (parser.eatToken(.LBrace)) |lbrace| { |
| ... | @@ -718,7 +742,7 @@ const Parser = struct { | ... | @@ -718,7 +742,7 @@ const Parser = struct { |
| 718 | fn recordSpec(parser: *Parser, tok: TokenIndex) !*Node.RecordType { | 742 | fn recordSpec(parser: *Parser, tok: TokenIndex) !*Node.RecordType { |
| 719 | const node = try parser.arena.create(Node.RecordType); | 743 | const node = try parser.arena.create(Node.RecordType); |
| 720 | const name = parser.eatToken(.Identifier); | 744 | const name = parser.eatToken(.Identifier); |
| 721 | const is_struct = parser.tree.slice(tok)[0] == 's'; | 745 | const is_struct = parser.tree.tokenSlice(tok)[0] == 's'; |
| 722 | node.* = .{ | 746 | node.* = .{ |
| 723 | .tok = tok, | 747 | .tok = tok, |
| 724 | .kind = if (is_struct) .Struct else .Union, | 748 | .kind = if (is_struct) .Struct else .Union, |
| ... | @@ -733,7 +757,7 @@ const Parser = struct { | ... | @@ -733,7 +757,7 @@ const Parser = struct { |
| 733 | }; | 757 | }; |
| 734 | if (name) |some| | 758 | if (name) |some| |
| 735 | try parser.symbols.append(.{ | 759 | try parser.symbols.append(.{ |
| 736 | .name = parser.tree.slice(some), | 760 | .name = parser.tree.tokenSlice(some), |
| 737 | .ty = ty, | 761 | .ty = ty, |
| 738 | }); | 762 | }); |
| 739 | if (parser.eatToken(.LBrace)) |lbrace| { | 763 | if (parser.eatToken(.LBrace)) |lbrace| { |
| ... | @@ -1195,11 +1219,16 @@ const Parser = struct { | ... | @@ -1195,11 +1219,16 @@ const Parser = struct { |
| 1195 | } | 1219 | } |
| 1196 | | 1220 | |
| 1197 | fn warn(parser: *Parser, msg: ast.Error) Error!void { | 1221 | fn warn(parser: *Parser, msg: ast.Error) Error!void { |
| | 1222 | const is_warning = switch (parser.options.warn_as_err) { |
| | 1223 | .None => true, |
| | 1224 | .Some => |list| for (list) |item| (if (item == msg) break false) else true, |
| | 1225 | .All => false, |
| | 1226 | }; |
| 1198 | try parser.tree.msgs.push(.{ | 1227 | try parser.tree.msgs.push(.{ |
| 1199 | .kind = if (parser.warnings) .Warning else .Error, | 1228 | .kind = if (is_warning) .Warning else .Error, |
| 1200 | .inner = msg, | 1229 | .inner = msg, |
| 1201 | }); | 1230 | }); |
| 1202 | if (!parser.warnings) return error.ParseError; | 1231 | if (!is_warning) return error.ParseError; |
| 1203 | } | 1232 | } |
| 1204 | | 1233 | |
| 1205 | fn note(parser: *Parser, msg: ast.Error) Error!void { | 1234 | fn note(parser: *Parser, msg: ast.Error) Error!void { |