From 22e6bfca9602fdb79f669b494fa7f1c58094706c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 26 Mar 2017 04:30:46 -0400 Subject: [PATCH] add comptime top level declaration closes #255 --- doc/langref.md | 2 +- src/all_types.hpp | 9 +++--- src/analyze.cpp | 33 +++++++++++++------ src/ast_render.cpp | 5 ++- src/ir.cpp | 2 ++ src/parser.cpp | 38 ++++++++++++---------- test/self_hosted.zig | 75 ++++++++++++++++++++++---------------------- 7 files changed, 95 insertions(+), 69 deletions(-) diff --git a/doc/langref.md b/doc/langref.md index cf759ae3f5..68c74bcbf3 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -5,7 +5,7 @@ ``` Root = many(TopLevelItem) "EOF" -TopLevelItem = ErrorValueDecl | Block | TopLevelDecl | TestDecl +TopLevelItem = ErrorValueDecl | CompTimeExpression | TopLevelDecl | TestDecl TestDecl = "test" String Block diff --git a/src/all_types.hpp b/src/all_types.hpp index 5a11c12bba..dc8c345285 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -242,6 +242,7 @@ enum TldId { TldIdFn, TldIdContainer, TldIdTypeDef, + TldIdCompTime, }; enum TldResolution { @@ -293,6 +294,10 @@ struct TldTypeDef { TypeTableEntry *type_entry; }; +struct TldCompTime { + Tld base; +}; + struct TypeEnumField { Buf *name; TypeTableEntry *type_entry; @@ -430,16 +435,12 @@ struct AstNodeTypeDecl { }; struct AstNodeErrorValueDecl { - // always invalid if it's not VisibModPrivate but can be parsed that way - VisibMod visib_mod; Buf *name; ErrorTableEntry *err; }; struct AstNodeTestDecl { - // always invalid if it's not VisibModPrivate but can be parsed that way - VisibMod visib_mod; Buf *name; AstNode *body; diff --git a/src/analyze.cpp b/src/analyze.cpp index bfec62e5de..fca3b1e39f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1924,6 +1924,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { } } +static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { + assert(tld_comptime->base.source_node->type == NodeTypeCompTime); + AstNode *expr_node = tld_comptime->base.source_node->data.comptime_expr.expr; + analyze_const_value(g, tld_comptime->base.parent_scope, expr_node, g->builtin_types.entry_void, nullptr); +} + static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { if (tld->visib_mod == VisibModExport || (buf_eql_str(tld->name, "panic") && @@ -1955,10 +1961,6 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { assert(node->type == NodeTypeTestDecl); - if (node->data.test_decl.visib_mod != VisibModPrivate) { - add_node_error(g, node, buf_sprintf("tests require no visibility modifier")); - } - if (!g->is_test_build) return; @@ -1976,10 +1978,6 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope static void preview_error_value_decl(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeErrorValueDecl); - if (node->data.error_value_decl.visib_mod != VisibModPrivate) { - add_node_error(g, node, buf_sprintf("error values require no visibility modifier")); - } - ErrorTableEntry *err = allocate(1); err->decl_node = node; @@ -2000,6 +1998,15 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) { node->data.error_value_decl.err = err; } +static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) { + assert(node->type == NodeTypeCompTime); + + TldCompTime *tld_comptime = allocate(1); + init_tld(&tld_comptime->base, TldIdCompTime, nullptr, VisibModPrivate, node, &decls_scope->base); + g->resolve_queue.append(&tld_comptime->base); +} + + void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope) { @@ -2069,6 +2076,9 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeTestDecl: preview_test_decl(g, node, decls_scope); break; + case NodeTypeCompTime: + preview_comptime_decl(g, node, decls_scope); + break; case NodeTypeContainerDecl: case NodeTypeParamDecl: case NodeTypeFnDecl: @@ -2098,7 +2108,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeSwitchRange: case NodeTypeLabel: case NodeTypeGoto: - case NodeTypeCompTime: case NodeTypeBreak: case NodeTypeContinue: case NodeTypeAsmExpr: @@ -2357,6 +2366,12 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only) { resolve_decl_typedef(g, tld_typedef); break; } + case TldIdCompTime: + { + TldCompTime *tld_comptime = (TldCompTime *)tld; + resolve_decl_comptime(g, tld_comptime); + break; + } } tld->resolution = TldResolutionOk; diff --git a/src/ast_render.cpp b/src/ast_render.cpp index c10844df46..9f3a1e143f 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -1055,7 +1055,7 @@ void ast_render_decls(FILE *f, int indent_size, ImportTableEntry *import) { Tld *tld = entry->value; - if (!buf_eql_buf(entry->key, tld->name)) { + if (tld->name != nullptr && !buf_eql_buf(entry->key, tld->name)) { fprintf(ar.f, "pub const "); print_symbol(&ar, entry->key); fprintf(ar.f, " = %s;\n", buf_ptr(tld->name)); @@ -1075,6 +1075,9 @@ void ast_render_decls(FILE *f, int indent_size, ImportTableEntry *import) { case TldIdTypeDef: ast_render_tld_typedef(&ar, entry->key, (TldTypeDef *)tld); break; + case TldIdCompTime: + fprintf(stdout, "comptime\n"); + break; } } } diff --git a/src/ir.cpp b/src/ir.cpp index b6a7c08a0e..73b09918fa 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9114,6 +9114,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source switch (tld->id) { case TldIdContainer: + case TldIdCompTime: zig_unreachable(); case TldIdVar: { @@ -12122,6 +12123,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira, switch (tld->id) { case TldIdContainer: + case TldIdCompTime: zig_unreachable(); case TldIdVar: { diff --git a/src/parser.cpp b/src/parser.cpp index 2ae51047e5..56b60e7e56 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2399,7 +2399,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, /* ErrorValueDecl : "error" "Symbol" ";" */ -static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) { +static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index) { Token *first_token = &pc->tokens->at(*token_index); if (first_token->id != TokenIdKeywordError) { @@ -2411,7 +2411,6 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index ast_eat_token(pc, token_index, TokenIdSemicolon); AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token); - node->data.error_value_decl.visib_mod = visib_mod; node->data.error_value_decl.name = token_buf(name_tok); return node; @@ -2420,7 +2419,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index /* TestDecl = "test" String Block */ -static AstNode *ast_parse_test_decl_node(ParseContext *pc, size_t *token_index, VisibMod visib_mod) { +static AstNode *ast_parse_test_decl_node(ParseContext *pc, size_t *token_index) { Token *first_token = &pc->tokens->at(*token_index); if (first_token->id != TokenIdKeywordTest) { @@ -2431,7 +2430,6 @@ static AstNode *ast_parse_test_decl_node(ParseContext *pc, size_t *token_index, Token *name_tok = ast_eat_token(pc, token_index, TokenIdStringLiteral); AstNode *node = ast_create_node(pc, NodeTypeTestDecl, first_token); - node->data.test_decl.visib_mod = visib_mod; node->data.test_decl.name = token_buf(name_tok); node->data.test_decl.body = ast_parse_block(pc, token_index, true); @@ -2464,11 +2462,29 @@ static AstNode *ast_parse_type_decl(ParseContext *pc, size_t *token_index, Visib } /* -TopLevelItem = ErrorValueDecl | Block | TopLevelDecl | TestDecl +TopLevelItem = ErrorValueDecl | CompTimeExpression | TopLevelDecl | TestDecl TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | TypeDecl | UseDecl) */ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList *top_level_decls) { for (;;) { + AstNode *comptime_expr_node = ast_parse_comptime_expr(pc, token_index, false); + if (comptime_expr_node) { + top_level_decls->append(comptime_expr_node); + continue; + } + + AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index); + if (error_value_node) { + top_level_decls->append(error_value_node); + continue; + } + + AstNode *test_decl_node = ast_parse_test_decl_node(pc, token_index); + if (test_decl_node) { + top_level_decls->append(test_decl_node); + continue; + } + Token *visib_tok = &pc->tokens->at(*token_index); VisibMod visib_mod; if (visib_tok->id == TokenIdKeywordPub) { @@ -2506,18 +2522,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig continue; } - AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index, visib_mod); - if (error_value_node) { - top_level_decls->append(error_value_node); - continue; - } - - AstNode *test_decl_node = ast_parse_test_decl_node(pc, token_index, visib_mod); - if (test_decl_node) { - top_level_decls->append(test_decl_node); - continue; - } - AstNode *type_decl_node = ast_parse_type_decl(pc, token_index, visib_mod); if (type_decl_node) { top_level_decls->append(type_decl_node); diff --git a/test/self_hosted.zig b/test/self_hosted.zig index a6888e2ea0..8968e08709 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -1,37 +1,38 @@ -// TODO '_' identifier for unused variable bindings -const test_array = @import("cases/array.zig"); -const test_atomics = @import("cases/atomics.zig"); -const test_bool = @import("cases/bool.zig"); -const test_cast = @import("cases/cast.zig"); -const test_const_slice_child = @import("cases/const_slice_child.zig"); -const test_defer = @import("cases/defer.zig"); -const test_enum = @import("cases/enum.zig"); -const test_enum_with_members = @import("cases/enum_with_members.zig"); -const test_error = @import("cases/error.zig"); -const test_eval = @import("cases/eval.zig"); -const test_fn = @import("cases/fn.zig"); -const test_for = @import("cases/for.zig"); -const test_generics = @import("cases/generics.zig"); -const test_goto = @import("cases/goto.zig"); -const test_if = @import("cases/if.zig"); -const test_import = @import("cases/import.zig"); -const test_incomplete_struct_param_tld = @import("cases/incomplete_struct_param_tld.zig"); -const test_ir_block_deps = @import("cases/ir_block_deps.zig"); -const test_math = @import("cases/math.zig"); -const test_misc = @import("cases/misc.zig"); -const test_namespace_depends_on_compile_var = @import("cases/namespace_depends_on_compile_var/index.zig"); -const test_null = @import("cases/null.zig"); -const test_pub_enum = @import("cases/pub_enum/index.zig"); -const test_sizeof_and_typeof = @import("cases/sizeof_and_typeof.zig"); -const test_struct = @import("cases/struct.zig"); -const test_struct_contains_slice_of_itself = @import("cases/struct_contains_slice_of_itself.zig"); -const test_switch = @import("cases/switch.zig"); -const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig"); -const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig"); -const test_this = @import("cases/this.zig"); -const test_try = @import("cases/try.zig"); -const test_typedef = @import("cases/typedef.zig"); -const test_undefined = @import("cases/undefined.zig"); -const test_var_args = @import("cases/var_args.zig"); -const test_void = @import("cases/void.zig"); -const test_while = @import("cases/while.zig"); +comptime { + _ = @import("cases/array.zig"); + _ = @import("cases/atomics.zig"); + _ = @import("cases/bool.zig"); + _ = @import("cases/cast.zig"); + _ = @import("cases/const_slice_child.zig"); + _ = @import("cases/defer.zig"); + _ = @import("cases/enum.zig"); + _ = @import("cases/enum_with_members.zig"); + _ = @import("cases/error.zig"); + _ = @import("cases/eval.zig"); + _ = @import("cases/fn.zig"); + _ = @import("cases/for.zig"); + _ = @import("cases/generics.zig"); + _ = @import("cases/goto.zig"); + _ = @import("cases/if.zig"); + _ = @import("cases/import.zig"); + _ = @import("cases/incomplete_struct_param_tld.zig"); + _ = @import("cases/ir_block_deps.zig"); + _ = @import("cases/math.zig"); + _ = @import("cases/misc.zig"); + _ = @import("cases/namespace_depends_on_compile_var/index.zig"); + _ = @import("cases/null.zig"); + _ = @import("cases/pub_enum/index.zig"); + _ = @import("cases/sizeof_and_typeof.zig"); + _ = @import("cases/struct.zig"); + _ = @import("cases/struct_contains_slice_of_itself.zig"); + _ = @import("cases/switch.zig"); + _ = @import("cases/switch_prong_err_enum.zig"); + _ = @import("cases/switch_prong_implicit_cast.zig"); + _ = @import("cases/this.zig"); + _ = @import("cases/try.zig"); + _ = @import("cases/typedef.zig"); + _ = @import("cases/undefined.zig"); + _ = @import("cases/var_args.zig"); + _ = @import("cases/void.zig"); + _ = @import("cases/while.zig"); +}