authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-12-03 10:10:33-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-12-03 10:10:33-07:00
logcb69cb0f26bb496bb0899da7f98767b2de025296
treef3eb4daba44517951610cf888056f1c352baa59e
parentf8ca6c70c74db6e6f0d4462aa763adb6f1f41c7e

analysis for variable declaration, but not variable reference


2 files changed, 90 insertions(+), 15 deletions(-)

src/analyze.cpp+75-15
...@@ -11,12 +11,6 @@...@@ -11,12 +11,6 @@
11#include "zig_llvm.hpp"11#include "zig_llvm.hpp"
12#include "os.hpp"12#include "os.hpp"
1313
14struct BlockContext {
15 AstNode *node;
16 BlockContext *root;
17 BlockContext *parent;
18};
19
20void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {14void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
21 ErrorMsg *err = allocate<ErrorMsg>(1);15 ErrorMsg *err = allocate<ErrorMsg>(1);
22 err->line_start = node->line;16 err->line_start = node->line;
...@@ -75,6 +69,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool...@@ -75,6 +69,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
75}69}
7670
77static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {71static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
72 assert(node->type == NodeTypeType);
78 assert(!node->codegen_node);73 assert(!node->codegen_node);
79 node->codegen_node = allocate<CodeGenNode>(1);74 node->codegen_node = allocate<CodeGenNode>(1);
80 TypeNode *type_node = &node->codegen_node->data.type_node;75 TypeNode *type_node = &node->codegen_node->data.type_node;
...@@ -353,6 +348,30 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *...@@ -353,6 +348,30 @@ static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *
353 add_node_error(g, node, buf_sprintf("type mismatch. expected %s. got %s", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));348 add_node_error(g, node, buf_sprintf("type mismatch. expected %s. got %s", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
354}349}
355350
351static BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
352 BlockContext *context = allocate<BlockContext>(1);
353 context->node = node;
354 context->parent = parent;
355 if (parent != nullptr)
356 context->root = parent->root;
357 else
358 context->root = context;
359 context->variable_table.init(8);
360 return context;
361}
362
363static LocalVariableTableEntry *find_local_variable(BlockContext *context, Buf *name) {
364 while (true) {
365 auto entry = context->variable_table.maybe_get(name);
366 if (entry != nullptr)
367 return entry->value;
368
369 context = context->parent;
370 if (context == nullptr)
371 return nullptr;
372 }
373}
374
356static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,375static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
357 TypeTableEntry *expected_type, AstNode *node)376 TypeTableEntry *expected_type, AstNode *node)
358{377{
...@@ -360,7 +379,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -360,7 +379,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
360 switch (node->type) {379 switch (node->type) {
361 case NodeTypeBlock:380 case NodeTypeBlock:
362 {381 {
363 // TODO: nested block scopes382 BlockContext *child_context = new_block_context(node, context);
364 return_type = g->builtin_types.entry_void;383 return_type = g->builtin_types.entry_void;
365 for (int i = 0; i < node->data.block.statements.length; i += 1) {384 for (int i = 0; i < node->data.block.statements.length; i += 1) {
366 AstNode *child = node->data.block.statements.at(i);385 AstNode *child = node->data.block.statements.at(i);
...@@ -375,7 +394,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -375,7 +394,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
375 add_node_error(g, child, buf_sprintf("unreachable code"));394 add_node_error(g, child, buf_sprintf("unreachable code"));
376 break;395 break;
377 }396 }
378 return_type = analyze_expression(g, import, context, nullptr, child);397 return_type = analyze_expression(g, import, child_context, nullptr, child);
379 }398 }
380 break;399 break;
381 }400 }
...@@ -402,8 +421,27 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -402,8 +421,27 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
402 }421 }
403 case NodeTypeVariableDeclaration:422 case NodeTypeVariableDeclaration:
404 {423 {
405 zig_panic("TODO: analyze variable declaration");424 AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;;
425
426 TypeTableEntry *explicit_type = variable_declaration->type != nullptr ?
427 resolve_type(g, variable_declaration->type) : nullptr;
428
429 TypeTableEntry *implicit_type = variable_declaration->expr != nullptr ?
430 analyze_expression(g, import, context, explicit_type, variable_declaration->expr) : nullptr;
431
432 TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type;
433 assert(type != nullptr); // should have been caught by the parser
406434
435 LocalVariableTableEntry *existing_variable = find_local_variable(context, &variable_declaration->symbol);
436 if (existing_variable) {
437 add_node_error(g, node, buf_sprintf("redeclaration of variable '%s'.",
438 buf_ptr(&variable_declaration->symbol)));
439 } else {
440 LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1);
441 buf_init_from_buf(&variable_entry->name, &variable_declaration->symbol);
442 variable_entry->type = type;
443 context->variable_table.put(&variable_entry->name, variable_entry);
444 }
407 return_type = g->builtin_types.entry_void;445 return_type = g->builtin_types.entry_void;
408 break;446 break;
409 }447 }
...@@ -641,6 +679,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -641,6 +679,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
641 node->codegen_node = allocate<CodeGenNode>(1);679 node->codegen_node = allocate<CodeGenNode>(1);
642 }680 }
643 node->codegen_node->expr_node.type_entry = return_type;681 node->codegen_node->expr_node.type_entry = return_type;
682 node->codegen_node->expr_node.block_context = context;
644683
645 return return_type;684 return return_type;
646}685}
...@@ -658,19 +697,40 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,...@@ -658,19 +697,40 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
658 AstNode *fn_proto_node = node->data.fn_def.fn_proto;697 AstNode *fn_proto_node = node->data.fn_def.fn_proto;
659 assert(fn_proto_node->type == NodeTypeFnProto);698 assert(fn_proto_node->type == NodeTypeFnProto);
660699
700 BlockContext *context = new_block_context(node, nullptr);
701
661 AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;702 AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
662 for (int i = 0; i < fn_proto->params.length; i += 1) {703 for (int i = 0; i < fn_proto->params.length; i += 1) {
663 AstNode *param_decl_node = fn_proto->params.at(i);704 AstNode *param_decl_node = fn_proto->params.at(i);
664 assert(param_decl_node->type == NodeTypeParamDecl);705 assert(param_decl_node->type == NodeTypeParamDecl);
665 // TODO: define local variables for parameters706
707 // define local variables for parameters
708 AstNodeParamDecl *param_decl = &param_decl_node->data.param_decl;
709 assert(param_decl->type->type == NodeTypeType);
710 TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry;
711
712 LocalVariableTableEntry *variable_entry = allocate<LocalVariableTableEntry>(1);
713 buf_init_from_buf(&variable_entry->name, &param_decl->name);
714 variable_entry->type = type;
715
716 LocalVariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name);
717 if (!existing_entry) {
718 // unique definition
719 context->variable_table.put(&variable_entry->name, variable_entry);
720 } else {
721 add_node_error(g, node, buf_sprintf("redeclaration of parameter '%s'.",
722 buf_ptr(&existing_entry->name)));
723 if (existing_entry->type == variable_entry->type) {
724 // types agree, so the type is probably good enough for the rest of analysis
725 } else {
726 // types disagree. don't trust either one of them.
727 existing_entry->type = g->builtin_types.entry_invalid;;
728 }
729 }
666 }730 }
667731
668 BlockContext context;
669 context.node = node;
670 context.root = &context;
671 context.parent = nullptr;
672 TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry;732 TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry;
673 TypeTableEntry *block_return_type = analyze_expression(g, import, &context, expected_type, node->data.fn_def.body);733 TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body);
674734
675 node->codegen_node = allocate<CodeGenNode>(1);735 node->codegen_node = allocate<CodeGenNode>(1);
676 node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type;736 node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type;
src/semantic_info.hpp+15
...@@ -117,6 +117,18 @@ struct CodeGen {...@@ -117,6 +117,18 @@ struct CodeGen {
117 ImportTableEntry *root_import;117 ImportTableEntry *root_import;
118};118};
119119
120struct LocalVariableTableEntry {
121 Buf name;
122 TypeTableEntry *type;
123};
124
125struct BlockContext {
126 AstNode *node; // either NodeTypeFnDef or NodeTypeBlock
127 BlockContext *root; // always points to the BlockContext with the NodeTypeFnDef
128 BlockContext *parent; // nullptr when this is the root
129 HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
130};
131
120struct TypeNode {132struct TypeNode {
121 TypeTableEntry *entry;133 TypeTableEntry *entry;
122};134};
...@@ -133,6 +145,9 @@ struct FnDefNode {...@@ -133,6 +145,9 @@ struct FnDefNode {
133145
134struct ExprNode {146struct ExprNode {
135 TypeTableEntry *type_entry;147 TypeTableEntry *type_entry;
148 // the context in which this expression is evaluated.
149 // for blocks, this points to the containing scope, not the block's own scope for its children.
150 BlockContext *block_context;
136};151};
137152
138struct CodeGenNode {153struct CodeGenNode {