| author | |
| committer | |
| log | d7f9128b5d3c8c8f6a0a617c45717cdc7e3543fd |
| tree | 8da94ed09600cfcebe599c531d7aa887531e5514 |
| parent | 960b5b518fa7ff7c6760d3e5f3c1256e553e6ba8 |
4 files changed, 27 insertions(+), 3 deletions(-)
lib/std/zig/ast.zig+4| ... | ... | @@ -171,6 +171,7 @@ pub const Error = union(enum) { |
| 171 | 171 | ExpectedBlockOrField: ExpectedBlockOrField, |
| 172 | 172 | DeclBetweenFields: DeclBetweenFields, |
| 173 | 173 | InvalidAnd: InvalidAnd, |
| 174 | AsteriskAfterPointerDereference: AsteriskAfterPointerDereference, | |
| 174 | 175 | |
| 175 | 176 | pub fn render(self: *const Error, tokens: []const Token.Id, stream: anytype) !void { |
| 176 | 177 | switch (self.*) { |
| ... | ... | @@ -222,6 +223,7 @@ pub const Error = union(enum) { |
| 222 | 223 | .ExpectedBlockOrField => |*x| return x.render(tokens, stream), |
| 223 | 224 | .DeclBetweenFields => |*x| return x.render(tokens, stream), |
| 224 | 225 | .InvalidAnd => |*x| return x.render(tokens, stream), |
| 226 | .AsteriskAfterPointerDereference => |*x| return x.render(tokens, stream), | |
| 225 | 227 | } |
| 226 | 228 | } |
| 227 | 229 | |
| ... | ... | @@ -275,6 +277,7 @@ pub const Error = union(enum) { |
| 275 | 277 | .ExpectedBlockOrField => |x| return x.token, |
| 276 | 278 | .DeclBetweenFields => |x| return x.token, |
| 277 | 279 | .InvalidAnd => |x| return x.token, |
| 280 | .AsteriskAfterPointerDereference => |x| return x.token, | |
| 278 | 281 | } |
| 279 | 282 | } |
| 280 | 283 | |
| ... | ... | @@ -323,6 +326,7 @@ pub const Error = union(enum) { |
| 323 | 326 | pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier"); |
| 324 | 327 | pub const DeclBetweenFields = SimpleError("Declarations are not allowed between container fields"); |
| 325 | 328 | pub const InvalidAnd = SimpleError("`&&` is invalid. Note that `and` is boolean AND."); |
| 329 | pub const AsteriskAfterPointerDereference = SimpleError("`.*` can't be followed by `*`. Are you missing a space?"); | |
| 326 | 330 | |
| 327 | 331 | pub const ExpectedCall = struct { |
| 328 | 332 | node: *Node, |
lib/std/zig/parse.zig+7| ... | ... | @@ -2701,6 +2701,13 @@ const Parser = struct { |
| 2701 | 2701 | return &node.base; |
| 2702 | 2702 | } |
| 2703 | 2703 | |
| 2704 | if (p.token_ids[p.tok_i] == .Invalid_periodasterisks) { | |
| 2705 | try p.errors.append(p.gpa, .{ | |
| 2706 | .AsteriskAfterPointerDereference = .{ .token = p.tok_i }, | |
| 2707 | }); | |
| 2708 | return null; | |
| 2709 | } | |
| 2710 | ||
| 2704 | 2711 | if (p.eatToken(.Period)) |period| { |
| 2705 | 2712 | if (try p.parseIdentifier()) |identifier| { |
| 2706 | 2713 | const node = try p.arena.allocator.create(Node.SimpleInfixOp); |
lib/std/zig/parser_test.zig+11| ... | ... | @@ -219,6 +219,17 @@ test "recovery: invalid global error set access" { |
| 219 | 219 | }); |
| 220 | 220 | } |
| 221 | 221 | |
| 222 | test "recovery: invalid asterisk after pointer dereference" { | |
| 223 | try testError( | |
| 224 | \\test "" { | |
| 225 | \\ var sequence = "repeat".*** 10; | |
| 226 | \\} | |
| 227 | , &[_]Error{ | |
| 228 | .AsteriskAfterPointerDereference, | |
| 229 | .ExpectedToken, | |
| 230 | }); | |
| 231 | } | |
| 232 | ||
| 222 | 233 | test "recovery: missing semicolon after if, for, while stmt" { |
| 223 | 234 | try testError( |
| 224 | 235 | \\test "" { |
lib/std/zig/tokenizer.zig+5-3| ... | ... | @@ -78,6 +78,7 @@ pub const Token = struct { |
| 78 | 78 | pub const Id = enum { |
| 79 | 79 | Invalid, |
| 80 | 80 | Invalid_ampersands, |
| 81 | Invalid_periodasterisks, | |
| 81 | 82 | Identifier, |
| 82 | 83 | StringLiteral, |
| 83 | 84 | MultilineStringLiteralLine, |
| ... | ... | @@ -201,6 +202,7 @@ pub const Token = struct { |
| 201 | 202 | return switch (id) { |
| 202 | 203 | .Invalid => "Invalid", |
| 203 | 204 | .Invalid_ampersands => "&&", |
| 205 | .Invalid_periodasterisks => ".**", | |
| 204 | 206 | .Identifier => "Identifier", |
| 205 | 207 | .StringLiteral => "StringLiteral", |
| 206 | 208 | .MultilineStringLiteralLine => "MultilineStringLiteralLine", |
| ... | ... | @@ -1002,13 +1004,13 @@ pub const Tokenizer = struct { |
| 1002 | 1004 | |
| 1003 | 1005 | .period_asterisk => switch (c) { |
| 1004 | 1006 | '*' => { |
| 1005 | result.id = .Invalid; | |
| 1007 | result.id = .Invalid_periodasterisks; | |
| 1006 | 1008 | break; |
| 1007 | 1009 | }, |
| 1008 | 1010 | else => { |
| 1009 | 1011 | result.id = .PeriodAsterisk; |
| 1010 | 1012 | break; |
| 1011 | } | |
| 1013 | }, | |
| 1012 | 1014 | }, |
| 1013 | 1015 | |
| 1014 | 1016 | .slash => switch (c) { |
| ... | ... | @@ -1794,7 +1796,7 @@ test "correctly parse pointer dereference followed by asterisk" { |
| 1794 | 1796 | |
| 1795 | 1797 | testTokenize("\"b\".*** 10", &[_]Token.Id{ |
| 1796 | 1798 | .StringLiteral, |
| 1797 | .Invalid, | |
| 1799 | .Invalid_periodasterisks, | |
| 1798 | 1800 | .AsteriskAsterisk, |
| 1799 | 1801 | .IntegerLiteral, |
| 1800 | 1802 | }); |