| ... | @@ -130,15 +130,7 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All | ... | @@ -130,15 +130,7 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All |
| 130 | | 130 | |
| 131 | const visib_token = eatToken(it, .Keyword_pub); | 131 | const visib_token = eatToken(it, .Keyword_pub); |
| 132 | | 132 | |
| 133 | if (parseTopLevelDecl(arena, it, tree) catch |err| switch (err) { | 133 | if (try parseTopLevelDecl(arena, it, tree)) |node| { |
| 134 | error.OutOfMemory => return error.OutOfMemory, | | |
| 135 | error.ParseError => { | | |
| 136 | // attempt to recover by finding a semicolon | | |
| 137 | // TODO if this was a function with a body we should use findEndOfBlock | | |
| 138 | findToken(it, .Semicolon); | | |
| 139 | continue; | | |
| 140 | }, | | |
| 141 | }) |node| { | | |
| 142 | if (field_state == .seen) { | 134 | if (field_state == .seen) { |
| 143 | field_state = .{ .end = visib_token orelse node.firstToken() }; | 135 | field_state = .{ .end = visib_token orelse node.firstToken() }; |
| 144 | } | 136 | } |
| ... | @@ -217,43 +209,49 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All | ... | @@ -217,43 +209,49 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All |
| 217 | return list; | 209 | return list; |
| 218 | } | 210 | } |
| 219 | | 211 | |
| 220 | /// Attempts to find a closing brace, assumes the opening brace was found. | 212 | /// Attempts to find a closing brace. |
| 221 | fn findEndOfBlock(it: *TokenIterator) void { | 213 | fn findEndOfBlock(it: *TokenIterator) void { |
| 222 | var count: u32 = 1; | 214 | var count: u32 = 0; |
| 223 | while (it.next()) |tok| switch (tok.id) { | 215 | while (true) { |
| 224 | .LBrace => count += 1, | 216 | const tok = nextToken(it); |
| 225 | .RBrace => { | 217 | switch (tok.ptr.id) { |
| 226 | count -= 1; | 218 | .LBrace => count += 1, |
| 227 | if (count == 0) return; | 219 | .RBrace => { |
| 228 | }, | 220 | if (count <= 1) return; |
| 229 | .Eof => { | 221 | count -= 1; |
| 230 | _ = it.prev(); | 222 | }, |
| 231 | return; | 223 | .Eof => { |
| 232 | }, | 224 | putBackToken(it, tok.index); |
| 233 | else => {}, | 225 | return; |
| 234 | }; | 226 | }, |
| | 227 | else => {}, |
| | 228 | } |
| | 229 | } |
| 235 | } | 230 | } |
| 236 | | 231 | |
| 237 | /// Attempts to find `wanted` token, keeps track of parentheses. | 232 | /// Attempts to find `wanted` token, keeps track of parentheses. |
| 238 | fn findToken(it: *TokenIterator, wanted: Token.Id) void { | 233 | fn findToken(it: *TokenIterator, wanted: Token.Id) void { |
| 239 | var count: u32 = 0; | 234 | var count: u32 = 0; |
| 240 | while (it.next()) |tok| switch (tok.id) { | 235 | while (true) { |
| 241 | .LParen, .LBracket, .LBrace => count += 1, | 236 | const tok = nextToken(it); |
| 242 | .RParen, .RBracket, .RBrace => { | 237 | switch (tok.ptr.id) { |
| 243 | if (count == 0) { | 238 | .LParen, .LBracket, .LBrace => count += 1, |
| 244 | _ = it.prev(); | 239 | .RParen, .RBracket, .RBrace => { |
| | 240 | if (count == 0) { |
| | 241 | putBackToken(it, tok.index); |
| | 242 | return; |
| | 243 | } |
| | 244 | count -= 1; |
| | 245 | }, |
| | 246 | .Eof => { |
| | 247 | putBackToken(it, tok.index); |
| 245 | return; | 248 | return; |
| 246 | } | 249 | }, |
| 247 | count -= 1; | 250 | else => { |
| 248 | }, | 251 | if (tok.ptr.id == wanted and count == 0) return; |
| 249 | .Eof => { | 252 | }, |
| 250 | _ = it.prev(); | 253 | } |
| 251 | return; | 254 | } |
| 252 | }, | | |
| 253 | else => { | | |
| 254 | if (tok.id == wanted and count == 0) return; | | |
| 255 | }, | | |
| 256 | }; | | |
| 257 | } | 255 | } |
| 258 | | 256 | |
| 259 | /// Eat a multiline container doc comment | 257 | /// Eat a multiline container doc comment |
| ... | @@ -317,7 +315,7 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* | ... | @@ -317,7 +315,7 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* |
| 317 | /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) | 315 | /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) |
| 318 | /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl | 316 | /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl |
| 319 | /// / KEYWORD_usingnamespace Expr SEMICOLON | 317 | /// / KEYWORD_usingnamespace Expr SEMICOLON |
| 320 | fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 318 | fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!?*Node { |
| 321 | var lib_name: ?*Node = null; | 319 | var lib_name: ?*Node = null; |
| 322 | const extern_export_inline_token = blk: { | 320 | const extern_export_inline_token = blk: { |
| 323 | if (eatToken(it, .Keyword_export)) |token| break :blk token; | 321 | if (eatToken(it, .Keyword_export)) |token| break :blk token; |
| ... | @@ -330,12 +328,26 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -330,12 +328,26 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 330 | break :blk null; | 328 | break :blk null; |
| 331 | }; | 329 | }; |
| 332 | | 330 | |
| 333 | if (try parseFnProto(arena, it, tree)) |node| { | 331 | if (parseFnProto(arena, it, tree) catch |err| switch (err) { |
| | 332 | error.OutOfMemory => return error.OutOfMemory, |
| | 333 | error.ParseError => { |
| | 334 | // this fn will likely have a body so we |
| | 335 | // use findEndOfBlock instead of findToken. |
| | 336 | findEndOfBlock(it); |
| | 337 | return null; |
| | 338 | }, |
| | 339 | }) |node| { |
| 334 | const fn_node = node.cast(Node.FnProto).?; | 340 | const fn_node = node.cast(Node.FnProto).?; |
| 335 | fn_node.*.extern_export_inline_token = extern_export_inline_token; | 341 | fn_node.*.extern_export_inline_token = extern_export_inline_token; |
| 336 | fn_node.*.lib_name = lib_name; | 342 | fn_node.*.lib_name = lib_name; |
| 337 | if (eatToken(it, .Semicolon)) |_| return node; | 343 | if (eatToken(it, .Semicolon)) |_| return node; |
| 338 | if (try parseBlock(arena, it, tree)) |body_node| { | 344 | if (parseBlock(arena, it, tree) catch |err| switch (err) { |
| | 345 | error.OutOfMemory => return error.OutOfMemory, |
| | 346 | // since parseBlock only return error.ParseError on |
| | 347 | // a missing '}' we can assume this function was |
| | 348 | // supposed to end here. |
| | 349 | error.ParseError => null, |
| | 350 | }) |body_node| { |
| 339 | fn_node.body_node = body_node; | 351 | fn_node.body_node = body_node; |
| 340 | return node; | 352 | return node; |
| 341 | } | 353 | } |
| ... | @@ -356,7 +368,14 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -356,7 +368,14 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 356 | | 368 | |
| 357 | const thread_local_token = eatToken(it, .Keyword_threadlocal); | 369 | const thread_local_token = eatToken(it, .Keyword_threadlocal); |
| 358 | | 370 | |
| 359 | if (try parseVarDecl(arena, it, tree)) |node| { | 371 | if (parseVarDecl(arena, it, tree) catch |err| switch (err) { |
| | 372 | error.OutOfMemory => return error.OutOfMemory, |
| | 373 | error.ParseError => { |
| | 374 | // try to skip to next decl |
| | 375 | findToken(it, .Semicolon); |
| | 376 | return null; |
| | 377 | }, |
| | 378 | }) |node| { |
| 360 | var var_decl = node.cast(Node.VarDecl).?; | 379 | var var_decl = node.cast(Node.VarDecl).?; |
| 361 | var_decl.*.thread_local_token = thread_local_token; | 380 | var_decl.*.thread_local_token = thread_local_token; |
| 362 | var_decl.*.comptime_token = null; | 381 | var_decl.*.comptime_token = null; |
| ... | @@ -369,7 +388,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -369,7 +388,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 369 | try tree.errors.push(.{ | 388 | try tree.errors.push(.{ |
| 370 | .ExpectedVarDecl = .{ .token = it.index }, | 389 | .ExpectedVarDecl = .{ .token = it.index }, |
| 371 | }); | 390 | }); |
| 372 | return error.ParseError; | 391 | // ignore this, try to find next decl by skipping the next block |
| | 392 | findEndOfBlock(it); |
| 373 | } | 393 | } |
| 374 | | 394 | |
| 375 | if (extern_export_inline_token) |token| { | 395 | if (extern_export_inline_token) |token| { |
| ... | @@ -379,16 +399,14 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -379,16 +399,14 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 379 | return null; | 399 | return null; |
| 380 | } | 400 | } |
| 381 | | 401 | |
| 382 | const use_node = (try parseUse(arena, it, tree)) orelse return null; | 402 | return parseUse(arena, it, tree) catch |err| switch (err) { |
| 383 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | 403 | error.OutOfMemory => return error.OutOfMemory, |
| 384 | .ExpectedExpr = .{ .token = it.index }, | 404 | error.ParseError => { |
| 385 | }); | 405 | // try to skip to next decl |
| 386 | const semicolon_token = try expectToken(it, tree, .Semicolon); | 406 | findToken(it, .Semicolon); |
| 387 | const use_node_raw = use_node.cast(Node.Use).?; | 407 | return null; |
| 388 | use_node_raw.*.expr = expr_node; | 408 | }, |
| 389 | use_node_raw.*.semicolon_token = semicolon_token; | 409 | }; |
| 390 | | | |
| 391 | return use_node; | | |
| 392 | } | 410 | } |
| 393 | | 411 | |
| 394 | /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) | 412 | /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) |
| ... | @@ -422,18 +440,23 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -422,18 +440,23 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 422 | const exclamation_token = eatToken(it, .Bang); | 440 | const exclamation_token = eatToken(it, .Bang); |
| 423 | | 441 | |
| 424 | const return_type_expr = (try parseVarType(arena, it, tree)) orelse | 442 | const return_type_expr = (try parseVarType(arena, it, tree)) orelse |
| 425 | try expectNode(arena, it, tree, parseTypeExpr, .{ | 443 | (try parseTypeExpr(arena, it, tree)) orelse blk: { |
| 426 | .ExpectedReturnType = .{ .token = it.index }, | 444 | try tree.errors.push(.{ |
| 427 | }); | 445 | .ExpectedReturnType = .{ .token = it.index }, |
| | 446 | }); |
| | 447 | // most likely the user forgot to specify the return type. |
| | 448 | // Mark return type as invalid and try to continue. |
| | 449 | break :blk null; |
| | 450 | }; |
| 428 | | 451 | |
| 429 | const return_type: Node.FnProto.ReturnType = if (exclamation_token != null) | 452 | // TODO https://github.com/ziglang/zig/issues/3750 |
| 430 | .{ | 453 | const R = Node.FnProto.ReturnType; |
| 431 | .InferErrorSet = return_type_expr, | 454 | const return_type = if (return_type_expr == null) |
| 432 | } | 455 | R{ .Invalid = {} } |
| | 456 | else if (exclamation_token != null) |
| | 457 | R{ .InferErrorSet = return_type_expr.? } |
| 433 | else | 458 | else |
| 434 | .{ | 459 | R{ .Explicit = return_type_expr.? }; |
| 435 | .Explicit = return_type_expr, | | |
| 436 | }; | | |
| 437 | | 460 | |
| 438 | const var_args_token = if (params.len > 0) | 461 | const var_args_token = if (params.len > 0) |
| 439 | params.at(params.len - 1).*.cast(Node.ParamDecl).?.var_args_token | 462 | params.at(params.len - 1).*.cast(Node.ParamDecl).?.var_args_token |
| ... | @@ -2992,8 +3015,10 @@ fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2992,8 +3015,10 @@ fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2992 | .doc_comments = null, | 3015 | .doc_comments = null, |
| 2993 | .visib_token = null, | 3016 | .visib_token = null, |
| 2994 | .use_token = token, | 3017 | .use_token = token, |
| 2995 | .expr = undefined, // set by caller | 3018 | .expr = try expectNode(arena, it, tree, parseExpr, .{ |
| 2996 | .semicolon_token = undefined, // set by caller | 3019 | .ExpectedExpr = .{ .token = it.index }, |
| | 3020 | }), |
| | 3021 | .semicolon_token = try expectToken(it, tree, .Semicolon), |
| 2997 | }; | 3022 | }; |
| 2998 | return &node.base; | 3023 | return &node.base; |
| 2999 | } | 3024 | } |