Commit 52e19b4a9b

Andrew Kelley <superjoe30@gmail.com>
2015-12-15 06:01:39
analyze: BlockContext has concept of module scope
1 parent 3049410
doc/langref.md
@@ -32,7 +32,9 @@ zig          |        C equivalent    | Description
 ```
 Root : many(TopLevelDecl) token(EOF)
 
-TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl
+TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration
+
+VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
 
 StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace)
 
src/analyze.cpp
@@ -445,6 +445,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
                 break;
             }
         case NodeTypeUse:
+        case NodeTypeVariableDeclaration:
             // nothing to do here
             break;
         case NodeTypeDirective:
@@ -453,7 +454,6 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
         case NodeTypeType:
         case NodeTypeFnDecl:
         case NodeTypeReturnExpr:
-        case NodeTypeVariableDeclaration:
         case NodeTypeRoot:
         case NodeTypeBlock:
         case NodeTypeBinOpExpr:
@@ -505,6 +505,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
         case NodeTypeFnDef:
         case NodeTypeRootExportDecl:
         case NodeTypeUse:
+        case NodeTypeVariableDeclaration:
             // nothing to do
             break;
         case NodeTypeDirective:
@@ -513,7 +514,6 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
         case NodeTypeType:
         case NodeTypeFnDecl:
         case NodeTypeReturnExpr:
-        case NodeTypeVariableDeclaration:
         case NodeTypeRoot:
         case NodeTypeBlock:
         case NodeTypeBinOpExpr:
@@ -537,26 +537,20 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
     }
 }
 
-static TypeTableEntry * get_return_type(BlockContext *context) {
-    AstNode *fn_def_node = context->root->node;
-    assert(fn_def_node->type == NodeTypeFnDef);
-    AstNode *fn_proto_node = fn_def_node->data.fn_def.fn_proto;
+static FnTableEntry *get_context_fn_entry(BlockContext *context) {
+    assert(context->fn_entry);
+    return context->fn_entry;
+}
+
+static TypeTableEntry *get_return_type(BlockContext *context) {
+    FnTableEntry *fn_entry = get_context_fn_entry(context);
+    AstNode *fn_proto_node = fn_entry->proto_node;
     assert(fn_proto_node->type == NodeTypeFnProto);
     AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
     assert(return_type_node->codegen_node);
     return return_type_node->codegen_node->data.type_node.entry;
 }
 
-static FnTableEntry *get_context_fn_entry(BlockContext *context) {
-    AstNode *fn_def_node = context->root->node;
-    assert(fn_def_node->type == NodeTypeFnDef);
-    AstNode *fn_proto_node = fn_def_node->data.fn_def.fn_proto;
-    assert(fn_proto_node->type == NodeTypeFnProto);
-    assert(fn_proto_node->codegen_node);
-    assert(fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry);
-    return fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;
-}
-
 static void check_type_compatibility(CodeGen *g, AstNode *node,
         TypeTableEntry *expected_type, TypeTableEntry *actual_type)
 {
@@ -575,21 +569,22 @@ static void check_type_compatibility(CodeGen *g, AstNode *node,
             buf_ptr(&actual_type->name)));
 }
 
-static BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
+BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
     BlockContext *context = allocate<BlockContext>(1);
     context->node = node;
     context->parent = parent;
-    if (parent != nullptr)
-        context->root = parent->root;
-    else
-        context->root = context;
     context->variable_table.init(8);
 
-    AstNode *fn_def_node = context->root->node;
-    assert(fn_def_node->type == NodeTypeFnDef);
-    assert(fn_def_node->codegen_node);
-    FnDefNode *fn_def_info = &fn_def_node->codegen_node->data.fn_def_node;
-    fn_def_info->all_block_contexts.append(context);
+    if (parent) {
+        context->fn_entry = parent->fn_entry;
+    } else if (node && node->type == NodeTypeFnDef) {
+        AstNode *fn_proto_node = node->data.fn_def.fn_proto;
+        context->fn_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;
+    }
+
+    if (context->fn_entry) {
+        context->fn_entry->all_block_contexts.append(context);
+    }
 
     return context;
 }
@@ -1509,13 +1504,15 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
         case NodeTypeStructDecl:
             // nothing to do
             break;
+        case NodeTypeVariableDeclaration:
+            analyze_variable_declaration(g, import, import->block_context, nullptr, node);
+            break;
         case NodeTypeDirective:
         case NodeTypeParamDecl:
         case NodeTypeFnProto:
         case NodeTypeType:
         case NodeTypeFnDecl:
         case NodeTypeReturnExpr:
-        case NodeTypeVariableDeclaration:
         case NodeTypeRoot:
         case NodeTypeBlock:
         case NodeTypeBinOpExpr:
src/analyze.hpp
@@ -90,6 +90,7 @@ struct ImportTableEntry {
     LLVMZigDIFile *di_file;
     Buf *source_code;
     ZigList<int> *line_offsets;
+    BlockContext *block_context;
 
     // reminder: hash tables must be initialized before use
     HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
@@ -116,6 +117,8 @@ struct FnTableEntry {
     unsigned calling_convention;
     ImportTableEntry *import_entry;
     ZigList<FnAttrId> fn_attr_list;
+    // Required to be a pre-order traversal of the AST. (parents must come before children)
+    ZigList<BlockContext *> all_block_contexts;
 
     // reminder: hash tables must be initialized before use
     HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
@@ -201,9 +204,9 @@ struct LocalVariableTableEntry {
 };
 
 struct BlockContext {
-    AstNode *node; // either NodeTypeFnDef or NodeTypeBlock
-    BlockContext *root; // always points to the BlockContext with the NodeTypeFnDef
-    BlockContext *parent; // nullptr when this is the root
+    AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or null for module scope
+    FnTableEntry *fn_entry; // null at the module scope
+    BlockContext *parent; // null when this is the root
     HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
     ZigList<AstNode *> cast_expr_alloca_list;
     LLVMZigDIScope *di_scope;
@@ -221,8 +224,6 @@ struct FnDefNode {
     TypeTableEntry *implicit_return_type;
     BlockContext *block_context;
     bool skip;
-    // Required to be a pre-order traversal of the AST. (parents must come before children)
-    ZigList<BlockContext *> all_block_contexts;
 };
 
 struct ExprNode {
@@ -295,5 +296,6 @@ void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
 TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
 TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
 LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name);
+BlockContext *new_block_context(AstNode *node, BlockContext *parent);
 
 #endif
src/codegen.cpp
@@ -1132,8 +1132,8 @@ static void do_code_gen(CodeGen *g) {
 
         // Set up debug info for blocks and variables and
         // allocate all local variables
-        for (int bc_i = 0; bc_i < codegen_fn_def->all_block_contexts.length; bc_i += 1) {
-            BlockContext *block_context = codegen_fn_def->all_block_contexts.at(bc_i);
+        for (int bc_i = 0; bc_i < fn_table_entry->all_block_contexts.length; bc_i += 1) {
+            BlockContext *block_context = fn_table_entry->all_block_contexts.at(bc_i);
 
             if (block_context->parent) {
                 LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder,
@@ -1530,6 +1530,9 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src
     import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
     g->import_table.put(full_path, import_entry);
 
+    import_entry->block_context = new_block_context(nullptr, nullptr);
+    import_entry->block_context->di_scope = LLVMZigFileToScope(import_entry->di_file);
+
 
     assert(import_entry->root->type == NodeTypeRoot);
     for (int decl_i = 0; decl_i < import_entry->root->data.root.top_level_decls.length; decl_i += 1) {
src/parser.cpp
@@ -2266,7 +2266,7 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
 }
 
 /*
-TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl
+TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration
 */
 static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
     for (;;) {
@@ -2310,6 +2310,13 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
         }
         pc->directive_list = nullptr;
 
+        AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false);
+        if (var_decl_node) {
+            ast_eat_token(pc, token_index, TokenIdSemicolon);
+            top_level_decls->append(var_decl_node);
+            continue;
+        }
+
         return;
     }
     zig_unreachable();