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
signature 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 {...@@ -57,16 +57,10 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree {
57fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root {57fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root {
58 const node = try arena.create(Node.Root);58 const node = try arena.create(Node.Root);
59 node.* = .{59 node.* = .{
60 .decls = try parseContainerMembers(arena, it, tree),60 .decls = try parseContainerMembers(arena, it, tree, true),
61 .eof_token = eatToken(it, .Eof) orelse blk: {61 // parseContainerMembers will try to skip as much
62 // parseContainerMembers will try to skip as much62 // invalid tokens as it can so this can only be the EOF
63 // invalid tokens as it can so this can only be a '}'63 .eof_token = eatToken(it, .Eof).?,
64 const tok = eatToken(it, .RBrace).?;
65 try tree.errors.push(.{
66 .ExpectedContainerMembers = .{ .token = tok },
67 });
68 break :blk tok;
69 },
70 };64 };
71 return node;65 return node;
72}66}
...@@ -78,7 +72,7 @@ fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error...@@ -78,7 +72,7 @@ fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error
78/// / KEYWORD_pub? ContainerField COMMA ContainerMembers72/// / KEYWORD_pub? ContainerField COMMA ContainerMembers
79/// / KEYWORD_pub? ContainerField73/// / KEYWORD_pub? ContainerField
80/// /74/// /
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 {
82 var list = Node.Root.DeclList.init(arena);76 var list = Node.Root.DeclList.init(arena);
8377
84 var field_state: union(enum) {78 var field_state: union(enum) {
...@@ -205,9 +199,15 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No...@@ -205,9 +199,15 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
205 // try to continue parsing199 // try to continue parsing
206 const index = it.index;200 const index = it.index;
207 findNextContainerMember(it);201 findNextContainerMember(it);
208 switch (it.peek().?.id) {202 const next = it.peek().?.id;
209 .Eof, .RBrace => break,203 switch (next) {
204 .Eof => break,
210 else => {205 else => {
206 if (next == .RBrace) {
207 if (!top_level) break;
208 _ = nextToken(it);
209 }
210
211 // add error and continue211 // add error and continue
212 try tree.errors.push(.{212 try tree.errors.push(.{
213 .ExpectedToken = .{ .token = index, .expected_id = .Comma },213 .ExpectedToken = .{ .token = index, .expected_id = .Comma },
...@@ -228,9 +228,15 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No...@@ -228,9 +228,15 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
228 });228 });
229 }229 }
230230
231 switch (it.peek().?.id) {231 const next = it.peek().?.id;
232 .Eof, .RBrace => break,232 switch (next) {
233 .Eof => break,
233 else => {234 else => {
235 if (next == .RBrace) {
236 if (!top_level) break;
237 _ = nextToken(it);
238 }
239
234 // this was likely not supposed to end yet,240 // this was likely not supposed to end yet,
235 // try to find the next declaration241 // try to find the next declaration
236 const index = it.index;242 const index = it.index;
...@@ -2778,7 +2784,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2778,7 +2784,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2778fn parseContainerDeclAuto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2784fn parseContainerDeclAuto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2779 const node = (try parseContainerDeclType(arena, it, tree)) orelse return null;2785 const node = (try parseContainerDeclType(arena, it, tree)) orelse return null;
2780 const lbrace = try expectToken(it, tree, .LBrace);2786 const lbrace = try expectToken(it, tree, .LBrace);
2781 const members = try parseContainerMembers(arena, it, tree);2787 const members = try parseContainerMembers(arena, it, tree, false);
2782 const rbrace = try expectToken(it, tree, .RBrace);2788 const rbrace = try expectToken(it, tree, .RBrace);
27832789
2784 const decl_type = node.cast(Node.ContainerDecl).?;2790 const decl_type = node.cast(Node.ContainerDecl).?;
lib/std/zig/parser_test.zig+14
...@@ -148,6 +148,20 @@ test "recovery: invalid parameter" {...@@ -148,6 +148,20 @@ test "recovery: invalid parameter" {
148 });148 });
149}149}
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
151test "zig fmt: top-level fields" {165test "zig fmt: top-level fields" {
152 try testCanonical(166 try testCanonical(
153 \\a: did_you_know,167 \\a: did_you_know,