| ... | @@ -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" |
| 13 | | 13 | |
| 14 | struct BlockContext { | | |
| 15 | AstNode *node; | | |
| 16 | BlockContext *root; | | |
| 17 | BlockContext *parent; | | |
| 18 | }; | | |
| 19 | | | |
| 20 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { | 14 | void 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 | } |
| 76 | | 70 | |
| 77 | static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { | 71 | static 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 | } |
| 355 | | 350 | |
| | 351 | static 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 | |
| | 363 | static 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 | |
| 356 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 375 | static 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 scopes | 382 | 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 |
| 406 | | 434 | |
| | 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; |
| 644 | | 683 | |
| 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); |
| 660 | | 699 | |
| | 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 parameters | 706 | |
| | 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 | } |
| 667 | | 731 | |
| 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); |
| 674 | | 734 | |
| 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; |