| ... | ... | @@ -130,15 +130,7 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) All |
| 130 | 130 | |
| 131 | 131 | const visib_token = eatToken(it, .Keyword_pub); |
| 132 | 132 | |
| 133 | | if (parseTopLevelDecl(arena, it, tree) catch |err| switch (err) { |
| 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| { |
| 133 | if (try parseTopLevelDecl(arena, it, tree)) |node| { |
| 142 | 134 | if (field_state == .seen) { |
| 143 | 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 | 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 | 213 | fn findEndOfBlock(it: *TokenIterator) void { |
| 222 | | var count: u32 = 1; |
| 223 | | while (it.next()) |tok| switch (tok.id) { |
| 224 | | .LBrace => count += 1, |
| 225 | | .RBrace => { |
| 226 | | count -= 1; |
| 227 | | if (count == 0) return; |
| 228 | | }, |
| 229 | | .Eof => { |
| 230 | | _ = it.prev(); |
| 231 | | return; |
| 232 | | }, |
| 233 | | else => {}, |
| 234 | | }; |
| 214 | var count: u32 = 0; |
| 215 | while (true) { |
| 216 | const tok = nextToken(it); |
| 217 | switch (tok.ptr.id) { |
| 218 | .LBrace => count += 1, |
| 219 | .RBrace => { |
| 220 | if (count <= 1) return; |
| 221 | count -= 1; |
| 222 | }, |
| 223 | .Eof => { |
| 224 | putBackToken(it, tok.index); |
| 225 | return; |
| 226 | }, |
| 227 | else => {}, |
| 228 | } |
| 229 | } |
| 235 | 230 | } |
| 236 | 231 | |
| 237 | 232 | /// Attempts to find `wanted` token, keeps track of parentheses. |
| 238 | 233 | fn findToken(it: *TokenIterator, wanted: Token.Id) void { |
| 239 | 234 | var count: u32 = 0; |
| 240 | | while (it.next()) |tok| switch (tok.id) { |
| 241 | | .LParen, .LBracket, .LBrace => count += 1, |
| 242 | | .RParen, .RBracket, .RBrace => { |
| 243 | | if (count == 0) { |
| 244 | | _ = it.prev(); |
| 235 | while (true) { |
| 236 | const tok = nextToken(it); |
| 237 | switch (tok.ptr.id) { |
| 238 | .LParen, .LBracket, .LBrace => count += 1, |
| 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 | 248 | return; |
| 246 | | } |
| 247 | | count -= 1; |
| 248 | | }, |
| 249 | | .Eof => { |
| 250 | | _ = it.prev(); |
| 251 | | return; |
| 252 | | }, |
| 253 | | else => { |
| 254 | | if (tok.id == wanted and count == 0) return; |
| 255 | | }, |
| 256 | | }; |
| 249 | }, |
| 250 | else => { |
| 251 | if (tok.ptr.id == wanted and count == 0) return; |
| 252 | }, |
| 253 | } |
| 254 | } |
| 257 | 255 | } |
| 258 | 256 | |
| 259 | 257 | /// Eat a multiline container doc comment |
| ... | ... | @@ -317,7 +315,7 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* |
| 317 | 315 | /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) |
| 318 | 316 | /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl |
| 319 | 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 | 319 | var lib_name: ?*Node = null; |
| 322 | 320 | const extern_export_inline_token = blk: { |
| 323 | 321 | if (eatToken(it, .Keyword_export)) |token| break :blk token; |
| ... | ... | @@ -330,12 +328,26 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 330 | 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 | 340 | const fn_node = node.cast(Node.FnProto).?; |
| 335 | 341 | fn_node.*.extern_export_inline_token = extern_export_inline_token; |
| 336 | 342 | fn_node.*.lib_name = lib_name; |
| 337 | 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 | 351 | fn_node.body_node = body_node; |
| 340 | 352 | return node; |
| 341 | 353 | } |
| ... | ... | @@ -356,7 +368,14 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 356 | 368 | |
| 357 | 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 | 379 | var var_decl = node.cast(Node.VarDecl).?; |
| 361 | 380 | var_decl.*.thread_local_token = thread_local_token; |
| 362 | 381 | var_decl.*.comptime_token = null; |
| ... | ... | @@ -369,7 +388,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 369 | 388 | try tree.errors.push(.{ |
| 370 | 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 | 395 | if (extern_export_inline_token) |token| { |
| ... | ... | @@ -379,16 +399,14 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 379 | 399 | return null; |
| 380 | 400 | } |
| 381 | 401 | |
| 382 | | const use_node = (try parseUse(arena, it, tree)) orelse return null; |
| 383 | | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 384 | | .ExpectedExpr = .{ .token = it.index }, |
| 385 | | }); |
| 386 | | const semicolon_token = try expectToken(it, tree, .Semicolon); |
| 387 | | const use_node_raw = use_node.cast(Node.Use).?; |
| 388 | | use_node_raw.*.expr = expr_node; |
| 389 | | use_node_raw.*.semicolon_token = semicolon_token; |
| 390 | | |
| 391 | | return use_node; |
| 402 | return parseUse(arena, it, tree) catch |err| switch (err) { |
| 403 | error.OutOfMemory => return error.OutOfMemory, |
| 404 | error.ParseError => { |
| 405 | // try to skip to next decl |
| 406 | findToken(it, .Semicolon); |
| 407 | return null; |
| 408 | }, |
| 409 | }; |
| 392 | 410 | } |
| 393 | 411 | |
| 394 | 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 | 440 | const exclamation_token = eatToken(it, .Bang); |
| 423 | 441 | |
| 424 | 442 | const return_type_expr = (try parseVarType(arena, it, tree)) orelse |
| 425 | | try expectNode(arena, it, tree, parseTypeExpr, .{ |
| 426 | | .ExpectedReturnType = .{ .token = it.index }, |
| 427 | | }); |
| 443 | (try parseTypeExpr(arena, it, tree)) orelse blk: { |
| 444 | try tree.errors.push(.{ |
| 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) |
| 430 | | .{ |
| 431 | | .InferErrorSet = return_type_expr, |
| 432 | | } |
| 452 | // TODO https://github.com/ziglang/zig/issues/3750 |
| 453 | const R = Node.FnProto.ReturnType; |
| 454 | const return_type = if (return_type_expr == null) |
| 455 | R{ .Invalid = {} } |
| 456 | else if (exclamation_token != null) |
| 457 | R{ .InferErrorSet = return_type_expr.? } |
| 433 | 458 | else |
| 434 | | .{ |
| 435 | | .Explicit = return_type_expr, |
| 436 | | }; |
| 459 | R{ .Explicit = return_type_expr.? }; |
| 437 | 460 | |
| 438 | 461 | const var_args_token = if (params.len > 0) |
| 439 | 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 | 3015 | .doc_comments = null, |
| 2993 | 3016 | .visib_token = null, |
| 2994 | 3017 | .use_token = token, |
| 2995 | | .expr = undefined, // set by caller |
| 2996 | | .semicolon_token = undefined, // set by caller |
| 3018 | .expr = try expectNode(arena, it, tree, parseExpr, .{ |
| 3019 | .ExpectedExpr = .{ .token = it.index }, |
| 3020 | }), |
| 3021 | .semicolon_token = try expectToken(it, tree, .Semicolon), |
| 2997 | 3022 | }; |
| 2998 | 3023 | return &node.base; |
| 2999 | 3024 | } |