From fff00c3bbb9ed211f46eb1f1be07ebab84bc8d9d Mon Sep 17 00:00:00 2001 From: Vexu Date: Sat, 18 Apr 2020 19:42:45 +0300 Subject: [PATCH] disallow declarations between container fields --- src/parser.cpp | 37 +++++++++++++++++++++++++++++++++++++ test/compile_errors.zig | 15 +++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/parser.cpp b/src/parser.cpp index 20ad179a7..1391393c2 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -526,6 +526,15 @@ static void ast_parse_container_doc_comments(ParseContext *pc, Buf *buf) { } } +enum ContainerFieldState { + // no fields have been seen + ContainerFieldStateNone, + // currently parsing fields + ContainerFieldStateSeen, + // saw fields and then a declaration after them + ContainerFieldStateEnd, +}; + // ContainerMembers // <- TestDecl ContainerMembers // / TopLevelComptime ContainerMembers @@ -537,17 +546,29 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { AstNodeContainerDecl res = {}; Buf tld_doc_comment_buf = BUF_INIT; buf_resize(&tld_doc_comment_buf, 0); + ContainerFieldState field_state = ContainerFieldStateNone; + Token *first_token = nullptr; for (;;) { ast_parse_container_doc_comments(pc, &tld_doc_comment_buf); + Token *peeked_token = peek_token(pc); + AstNode *test_decl = ast_parse_test_decl(pc); if (test_decl != nullptr) { + if (field_state == ContainerFieldStateSeen) { + field_state = ContainerFieldStateEnd; + first_token = peeked_token; + } res.decls.append(test_decl); continue; } AstNode *top_level_comptime = ast_parse_top_level_comptime(pc); if (top_level_comptime != nullptr) { + if (field_state == ContainerFieldStateSeen) { + field_state = ContainerFieldStateEnd; + first_token = peeked_token; + } res.decls.append(top_level_comptime); continue; } @@ -555,11 +576,17 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { Buf doc_comment_buf = BUF_INIT; ast_parse_doc_comments(pc, &doc_comment_buf); + peeked_token = peek_token(pc); + Token *visib_token = eat_token_if(pc, TokenIdKeywordPub); VisibMod visib_mod = visib_token != nullptr ? VisibModPub : VisibModPrivate; AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod, &doc_comment_buf); if (top_level_decl != nullptr) { + if (field_state == ContainerFieldStateSeen) { + field_state = ContainerFieldStateEnd; + first_token = peeked_token; + } res.decls.append(top_level_decl); continue; } @@ -572,6 +599,16 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { AstNode *container_field = ast_parse_container_field(pc); if (container_field != nullptr) { + switch (field_state) { + case ContainerFieldStateNone: + field_state = ContainerFieldStateSeen; + break; + case ContainerFieldStateSeen: + break; + case ContainerFieldStateEnd: + ast_error(pc, first_token, "declarations are not allowed between container fields"); + } + assert(container_field->type == NodeTypeStructField); container_field->data.struct_field.doc_comments = doc_comment_buf; container_field->data.struct_field.comptime_token = comptime_token; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index dfbb82edc..6c120330e 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,21 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add("declaration between fields", + \\const S = struct { + \\ a: usize, + \\ const foo = 2; + \\ const bar = 2; + \\ const baz = 2; + \\ b: usize, + \\}; + \\comptime { + \\ _ = S; + \\} + , &[_][]const u8{ + "tmp.zig:3:5: error: declarations are not allowed between container fields", + }); + cases.add("non-extern function with var args", \\fn foo(args: ...) void {} \\export fn entry() void {