| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const mem = std.mem; |
| 2 | 3 | const assert = std.debug.assert; |
| 3 | 4 | const Allocator = std.mem.Allocator; |
| 4 | 5 | const ast = std.c.ast; |
| ... | ... | @@ -11,9 +12,26 @@ const TokenIterator = ast.Tree.TokenList.Iterator; |
| 11 | 12 | |
| 12 | 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 | 32 | /// Result should be freed with tree.deinit() when there are |
| 15 | 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 | 35 | const tree = blk: { |
| 18 | 36 | // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists |
| 19 | 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 | 80 | .arena = arena, |
| 63 | 81 | .it = &it, |
| 64 | 82 | .tree = tree, |
| 83 | .options = options, |
| 65 | 84 | }; |
| 66 | 85 | defer parser.symbols.deinit(); |
| 67 | 86 | |
| ... | ... | @@ -76,7 +95,7 @@ const Parser = struct { |
| 76 | 95 | |
| 77 | 96 | /// only used for scopes |
| 78 | 97 | symbols: SymbolList, |
| 79 | | warnings: bool = true, |
| 98 | options: Options, |
| 80 | 99 | |
| 81 | 100 | const SymbolList = std.ArrayList(Symbol); |
| 82 | 101 | |
| ... | ... | @@ -94,11 +113,11 @@ const Parser = struct { |
| 94 | 113 | } |
| 95 | 114 | |
| 96 | 115 | fn getSymbol(parser: *Parser, tok: TokenIndex) ?*Type { |
| 97 | | const name = parser.tree.slice(tok); |
| 116 | const name = parser.tree.tokenSlice(tok); |
| 98 | 117 | const syms = parser.symbols.toSliceConst(); |
| 99 | 118 | var i = syms.len; |
| 100 | 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 | 121 | return syms[i].ty; |
| 103 | 122 | } |
| 104 | 123 | } |
| ... | ... | @@ -249,7 +268,7 @@ const Parser = struct { |
| 249 | 268 | try node.initializers.push((try parser.initializer(dr)) orelse return parser.err(.{ |
| 250 | 269 | .ExpectedInitializer = .{ .token = parser.it.index }, |
| 251 | 270 | })); |
| 252 | | } else |
| 271 | } else |
| 253 | 272 | try node.initializers.push(&dr.base); |
| 254 | 273 | if (parser.eatToken(.Comma) != null) break; |
| 255 | 274 | dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{ |
| ... | ... | @@ -558,12 +577,18 @@ const Parser = struct { |
| 558 | 577 | return false; |
| 559 | 578 | }; |
| 560 | 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 | 584 | return parser.err(.{ |
| 563 | 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 | 592 | return parser.err(.{ |
| 568 | 593 | .MustUseKwToRefer = .{ |
| 569 | 594 | .kw = r.tok, |
| ... | ... | @@ -580,11 +605,10 @@ const Parser = struct { |
| 580 | 605 | }; |
| 581 | 606 | return true; |
| 582 | 607 | }, |
| 583 | | else => { |
| 584 | | parser.putBackToken(tok); |
| 585 | | return false; |
| 586 | | }, |
| 608 | else => {}, |
| 587 | 609 | } |
| 610 | parser.putBackToken(tok); |
| 611 | return false; |
| 588 | 612 | } |
| 589 | 613 | } |
| 590 | 614 | return parser.err(.{ |
| ... | ... | @@ -680,7 +704,7 @@ const Parser = struct { |
| 680 | 704 | }; |
| 681 | 705 | if (name) |some| |
| 682 | 706 | try parser.symbols.append(.{ |
| 683 | | .name = parser.tree.slice(some), |
| 707 | .name = parser.tree.tokenSlice(some), |
| 684 | 708 | .ty = ty, |
| 685 | 709 | }); |
| 686 | 710 | if (parser.eatToken(.LBrace)) |lbrace| { |
| ... | ... | @@ -718,7 +742,7 @@ const Parser = struct { |
| 718 | 742 | fn recordSpec(parser: *Parser, tok: TokenIndex) !*Node.RecordType { |
| 719 | 743 | const node = try parser.arena.create(Node.RecordType); |
| 720 | 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 | 746 | node.* = .{ |
| 723 | 747 | .tok = tok, |
| 724 | 748 | .kind = if (is_struct) .Struct else .Union, |
| ... | ... | @@ -733,7 +757,7 @@ const Parser = struct { |
| 733 | 757 | }; |
| 734 | 758 | if (name) |some| |
| 735 | 759 | try parser.symbols.append(.{ |
| 736 | | .name = parser.tree.slice(some), |
| 760 | .name = parser.tree.tokenSlice(some), |
| 737 | 761 | .ty = ty, |
| 738 | 762 | }); |
| 739 | 763 | if (parser.eatToken(.LBrace)) |lbrace| { |
| ... | ... | @@ -1195,11 +1219,16 @@ const Parser = struct { |
| 1195 | 1219 | } |
| 1196 | 1220 | |
| 1197 | 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 | 1227 | try parser.tree.msgs.push(.{ |
| 1199 | | .kind = if (parser.warnings) .Warning else .Error, |
| 1228 | .kind = if (is_warning) .Warning else .Error, |
| 1200 | 1229 | .inner = msg, |
| 1201 | 1230 | }); |
| 1202 | | if (!parser.warnings) return error.ParseError; |
| 1231 | if (!is_warning) return error.ParseError; |
| 1203 | 1232 | } |
| 1204 | 1233 | |
| 1205 | 1234 | fn note(parser: *Parser, msg: ast.Error) Error!void { |