diff options
| author | Vexu <git@vexu.eu> | 2020-05-15 14:30:49 +0300 |
|---|---|---|
| committer | Vexu <git@vexu.eu> | 2020-05-15 14:30:49 +0300 |
| commit | a00fd6e25469a9929defea95425a1c312a68cf0e (patch) | |
| tree | 2f806478e13ca3677b840994c5aff4465c13f2fc /lib | |
| parent | 440189a04ae4baa4a20114fe1d30f0eb585bacc4 (diff) | |
| download | zig-a00fd6e25469a9929defea95425a1c312a68cf0e.tar.gz zig-a00fd6e25469a9929defea95425a1c312a68cf0e.zip | |
properly handle extra closing braces at top level
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/std/zig/parse.zig | 38 | ||||
| -rw-r--r-- | lib/std/zig/parser_test.zig | 14 |
2 files changed, 36 insertions, 16 deletions
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index a269dc616c..6e41771ecc 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -57,16 +57,10 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root { const node = try arena.create(Node.Root); node.* = .{ - .decls = try parseContainerMembers(arena, it, tree), - .eof_token = eatToken(it, .Eof) orelse blk: { - // parseContainerMembers will try to skip as much - // invalid tokens as it can so this can only be a '}' - const tok = eatToken(it, .RBrace).?; - try tree.errors.push(.{ - .ExpectedContainerMembers = .{ .token = tok }, - }); - break :blk tok; - }, + .decls = try parseContainerMembers(arena, it, tree, true), + // parseContainerMembers will try to skip as much + // invalid tokens as it can so this can only be the EOF + .eof_token = eatToken(it, .Eof).?, }; return node; } @@ -78,7 +72,7 @@ fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error /// / KEYWORD_pub? ContainerField COMMA ContainerMembers /// / KEYWORD_pub? ContainerField /// / -fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.Root.DeclList { +fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree, top_level: bool) !Node.Root.DeclList { var list = Node.Root.DeclList.init(arena); var field_state: union(enum) { @@ -205,9 +199,15 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No // try to continue parsing const index = it.index; findNextContainerMember(it); - switch (it.peek().?.id) { - .Eof, .RBrace => break, + const next = it.peek().?.id; + switch (next) { + .Eof => break, else => { + if (next == .RBrace) { + if (!top_level) break; + _ = nextToken(it); + } + // add error and continue try tree.errors.push(.{ .ExpectedToken = .{ .token = index, .expected_id = .Comma }, @@ -228,9 +228,15 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No }); } - switch (it.peek().?.id) { - .Eof, .RBrace => break, + const next = it.peek().?.id; + switch (next) { + .Eof => break, else => { + if (next == .RBrace) { + if (!top_level) break; + _ = nextToken(it); + } + // this was likely not supposed to end yet, // try to find the next declaration const index = it.index; @@ -2778,7 +2784,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node fn parseContainerDeclAuto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = (try parseContainerDeclType(arena, it, tree)) orelse return null; const lbrace = try expectToken(it, tree, .LBrace); - const members = try parseContainerMembers(arena, it, tree); + const members = try parseContainerMembers(arena, it, tree, false); const rbrace = try expectToken(it, tree, .RBrace); const decl_type = node.cast(Node.ContainerDecl).?; diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 6adc44a5b7..616c1a5ea4 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -148,6 +148,20 @@ test "recovery: invalid parameter" { }); } +test "recovery: extra '}' at top level" { + try testError( + \\}}} + \\test "" { + \\ a && b; + \\} + , &[_]Error{ + .ExpectedContainerMembers, + .ExpectedContainerMembers, + .ExpectedContainerMembers, + .InvalidAnd, + }); +} + test "zig fmt: top-level fields" { try testCanonical( \\a: did_you_know, |
