Commit 67dac2936c

Veikka Tuominen <git@vexu.eu>
2021-02-22 09:04:05
parser: warn on missing for loop payload, recover from invalid global error set access
1 parent 621ad24
Changed files (3)
lib/std/zig/ast.zig
@@ -253,6 +253,11 @@ pub const Tree = struct {
                     token_tags[parse_error.token].symbol(),
                 });
             },
+            .expected_loop_payload => {
+                return stream.print("expected loop payload, found '{s}'", .{
+                    token_tags[parse_error.token].symbol(),
+                });
+            },
             .extra_align_qualifier => {
                 return stream.writeAll("extra align qualifier");
             },
@@ -2332,6 +2337,7 @@ pub const Error = struct {
         expected_type_expr,
         expected_var_decl,
         expected_var_decl_or_fn,
+        expected_loop_payload,
         extra_align_qualifier,
         extra_allowzero_qualifier,
         extra_const_qualifier,
lib/std/zig/parse.zig
@@ -1052,7 +1052,8 @@ const Parser = struct {
         _ = try p.expectToken(.l_paren);
         const array_expr = try p.expectExpr();
         _ = try p.expectToken(.r_paren);
-        _ = try p.parsePtrIndexPayload();
+        const found_payload = try p.parsePtrIndexPayload();
+        if (found_payload == 0) try p.warn(.expected_loop_payload);
 
         // TODO propose to change the syntax so that semicolons are always required
         // inside while statements, even if there is an `else`.
@@ -2067,7 +2068,8 @@ const Parser = struct {
         _ = try p.expectToken(.l_paren);
         const array_expr = try p.expectExpr();
         _ = try p.expectToken(.r_paren);
-        _ = try p.parsePtrIndexPayload();
+        const found_payload = try p.parsePtrIndexPayload();
+        if (found_payload == 0) try p.warn(.expected_loop_payload);
 
         const then_expr = try p.expectExpr();
         const else_token = p.eatToken(.keyword_else) orelse {
@@ -2672,6 +2674,16 @@ const Parser = struct {
                     },
                 }),
             },
+            .keyword_inline => {
+                p.tok_i += 1;
+                switch (p.token_tags[p.tok_i]) {
+                    .keyword_for => return p.parseForTypeExpr(),
+                    .keyword_while => return p.parseWhileTypeExpr(),
+                    else => return p.fail(.expected_inlinable),
+                }
+            },
+            .keyword_for => return p.parseForTypeExpr(),
+            .keyword_while => return p.parseWhileTypeExpr(),
             .period => switch (p.token_tags[p.tok_i + 1]) {
                 .identifier => return p.addNode(.{
                     .tag = .enum_literal,
@@ -2879,14 +2891,21 @@ const Parser = struct {
                         },
                     });
                 },
-                else => return p.addNode(.{
-                    .tag = .error_value,
-                    .main_token = p.nextToken(),
-                    .data = .{
-                        .lhs = try p.expectToken(.period),
-                        .rhs = try p.expectToken(.identifier),
-                    },
-                }),
+                else => {
+                    const main_token = p.nextToken();
+                    const period = p.eatToken(.period);
+                    if (period == null) try p.warnExpected(.period);
+                    const identifier = p.eatToken(.identifier);
+                    if (identifier == null) try p.warnExpected(.identifier);
+                    return p.addNode(.{
+                        .tag = .error_value,
+                        .main_token = main_token,
+                        .data = .{
+                            .lhs = period orelse 0,
+                            .rhs = identifier orelse 0,
+                        },
+                    });
+                },
             },
             .l_paren => return p.addNode(.{
                 .tag = .grouped_expression,
@@ -2913,9 +2932,10 @@ const Parser = struct {
     fn parseForTypeExpr(p: *Parser) !Node.Index {
         const for_token = p.eatToken(.keyword_for) orelse return null_node;
         _ = try p.expectToken(.l_paren);
-        const array_expr = try p.expectTypeExpr();
+        const array_expr = try p.expectExpr();
         _ = try p.expectToken(.r_paren);
-        _ = try p.parsePtrIndexPayload();
+        const found_payload = try p.parsePtrIndexPayload();
+        if (found_payload == 0) try p.warn(.expected_loop_payload);
 
         const then_expr = try p.expectExpr();
         const else_token = p.eatToken(.keyword_else) orelse {
lib/std/zig/parser_test.zig
@@ -4215,6 +4215,8 @@ test "recovery: invalid global error set access" {
         \\}
     , &[_]Error{
         .expected_token,
+        .expected_token,
+        .invalid_and,
     });
 }
 
@@ -4273,6 +4275,20 @@ test "recovery: missing block after for/while loops" {
     });
 }
 
+test "recovery: missing for payload" {
+    try testError(
+        \\comptime {
+        \\    const a = for(a) {};
+        \\    const a: for(a) {};
+        \\    for(a) {}
+        \\}
+    , &[_]Error{
+        .expected_loop_payload,
+        .expected_loop_payload,
+        .expected_loop_payload,
+    });
+}
+
 const std = @import("std");
 const mem = std.mem;
 const warn = std.debug.warn;