Merge pull request #6858 from travv0/no-star-after-dot-star

don't allow a token starting with an asterisk directly following .*
This commit is contained in:
Veikka Tuominen
2020-10-30 16:08:04 +02:00
committed by GitHub
7 changed files with 102 additions and 6 deletions

View File

@@ -972,7 +972,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: anytype, source_token:
.Tilde,
=> try writeEscaped(out, src[token.loc.start..token.loc.end]),
.Invalid, .Invalid_ampersands => return parseError(
.Invalid, .Invalid_ampersands, .Invalid_periodasterisks => return parseError(
docgen_tokenizer,
source_token,
"syntax error",

View File

@@ -171,6 +171,7 @@ pub const Error = union(enum) {
ExpectedBlockOrField: ExpectedBlockOrField,
DeclBetweenFields: DeclBetweenFields,
InvalidAnd: InvalidAnd,
AsteriskAfterPointerDereference: AsteriskAfterPointerDereference,
pub fn render(self: *const Error, tokens: []const Token.Id, stream: anytype) !void {
switch (self.*) {
@@ -222,6 +223,7 @@ pub const Error = union(enum) {
.ExpectedBlockOrField => |*x| return x.render(tokens, stream),
.DeclBetweenFields => |*x| return x.render(tokens, stream),
.InvalidAnd => |*x| return x.render(tokens, stream),
.AsteriskAfterPointerDereference => |*x| return x.render(tokens, stream),
}
}
@@ -275,6 +277,7 @@ pub const Error = union(enum) {
.ExpectedBlockOrField => |x| return x.token,
.DeclBetweenFields => |x| return x.token,
.InvalidAnd => |x| return x.token,
.AsteriskAfterPointerDereference => |x| return x.token,
}
}
@@ -323,6 +326,7 @@ pub const Error = union(enum) {
pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier");
pub const DeclBetweenFields = SimpleError("Declarations are not allowed between container fields");
pub const InvalidAnd = SimpleError("`&&` is invalid. Note that `and` is boolean AND.");
pub const AsteriskAfterPointerDereference = SimpleError("`.*` can't be followed by `*`. Are you missing a space?");
pub const ExpectedCall = struct {
node: *Node,

View File

@@ -2701,6 +2701,19 @@ const Parser = struct {
return &node.base;
}
if (p.eatToken(.Invalid_periodasterisks)) |period_asterisk| {
try p.errors.append(p.gpa, .{
.AsteriskAfterPointerDereference = .{ .token = period_asterisk },
});
const node = try p.arena.allocator.create(Node.SimpleSuffixOp);
node.* = .{
.base = .{ .tag = .Deref },
.lhs = lhs,
.rtoken = period_asterisk,
};
return &node.base;
}
if (p.eatToken(.Period)) |period| {
if (try p.parseIdentifier()) |identifier| {
const node = try p.arena.allocator.create(Node.SimpleInfixOp);

View File

@@ -219,6 +219,24 @@ test "recovery: invalid global error set access" {
});
}
test "recovery: invalid asterisk after pointer dereference" {
try testError(
\\test "" {
\\ var sequence = "repeat".*** 10;
\\}
, &[_]Error{
.AsteriskAfterPointerDereference,
});
try testError(
\\test "" {
\\ var sequence = "repeat".** 10&&a;
\\}
, &[_]Error{
.AsteriskAfterPointerDereference,
.InvalidAnd,
});
}
test "recovery: missing semicolon after if, for, while stmt" {
try testError(
\\test "" {

View File

@@ -78,6 +78,7 @@ pub const Token = struct {
pub const Id = enum {
Invalid,
Invalid_ampersands,
Invalid_periodasterisks,
Identifier,
StringLiteral,
MultilineStringLiteralLine,
@@ -201,6 +202,7 @@ pub const Token = struct {
return switch (id) {
.Invalid => "Invalid",
.Invalid_ampersands => "&&",
.Invalid_periodasterisks => ".**",
.Identifier => "Identifier",
.StringLiteral => "StringLiteral",
.MultilineStringLiteralLine => "MultilineStringLiteralLine",
@@ -403,6 +405,7 @@ pub const Tokenizer = struct {
angle_bracket_angle_bracket_right,
period,
period_2,
period_asterisk,
saw_at_sign,
};
@@ -979,9 +982,7 @@ pub const Tokenizer = struct {
state = .period_2;
},
'*' => {
result.id = .PeriodAsterisk;
self.index += 1;
break;
state = .period_asterisk;
},
else => {
result.id = .Period;
@@ -1001,6 +1002,17 @@ pub const Tokenizer = struct {
},
},
.period_asterisk => switch (c) {
'*' => {
result.id = .Invalid_periodasterisks;
break;
},
else => {
result.id = .PeriodAsterisk;
break;
},
},
.slash => switch (c) {
'/' => {
state = .line_comment_start;
@@ -1376,6 +1388,9 @@ pub const Tokenizer = struct {
.period_2 => {
result.id = .Ellipsis2;
},
.period_asterisk => {
result.id = .PeriodAsterisk;
},
.pipe => {
result.id = .Pipe;
},
@@ -1762,6 +1777,31 @@ test "correctly parse pointer assignment" {
});
}
test "correctly parse pointer dereference followed by asterisk" {
testTokenize("\"b\".* ** 10", &[_]Token.Id{
.StringLiteral,
.PeriodAsterisk,
.AsteriskAsterisk,
.IntegerLiteral,
});
testTokenize("(\"b\".*)** 10", &[_]Token.Id{
.LParen,
.StringLiteral,
.PeriodAsterisk,
.RParen,
.AsteriskAsterisk,
.IntegerLiteral,
});
testTokenize("\"b\".*** 10", &[_]Token.Id{
.StringLiteral,
.Invalid_periodasterisks,
.AsteriskAsterisk,
.IntegerLiteral,
});
}
test "tokenizer - range literals" {
testTokenize("0...9", &[_]Token.Id{ .IntegerLiteral, .Ellipsis3, .IntegerLiteral });
testTokenize("'0'...'9'", &[_]Token.Id{ .CharLiteral, .Ellipsis3, .CharLiteral });

View File

@@ -223,6 +223,7 @@ enum TokenizeState {
TokenizeStateSawGreaterThanGreaterThan,
TokenizeStateSawDot,
TokenizeStateSawDotDot,
TokenizeStateSawDotStar,
TokenizeStateSawAtSign,
TokenizeStateCharCode,
TokenizeStateError,
@@ -566,9 +567,8 @@ void tokenize(Buf *buf, Tokenization *out) {
set_token_id(&t, t.cur_tok, TokenIdEllipsis2);
break;
case '*':
t.state = TokenizeStateStart;
t.state = TokenizeStateSawDotStar;
set_token_id(&t, t.cur_tok, TokenIdDotStar);
end_token(&t);
break;
default:
t.pos -= 1;
@@ -591,6 +591,18 @@ void tokenize(Buf *buf, Tokenization *out) {
continue;
}
break;
case TokenizeStateSawDotStar:
switch (c) {
case '*':
tokenize_error(&t, "`.*` can't be followed by `*`. Are you missing a space?");
break;
default:
t.pos -= 1;
end_token(&t);
t.state = TokenizeStateStart;
continue;
}
break;
case TokenizeStateSawGreaterThan:
switch (c) {
case '=':
@@ -1481,6 +1493,7 @@ void tokenize(Buf *buf, Tokenization *out) {
case TokenizeStateSawGreaterThan:
case TokenizeStateSawGreaterThanGreaterThan:
case TokenizeStateSawDot:
case TokenizeStateSawDotStar:
case TokenizeStateSawAtSign:
case TokenizeStateSawStarPercent:
case TokenizeStateSawPlusPercent:

View File

@@ -8210,4 +8210,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
, &[_][]const u8{
"tmp.zig:4:9: error: expected type '*c_void', found '?*c_void'",
});
cases.add("Issue #6823: don't allow .* to be followed by **",
\\fn foo() void {
\\ var sequence = "repeat".*** 10;
\\}
, &[_][]const u8{
"tmp.zig:2:30: error: `.*` can't be followed by `*`. Are you missing a space?",
});
}