| ... | ... | @@ -59,10 +59,13 @@ fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error |
| 59 | 59 | node.* = .{ |
| 60 | 60 | .decls = try parseContainerMembers(arena, it, tree), |
| 61 | 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).?; |
| 62 | 65 | try tree.errors.push(.{ |
| 63 | | .ExpectedContainerMembers = .{ .token = it.index }, |
| 66 | .ExpectedContainerMembers = .{ .token = tok }, |
| 64 | 67 | }); |
| 65 | | break :blk undefined; |
| 68 | break :blk tok; |
| 66 | 69 | }, |
| 67 | 70 | }; |
| 68 | 71 | return node; |
| ... | ... | @@ -101,7 +104,7 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All |
| 101 | 104 | if (parseTestDecl(arena, it, tree) catch |err| switch (err) { |
| 102 | 105 | error.OutOfMemory => return error.OutOfMemory, |
| 103 | 106 | error.ParseError => { |
| 104 | | findEndOfBlock(it); |
| 107 | findNextContainerMember(it); |
| 105 | 108 | continue; |
| 106 | 109 | }, |
| 107 | 110 | }) |node| { |
| ... | ... | @@ -116,7 +119,7 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All |
| 116 | 119 | if (parseTopLevelComptime(arena, it, tree) catch |err| switch (err) { |
| 117 | 120 | error.OutOfMemory => return error.OutOfMemory, |
| 118 | 121 | error.ParseError => { |
| 119 | | findEndOfBlock(it); |
| 122 | findNextContainerMember(it); |
| 120 | 123 | continue; |
| 121 | 124 | }, |
| 122 | 125 | }) |node| { |
| ... | ... | @@ -178,8 +181,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All |
| 178 | 181 | if (parseContainerField(arena, it, tree) catch |err| switch (err) { |
| 179 | 182 | error.OutOfMemory => return error.OutOfMemory, |
| 180 | 183 | error.ParseError => { |
| 181 | | // attempt to recover by finding a comma |
| 182 | | findToken(it, .Comma); |
| 184 | // attempt to recover |
| 185 | findNextContainerMember(it); |
| 183 | 186 | continue; |
| 184 | 187 | }, |
| 185 | 188 | }) |node| { |
| ... | ... | @@ -198,7 +201,21 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All |
| 198 | 201 | const field = node.cast(Node.ContainerField).?; |
| 199 | 202 | field.doc_comments = doc_comments; |
| 200 | 203 | try list.push(node); |
| 201 | | const comma = eatToken(it, .Comma) orelse break; |
| 204 | const comma = eatToken(it, .Comma) orelse { |
| 205 | // try to continue parsing |
| 206 | const index = it.index; |
| 207 | findNextContainerMember(it); |
| 208 | switch (it.peek().?.id) { |
| 209 | .Eof, .RBrace => break, |
| 210 | else => { |
| 211 | // add error and continue |
| 212 | try tree.errors.push(.{ |
| 213 | .ExpectedToken = .{ .token = index, .expected_id = .Comma }, |
| 214 | }); |
| 215 | continue; |
| 216 | } |
| 217 | } |
| 218 | }; |
| 202 | 219 | if (try parseAppendedDocComment(arena, it, tree, comma)) |appended_comment| |
| 203 | 220 | field.doc_comments = appended_comment; |
| 204 | 221 | continue; |
| ... | ... | @@ -210,22 +227,63 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All |
| 210 | 227 | .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() }, |
| 211 | 228 | }); |
| 212 | 229 | } |
| 213 | | break; |
| 230 | |
| 231 | switch (it.peek().?.id) { |
| 232 | .Eof, .RBrace => break, |
| 233 | else => { |
| 234 | // this was likely not supposed to end yet, |
| 235 | // try to find the next declaration |
| 236 | const index = it.index; |
| 237 | findNextContainerMember(it); |
| 238 | try tree.errors.push(.{ |
| 239 | .ExpectedContainerMembers = .{ .token = index }, |
| 240 | }); |
| 241 | }, |
| 242 | } |
| 214 | 243 | } |
| 215 | 244 | |
| 216 | 245 | return list; |
| 217 | 246 | } |
| 218 | 247 | |
| 219 | | /// Attempts to find a closing brace. |
| 220 | | fn findEndOfBlock(it: *TokenIterator) void { |
| 221 | | var count: u32 = 0; |
| 248 | fn findNextContainerMember(it: *TokenIterator) void { |
| 249 | var level: u32 = 0; |
| 222 | 250 | while (true) { |
| 223 | 251 | const tok = nextToken(it); |
| 224 | 252 | switch (tok.ptr.id) { |
| 225 | | .LBrace => count += 1, |
| 226 | | .RBrace => { |
| 227 | | if (count <= 1) return; |
| 228 | | count -= 1; |
| 253 | // any of these can start a new top level declaration |
| 254 | .Keyword_test, |
| 255 | .Keyword_comptime, |
| 256 | .Keyword_pub, |
| 257 | .Keyword_export, |
| 258 | .Keyword_extern, |
| 259 | .Keyword_inline, |
| 260 | .Keyword_noinline, |
| 261 | .Keyword_usingnamespace, |
| 262 | .Keyword_threadlocal, |
| 263 | .Keyword_const, |
| 264 | .Keyword_var, |
| 265 | .Keyword_fn, |
| 266 | .Identifier, |
| 267 | => { |
| 268 | if (level == 0) { |
| 269 | putBackToken(it, tok.index); |
| 270 | return; |
| 271 | } |
| 272 | }, |
| 273 | .Comma, .Semicolon => { |
| 274 | // this decl was likely meant to end here |
| 275 | if (level == 0) { |
| 276 | return; |
| 277 | } |
| 278 | }, |
| 279 | .LParen, .LBracket, .LBrace => level += 1, |
| 280 | .RParen, .RBracket, .RBrace => { |
| 281 | if (level == 0) { |
| 282 | // end of container, exit |
| 283 | putBackToken(it, tok.index); |
| 284 | return; |
| 285 | } |
| 286 | level -= 1; |
| 229 | 287 | }, |
| 230 | 288 | .Eof => { |
| 231 | 289 | putBackToken(it, tok.index); |
| ... | ... | @@ -338,9 +396,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!? |
| 338 | 396 | if (parseFnProto(arena, it, tree) catch |err| switch (err) { |
| 339 | 397 | error.OutOfMemory => return error.OutOfMemory, |
| 340 | 398 | error.ParseError => { |
| 341 | | // this fn will likely have a body so we |
| 342 | | // use findEndOfBlock instead of findToken. |
| 343 | | findEndOfBlock(it); |
| 399 | findNextContainerMember(it); |
| 344 | 400 | return error.ParseError; |
| 345 | 401 | }, |
| 346 | 402 | }) |node| { |
| ... | ... | @@ -381,7 +437,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!? |
| 381 | 437 | error.OutOfMemory => return error.OutOfMemory, |
| 382 | 438 | error.ParseError => { |
| 383 | 439 | // try to skip to next decl |
| 384 | | findToken(it, .Semicolon); |
| 440 | findNextContainerMember(it); |
| 385 | 441 | return error.ParseError; |
| 386 | 442 | }, |
| 387 | 443 | }) |node| { |
| ... | ... | @@ -413,7 +469,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!? |
| 413 | 469 | error.OutOfMemory => return error.OutOfMemory, |
| 414 | 470 | error.ParseError => { |
| 415 | 471 | // try to skip to next decl |
| 416 | | findToken(it, .Semicolon); |
| 472 | findNextContainerMember(it); |
| 417 | 473 | return error.ParseError; |
| 418 | 474 | }, |
| 419 | 475 | }; |
| ... | ... | @@ -3215,6 +3271,8 @@ fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex { |
| 3215 | 3271 | try tree.errors.push(.{ |
| 3216 | 3272 | .ExpectedToken = .{ .token = token.index, .expected_id = id }, |
| 3217 | 3273 | }); |
| 3274 | // go back so that we can recover properly |
| 3275 | putBackToken(it, token.index); |
| 3218 | 3276 | return error.ParseError; |
| 3219 | 3277 | } |
| 3220 | 3278 | return token.index; |