Commit 22e6bfca96

Andrew Kelley <superjoe30@gmail.com>
2017-03-26 10:30:46
add comptime top level declaration
closes #255
1 parent 9ae426a
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
 
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;
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<ErrorTableEntry>(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<TldCompTime>(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;
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;
         }
     }
 }
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:
         {
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<AstNode *> *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);
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");
+}