authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-05-15 14:30:49+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-05-15 14:30:49+03:00
loga00fd6e25469a9929defea95425a1c312a68cf0e
tree2f806478e13ca3677b840994c5aff4465c13f2fc
parent440189a04ae4baa4a20114fe1d30f0eb585bacc4
signaturelock-open Commit is signed but in an unrecognized format.

properly handle extra closing braces at top level


2 files changed, 36 insertions(+), 16 deletions(-)

lib/std/zig/parse.zig+22-16
......@@ -57,16 +57,10 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree {
5757fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root {
5858 const node = try arena.create(Node.Root);
5959 node.* = .{
60 .decls = try parseContainerMembers(arena, it, tree),
61 .eof_token = eatToken(it, .Eof) orelse blk: {
62 // parseContainerMembers will try to skip as much
63 // invalid tokens as it can so this can only be a '}'
64 const tok = eatToken(it, .RBrace).?;
65 try tree.errors.push(.{
66 .ExpectedContainerMembers = .{ .token = tok },
67 });
68 break :blk tok;
69 },
60 .decls = try parseContainerMembers(arena, it, tree, true),
61 // parseContainerMembers will try to skip as much
62 // invalid tokens as it can so this can only be the EOF
63 .eof_token = eatToken(it, .Eof).?,
7064 };
7165 return node;
7266}
......@@ -78,7 +72,7 @@ fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error
7872/// / KEYWORD_pub? ContainerField COMMA ContainerMembers
7973/// / KEYWORD_pub? ContainerField
8074/// /
81fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.Root.DeclList {
75fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree, top_level: bool) !Node.Root.DeclList {
8276 var list = Node.Root.DeclList.init(arena);
8377
8478 var field_state: union(enum) {
......@@ -205,9 +199,15 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
205199 // try to continue parsing
206200 const index = it.index;
207201 findNextContainerMember(it);
208 switch (it.peek().?.id) {
209 .Eof, .RBrace => break,
202 const next = it.peek().?.id;
203 switch (next) {
204 .Eof => break,
210205 else => {
206 if (next == .RBrace) {
207 if (!top_level) break;
208 _ = nextToken(it);
209 }
210
211211 // add error and continue
212212 try tree.errors.push(.{
213213 .ExpectedToken = .{ .token = index, .expected_id = .Comma },
......@@ -228,9 +228,15 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
228228 });
229229 }
230230
231 switch (it.peek().?.id) {
232 .Eof, .RBrace => break,
231 const next = it.peek().?.id;
232 switch (next) {
233 .Eof => break,
233234 else => {
235 if (next == .RBrace) {
236 if (!top_level) break;
237 _ = nextToken(it);
238 }
239
234240 // this was likely not supposed to end yet,
235241 // try to find the next declaration
236242 const index = it.index;
......@@ -2778,7 +2784,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
27782784fn parseContainerDeclAuto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
27792785 const node = (try parseContainerDeclType(arena, it, tree)) orelse return null;
27802786 const lbrace = try expectToken(it, tree, .LBrace);
2781 const members = try parseContainerMembers(arena, it, tree);
2787 const members = try parseContainerMembers(arena, it, tree, false);
27822788 const rbrace = try expectToken(it, tree, .RBrace);
27832789
27842790 const decl_type = node.cast(Node.ContainerDecl).?;
lib/std/zig/parser_test.zig+14
......@@ -148,6 +148,20 @@ test "recovery: invalid parameter" {
148148 });
149149}
150150
151test "recovery: extra '}' at top level" {
152 try testError(
153 \\}}}
154 \\test "" {
155 \\ a && b;
156 \\}
157 , &[_]Error{
158 .ExpectedContainerMembers,
159 .ExpectedContainerMembers,
160 .ExpectedContainerMembers,
161 .InvalidAnd,
162 });
163}
164
151165test "zig fmt: top-level fields" {
152166 try testCanonical(
153167 \\a: did_you_know,