| author | |
| committer | |
| log | 80dd43213727b914418175e6e35c35de95204f7c |
| tree | 47ecbc59fdfdbe8645b1c07efb2b3cbc3e720bb8 |
| parent | 72343ffd06dbbc95424d74c93188ba4a6aa74c49 |
| parent | f54605ecc2c93b98b94c5e9e42aafa9e433006fc |
| signature |
don't allow a token starting with an asterisk directly following .*7 files changed, 102 insertions(+), 6 deletions(-)
doc/docgen.zig+1-1| ... | ... | @@ -972,7 +972,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: anytype, source_token: |
| 972 | 972 | .Tilde, |
| 973 | 973 | => try writeEscaped(out, src[token.loc.start..token.loc.end]), |
| 974 | 974 | |
| 975 | .Invalid, .Invalid_ampersands => return parseError( | |
| 975 | .Invalid, .Invalid_ampersands, .Invalid_periodasterisks => return parseError( | |
| 976 | 976 | docgen_tokenizer, |
| 977 | 977 | source_token, |
| 978 | 978 | "syntax error", |
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+13| ... | ... | @@ -2701,6 +2701,19 @@ const Parser = struct { |
| 2701 | 2701 | return &node.base; |
| 2702 | 2702 | } |
| 2703 | 2703 | |
| 2704 | if (p.eatToken(.Invalid_periodasterisks)) |period_asterisk| { | |
| 2705 | try p.errors.append(p.gpa, .{ | |
| 2706 | .AsteriskAfterPointerDereference = .{ .token = period_asterisk }, | |
| 2707 | }); | |
| 2708 | const node = try p.arena.allocator.create(Node.SimpleSuffixOp); | |
| 2709 | node.* = .{ | |
| 2710 | .base = .{ .tag = .Deref }, | |
| 2711 | .lhs = lhs, | |
| 2712 | .rtoken = period_asterisk, | |
| 2713 | }; | |
| 2714 | return &node.base; | |
| 2715 | } | |
| 2716 | ||
| 2704 | 2717 | if (p.eatToken(.Period)) |period| { |
| 2705 | 2718 | if (try p.parseIdentifier()) |identifier| { |
| 2706 | 2719 | const node = try p.arena.allocator.create(Node.SimpleInfixOp); |
lib/std/zig/parser_test.zig+18| ... | ... | @@ -219,6 +219,24 @@ 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 | }); | |
| 230 | try testError( | |
| 231 | \\test "" { | |
| 232 | \\ var sequence = "repeat".** 10&&a; | |
| 233 | \\} | |
| 234 | , &[_]Error{ | |
| 235 | .AsteriskAfterPointerDereference, | |
| 236 | .InvalidAnd, | |
| 237 | }); | |
| 238 | } | |
| 239 | ||
| 222 | 240 | test "recovery: missing semicolon after if, for, while stmt" { |
| 223 | 241 | try testError( |
| 224 | 242 | \\test "" { |
lib/std/zig/tokenizer.zig+43-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", |
| ... | ... | @@ -403,6 +405,7 @@ pub const Tokenizer = struct { |
| 403 | 405 | angle_bracket_angle_bracket_right, |
| 404 | 406 | period, |
| 405 | 407 | period_2, |
| 408 | period_asterisk, | |
| 406 | 409 | saw_at_sign, |
| 407 | 410 | }; |
| 408 | 411 | |
| ... | ... | @@ -979,9 +982,7 @@ pub const Tokenizer = struct { |
| 979 | 982 | state = .period_2; |
| 980 | 983 | }, |
| 981 | 984 | '*' => { |
| 982 | result.id = .PeriodAsterisk; | |
| 983 | self.index += 1; | |
| 984 | break; | |
| 985 | state = .period_asterisk; | |
| 985 | 986 | }, |
| 986 | 987 | else => { |
| 987 | 988 | result.id = .Period; |
| ... | ... | @@ -1001,6 +1002,17 @@ pub const Tokenizer = struct { |
| 1001 | 1002 | }, |
| 1002 | 1003 | }, |
| 1003 | 1004 | |
| 1005 | .period_asterisk => switch (c) { | |
| 1006 | '*' => { | |
| 1007 | result.id = .Invalid_periodasterisks; | |
| 1008 | break; | |
| 1009 | }, | |
| 1010 | else => { | |
| 1011 | result.id = .PeriodAsterisk; | |
| 1012 | break; | |
| 1013 | }, | |
| 1014 | }, | |
| 1015 | ||
| 1004 | 1016 | .slash => switch (c) { |
| 1005 | 1017 | '/' => { |
| 1006 | 1018 | state = .line_comment_start; |
| ... | ... | @@ -1376,6 +1388,9 @@ pub const Tokenizer = struct { |
| 1376 | 1388 | .period_2 => { |
| 1377 | 1389 | result.id = .Ellipsis2; |
| 1378 | 1390 | }, |
| 1391 | .period_asterisk => { | |
| 1392 | result.id = .PeriodAsterisk; | |
| 1393 | }, | |
| 1379 | 1394 | .pipe => { |
| 1380 | 1395 | result.id = .Pipe; |
| 1381 | 1396 | }, |
| ... | ... | @@ -1762,6 +1777,31 @@ test "correctly parse pointer assignment" { |
| 1762 | 1777 | }); |
| 1763 | 1778 | } |
| 1764 | 1779 | |
| 1780 | test "correctly parse pointer dereference followed by asterisk" { | |
| 1781 | testTokenize("\"b\".* ** 10", &[_]Token.Id{ | |
| 1782 | .StringLiteral, | |
| 1783 | .PeriodAsterisk, | |
| 1784 | .AsteriskAsterisk, | |
| 1785 | .IntegerLiteral, | |
| 1786 | }); | |
| 1787 | ||
| 1788 | testTokenize("(\"b\".*)** 10", &[_]Token.Id{ | |
| 1789 | .LParen, | |
| 1790 | .StringLiteral, | |
| 1791 | .PeriodAsterisk, | |
| 1792 | .RParen, | |
| 1793 | .AsteriskAsterisk, | |
| 1794 | .IntegerLiteral, | |
| 1795 | }); | |
| 1796 | ||
| 1797 | testTokenize("\"b\".*** 10", &[_]Token.Id{ | |
| 1798 | .StringLiteral, | |
| 1799 | .Invalid_periodasterisks, | |
| 1800 | .AsteriskAsterisk, | |
| 1801 | .IntegerLiteral, | |
| 1802 | }); | |
| 1803 | } | |
| 1804 | ||
| 1765 | 1805 | test "tokenizer - range literals" { |
| 1766 | 1806 | testTokenize("0...9", &[_]Token.Id{ .IntegerLiteral, .Ellipsis3, .IntegerLiteral }); |
| 1767 | 1807 | testTokenize("'0'...'9'", &[_]Token.Id{ .CharLiteral, .Ellipsis3, .CharLiteral }); |
src/stage1/tokenizer.cpp+15-2| ... | ... | @@ -223,6 +223,7 @@ enum TokenizeState { |
| 223 | 223 | TokenizeStateSawGreaterThanGreaterThan, |
| 224 | 224 | TokenizeStateSawDot, |
| 225 | 225 | TokenizeStateSawDotDot, |
| 226 | TokenizeStateSawDotStar, | |
| 226 | 227 | TokenizeStateSawAtSign, |
| 227 | 228 | TokenizeStateCharCode, |
| 228 | 229 | TokenizeStateError, |
| ... | ... | @@ -566,9 +567,8 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 566 | 567 | set_token_id(&t, t.cur_tok, TokenIdEllipsis2); |
| 567 | 568 | break; |
| 568 | 569 | case '*': |
| 569 | t.state = TokenizeStateStart; | |
| 570 | t.state = TokenizeStateSawDotStar; | |
| 570 | 571 | set_token_id(&t, t.cur_tok, TokenIdDotStar); |
| 571 | end_token(&t); | |
| 572 | 572 | break; |
| 573 | 573 | default: |
| 574 | 574 | t.pos -= 1; |
| ... | ... | @@ -591,6 +591,18 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 591 | 591 | continue; |
| 592 | 592 | } |
| 593 | 593 | break; |
| 594 | case TokenizeStateSawDotStar: | |
| 595 | switch (c) { | |
| 596 | case '*': | |
| 597 | tokenize_error(&t, "`.*` can't be followed by `*`. Are you missing a space?"); | |
| 598 | break; | |
| 599 | default: | |
| 600 | t.pos -= 1; | |
| 601 | end_token(&t); | |
| 602 | t.state = TokenizeStateStart; | |
| 603 | continue; | |
| 604 | } | |
| 605 | break; | |
| 594 | 606 | case TokenizeStateSawGreaterThan: |
| 595 | 607 | switch (c) { |
| 596 | 608 | case '=': |
| ... | ... | @@ -1481,6 +1493,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1481 | 1493 | case TokenizeStateSawGreaterThan: |
| 1482 | 1494 | case TokenizeStateSawGreaterThanGreaterThan: |
| 1483 | 1495 | case TokenizeStateSawDot: |
| 1496 | case TokenizeStateSawDotStar: | |
| 1484 | 1497 | case TokenizeStateSawAtSign: |
| 1485 | 1498 | case TokenizeStateSawStarPercent: |
| 1486 | 1499 | case TokenizeStateSawPlusPercent: |
test/compile_errors.zig+8| ... | ... | @@ -8210,4 +8210,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 8210 | 8210 | , &[_][]const u8{ |
| 8211 | 8211 | "tmp.zig:4:9: error: expected type '*c_void', found '?*c_void'", |
| 8212 | 8212 | }); |
| 8213 | ||
| 8214 | cases.add("Issue #6823: don't allow .* to be followed by **", | |
| 8215 | \\fn foo() void { | |
| 8216 | \\ var sequence = "repeat".*** 10; | |
| 8217 | \\} | |
| 8218 | , &[_][]const u8{ | |
| 8219 | "tmp.zig:2:30: error: `.*` can't be followed by `*`. Are you missing a space?", | |
| 8220 | }); | |
| 8213 | 8221 | } |