| ... | @@ -106,6 +106,11 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { | ... | @@ -106,6 +106,11 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { |
| 106 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | 106 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); |
| 107 | entry->arrays_by_size.init(2); | 107 | entry->arrays_by_size.init(2); |
| 108 | entry->id = id; | 108 | entry->id = id; |
| | 109 | |
| | 110 | if (id == TypeTableEntryIdStruct) { |
| | 111 | entry->data.structure.fn_table.init(8); |
| | 112 | } |
| | 113 | |
| 109 | return entry; | 114 | return entry; |
| 110 | } | 115 | } |
| 111 | | 116 | |
| ... | @@ -461,6 +466,68 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE | ... | @@ -461,6 +466,68 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE |
| 461 | struct_type->di_type = replacement_di_type; | 466 | struct_type->di_type = replacement_di_type; |
| 462 | } | 467 | } |
| 463 | | 468 | |
| | 469 | static void preview_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node, TypeTableEntry *struct_type) { |
| | 470 | assert(node->type == NodeTypeFnDef); |
| | 471 | AstNode *proto_node = node->data.fn_def.fn_proto; |
| | 472 | assert(proto_node->type == NodeTypeFnProto); |
| | 473 | Buf *proto_name = &proto_node->data.fn_proto.name; |
| | 474 | |
| | 475 | auto fn_table = struct_type ? &struct_type->data.structure.fn_table : &import->fn_table; |
| | 476 | |
| | 477 | auto entry = fn_table->maybe_get(proto_name); |
| | 478 | bool skip = false; |
| | 479 | bool is_internal = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport); |
| | 480 | bool is_pub = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModPrivate); |
| | 481 | if (entry) { |
| | 482 | add_node_error(g, node, |
| | 483 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| | 484 | alloc_codegen_node(node); |
| | 485 | node->codegen_node->data.fn_def_node.skip = true; |
| | 486 | skip = true; |
| | 487 | } else if (is_pub) { |
| | 488 | auto entry = fn_table->maybe_get(proto_name); |
| | 489 | if (entry) { |
| | 490 | add_node_error(g, node, |
| | 491 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| | 492 | alloc_codegen_node(node); |
| | 493 | node->codegen_node->data.fn_def_node.skip = true; |
| | 494 | skip = true; |
| | 495 | } |
| | 496 | } |
| | 497 | if (proto_node->data.fn_proto.is_var_args) { |
| | 498 | add_node_error(g, node, |
| | 499 | buf_sprintf("variadic arguments only allowed in extern functions")); |
| | 500 | } |
| | 501 | if (!skip) { |
| | 502 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); |
| | 503 | fn_table_entry->import_entry = import; |
| | 504 | fn_table_entry->proto_node = proto_node; |
| | 505 | fn_table_entry->fn_def_node = node; |
| | 506 | fn_table_entry->internal_linkage = is_internal; |
| | 507 | fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv; |
| | 508 | fn_table_entry->label_table.init(8); |
| | 509 | |
| | 510 | g->fn_protos.append(fn_table_entry); |
| | 511 | g->fn_defs.append(fn_table_entry); |
| | 512 | |
| | 513 | fn_table->put(proto_name, fn_table_entry); |
| | 514 | |
| | 515 | if (!struct_type && |
| | 516 | g->bootstrap_import && |
| | 517 | import == g->root_import && buf_eql_str(proto_name, "main")) |
| | 518 | { |
| | 519 | g->bootstrap_import->fn_table.put(proto_name, fn_table_entry); |
| | 520 | } |
| | 521 | |
| | 522 | resolve_function_proto(g, proto_node, fn_table_entry, import); |
| | 523 | |
| | 524 | |
| | 525 | alloc_codegen_node(proto_node); |
| | 526 | proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; |
| | 527 | |
| | 528 | preview_function_labels(g, node->data.fn_def.body, fn_table_entry); |
| | 529 | } |
| | 530 | } |
| 464 | | 531 | |
| 465 | static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) { | 532 | static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 466 | switch (node->type) { | 533 | switch (node->type) { |
| ... | @@ -500,61 +567,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, | ... | @@ -500,61 +567,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 500 | } | 567 | } |
| 501 | break; | 568 | break; |
| 502 | case NodeTypeFnDef: | 569 | case NodeTypeFnDef: |
| 503 | { | 570 | preview_fn_def(g, import, node, nullptr); |
| 504 | AstNode *proto_node = node->data.fn_def.fn_proto; | | |
| 505 | assert(proto_node->type == NodeTypeFnProto); | | |
| 506 | Buf *proto_name = &proto_node->data.fn_proto.name; | | |
| 507 | auto entry = import->fn_table.maybe_get(proto_name); | | |
| 508 | bool skip = false; | | |
| 509 | bool is_internal = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport); | | |
| 510 | bool is_pub = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModPrivate); | | |
| 511 | if (entry) { | | |
| 512 | add_node_error(g, node, | | |
| 513 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); | | |
| 514 | alloc_codegen_node(node); | | |
| 515 | node->codegen_node->data.fn_def_node.skip = true; | | |
| 516 | skip = true; | | |
| 517 | } else if (is_pub) { | | |
| 518 | auto entry = import->fn_table.maybe_get(proto_name); | | |
| 519 | if (entry) { | | |
| 520 | add_node_error(g, node, | | |
| 521 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); | | |
| 522 | alloc_codegen_node(node); | | |
| 523 | node->codegen_node->data.fn_def_node.skip = true; | | |
| 524 | skip = true; | | |
| 525 | } | | |
| 526 | } | | |
| 527 | if (proto_node->data.fn_proto.is_var_args) { | | |
| 528 | add_node_error(g, node, | | |
| 529 | buf_sprintf("variadic arguments only allowed in extern functions")); | | |
| 530 | } | | |
| 531 | if (!skip) { | | |
| 532 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); | | |
| 533 | fn_table_entry->import_entry = import; | | |
| 534 | fn_table_entry->proto_node = proto_node; | | |
| 535 | fn_table_entry->fn_def_node = node; | | |
| 536 | fn_table_entry->internal_linkage = is_internal; | | |
| 537 | fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv; | | |
| 538 | fn_table_entry->label_table.init(8); | | |
| 539 | | | |
| 540 | g->fn_protos.append(fn_table_entry); | | |
| 541 | g->fn_defs.append(fn_table_entry); | | |
| 542 | | | |
| 543 | import->fn_table.put(proto_name, fn_table_entry); | | |
| 544 | | | |
| 545 | if (g->bootstrap_import && import == g->root_import && buf_eql_str(proto_name, "main")) { | | |
| 546 | g->bootstrap_import->fn_table.put(proto_name, fn_table_entry); | | |
| 547 | } | | |
| 548 | | | |
| 549 | resolve_function_proto(g, proto_node, fn_table_entry, import); | | |
| 550 | | | |
| 551 | | | |
| 552 | alloc_codegen_node(proto_node); | | |
| 553 | proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; | | |
| 554 | | | |
| 555 | preview_function_labels(g, node->data.fn_def.body, fn_table_entry); | | |
| 556 | } | | |
| 557 | } | | |
| 558 | break; | 571 | break; |
| 559 | case NodeTypeRootExportDecl: | 572 | case NodeTypeRootExportDecl: |
| 560 | if (import == g->root_import) { | 573 | if (import == g->root_import) { |
| ... | @@ -605,6 +618,11 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, | ... | @@ -605,6 +618,11 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 605 | TypeTableEntry *type_entry = struct_codegen->type_entry; | 618 | TypeTableEntry *type_entry = struct_codegen->type_entry; |
| 606 | | 619 | |
| 607 | resolve_struct_type(g, import, type_entry); | 620 | resolve_struct_type(g, import, type_entry); |
| | 621 | |
| | 622 | for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) { |
| | 623 | AstNode *fn_def_node = node->data.struct_decl.fns.at(i); |
| | 624 | preview_fn_def(g, import, fn_def_node, type_entry); |
| | 625 | } |
| 608 | break; | 626 | break; |
| 609 | } | 627 | } |
| 610 | case NodeTypeUse: | 628 | case NodeTypeUse: |
| ... | @@ -1624,6 +1642,94 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im | ... | @@ -1624,6 +1642,94 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im |
| 1624 | } | 1642 | } |
| 1625 | } | 1643 | } |
| 1626 | | 1644 | |
| | 1645 | static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| | 1646 | TypeTableEntry *expected_type, AstNode *node) |
| | 1647 | { |
| | 1648 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; |
| | 1649 | TypeTableEntry *struct_type = nullptr; |
| | 1650 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> *fn_table = &import->fn_table; |
| | 1651 | AstNode *first_param_expr = nullptr; |
| | 1652 | Buf *name; |
| | 1653 | |
| | 1654 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr) { |
| | 1655 | first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr; |
| | 1656 | struct_type = analyze_expression(g, import, context, nullptr, first_param_expr); |
| | 1657 | name = &fn_ref_expr->data.field_access_expr.field_name; |
| | 1658 | if (struct_type->id == TypeTableEntryIdStruct) { |
| | 1659 | fn_table = &struct_type->data.structure.fn_table; |
| | 1660 | } else if (struct_type->id == TypeTableEntryIdInvalid) { |
| | 1661 | return struct_type; |
| | 1662 | } else { |
| | 1663 | add_node_error(g, fn_ref_expr->data.field_access_expr.struct_expr, |
| | 1664 | buf_sprintf("member reference base type not struct or enum")); |
| | 1665 | return g->builtin_types.entry_invalid; |
| | 1666 | } |
| | 1667 | } else if (fn_ref_expr->type == NodeTypeSymbol) { |
| | 1668 | name = &fn_ref_expr->data.symbol; |
| | 1669 | } else { |
| | 1670 | add_node_error(g, node, |
| | 1671 | buf_sprintf("function pointers not yet supported")); |
| | 1672 | return g->builtin_types.entry_invalid; |
| | 1673 | } |
| | 1674 | |
| | 1675 | auto entry = fn_table->maybe_get(name); |
| | 1676 | |
| | 1677 | if (!entry) { |
| | 1678 | add_node_error(g, fn_ref_expr, |
| | 1679 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); |
| | 1680 | // still analyze the parameters, even though we don't know what to expect |
| | 1681 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| | 1682 | AstNode *child = node->data.fn_call_expr.params.at(i); |
| | 1683 | analyze_expression(g, import, context, nullptr, child); |
| | 1684 | } |
| | 1685 | |
| | 1686 | return g->builtin_types.entry_invalid; |
| | 1687 | } else { |
| | 1688 | FnTableEntry *fn_table_entry = entry->value; |
| | 1689 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| | 1690 | AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; |
| | 1691 | |
| | 1692 | // count parameters |
| | 1693 | int expected_param_count = fn_proto->params.length; |
| | 1694 | int actual_param_count = node->data.fn_call_expr.params.length; |
| | 1695 | |
| | 1696 | if (struct_type) { |
| | 1697 | actual_param_count += 1; |
| | 1698 | } |
| | 1699 | |
| | 1700 | if (fn_proto->is_var_args) { |
| | 1701 | if (actual_param_count < expected_param_count) { |
| | 1702 | add_node_error(g, node, |
| | 1703 | buf_sprintf("wrong number of arguments. Expected at least %d, got %d.", |
| | 1704 | expected_param_count, actual_param_count)); |
| | 1705 | } |
| | 1706 | } else if (expected_param_count != actual_param_count) { |
| | 1707 | add_node_error(g, node, |
| | 1708 | buf_sprintf("wrong number of arguments. Expected %d, got %d.", |
| | 1709 | expected_param_count, actual_param_count)); |
| | 1710 | } |
| | 1711 | |
| | 1712 | // analyze each parameter. in the case of a method, we already analyzed the |
| | 1713 | // first parameter in order to figure out which struct we were calling a method on. |
| | 1714 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| | 1715 | AstNode *child = node->data.fn_call_expr.params.at(i); |
| | 1716 | // determine the expected type for each parameter |
| | 1717 | TypeTableEntry *expected_param_type = nullptr; |
| | 1718 | int fn_proto_i = i + (struct_type ? 1 : 0); |
| | 1719 | if (fn_proto_i < fn_proto->params.length) { |
| | 1720 | AstNode *param_decl_node = fn_proto->params.at(fn_proto_i); |
| | 1721 | assert(param_decl_node->type == NodeTypeParamDecl); |
| | 1722 | AstNode *param_type_node = param_decl_node->data.param_decl.type; |
| | 1723 | if (param_type_node->codegen_node) |
| | 1724 | expected_param_type = param_type_node->codegen_node->data.type_node.entry; |
| | 1725 | } |
| | 1726 | analyze_expression(g, import, context, expected_param_type, child); |
| | 1727 | } |
| | 1728 | |
| | 1729 | return fn_proto->return_type->codegen_node->data.type_node.entry; |
| | 1730 | } |
| | 1731 | } |
| | 1732 | |
| 1627 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1733 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1628 | TypeTableEntry *expected_type, AstNode *node) | 1734 | TypeTableEntry *expected_type, AstNode *node) |
| 1629 | { | 1735 | { |
| ... | @@ -1739,67 +1845,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1739,67 +1845,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1739 | break; | 1845 | break; |
| 1740 | | 1846 | |
| 1741 | case NodeTypeFnCallExpr: | 1847 | case NodeTypeFnCallExpr: |
| 1742 | { | 1848 | return_type = analyze_fn_call_expr(g, import, context, expected_type, node); |
| 1743 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; | 1849 | break; |
| 1744 | if (fn_ref_expr->type != NodeTypeSymbol) { | | |
| 1745 | add_node_error(g, node, | | |
| 1746 | buf_sprintf("function pointers not allowed")); | | |
| 1747 | break; | | |
| 1748 | } | | |
| 1749 | | | |
| 1750 | Buf *name = &fn_ref_expr->data.symbol; | | |
| 1751 | | | |
| 1752 | auto entry = import->fn_table.maybe_get(name); | | |
| 1753 | | | |
| 1754 | if (!entry) { | | |
| 1755 | add_node_error(g, fn_ref_expr, | | |
| 1756 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); | | |
| 1757 | // still analyze the parameters, even though we don't know what to expect | | |
| 1758 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | | |
| 1759 | AstNode *child = node->data.fn_call_expr.params.at(i); | | |
| 1760 | analyze_expression(g, import, context, nullptr, child); | | |
| 1761 | } | | |
| 1762 | | | |
| 1763 | return_type = g->builtin_types.entry_invalid; | | |
| 1764 | } else { | | |
| 1765 | FnTableEntry *fn_table_entry = entry->value; | | |
| 1766 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); | | |
| 1767 | AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; | | |
| 1768 | | | |
| 1769 | // count parameters | | |
| 1770 | int expected_param_count = fn_proto->params.length; | | |
| 1771 | int actual_param_count = node->data.fn_call_expr.params.length; | | |
| 1772 | if (fn_proto->is_var_args) { | | |
| 1773 | if (actual_param_count < expected_param_count) { | | |
| 1774 | add_node_error(g, node, | | |
| 1775 | buf_sprintf("wrong number of arguments. Expected at least %d, got %d.", | | |
| 1776 | expected_param_count, actual_param_count)); | | |
| 1777 | } | | |
| 1778 | } else if (expected_param_count != actual_param_count) { | | |
| 1779 | add_node_error(g, node, | | |
| 1780 | buf_sprintf("wrong number of arguments. Expected %d, got %d.", | | |
| 1781 | expected_param_count, actual_param_count)); | | |
| 1782 | } | | |
| 1783 | | | |
| 1784 | // analyze each parameter | | |
| 1785 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | | |
| 1786 | AstNode *child = node->data.fn_call_expr.params.at(i); | | |
| 1787 | // determine the expected type for each parameter | | |
| 1788 | TypeTableEntry *expected_param_type = nullptr; | | |
| 1789 | if (i < fn_proto->params.length) { | | |
| 1790 | AstNode *param_decl_node = fn_proto->params.at(i); | | |
| 1791 | assert(param_decl_node->type == NodeTypeParamDecl); | | |
| 1792 | AstNode *param_type_node = param_decl_node->data.param_decl.type; | | |
| 1793 | if (param_type_node->codegen_node) | | |
| 1794 | expected_param_type = param_type_node->codegen_node->data.type_node.entry; | | |
| 1795 | } | | |
| 1796 | analyze_expression(g, import, context, expected_param_type, child); | | |
| 1797 | } | | |
| 1798 | | | |
| 1799 | return_type = fn_proto->return_type->codegen_node->data.type_node.entry; | | |
| 1800 | } | | |
| 1801 | break; | | |
| 1802 | } | | |
| 1803 | | 1850 | |
| 1804 | case NodeTypeArrayAccessExpr: | 1851 | case NodeTypeArrayAccessExpr: |
| 1805 | // for reading array access; assignment handled elsewhere | 1852 | // for reading array access; assignment handled elsewhere |
| ... | @@ -1924,89 +1971,92 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1924,89 +1971,92 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1924 | return return_type; | 1971 | return return_type; |
| 1925 | } | 1972 | } |
| 1926 | | 1973 | |
| 1927 | static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) { | 1974 | static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 1928 | switch (node->type) { | 1975 | assert(node->type == NodeTypeFnDef); |
| 1929 | case NodeTypeFnDef: | | |
| 1930 | { | | |
| 1931 | if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) { | | |
| 1932 | // we detected an error with this function definition which prevents us | | |
| 1933 | // from further analyzing it. | | |
| 1934 | break; | | |
| 1935 | } | | |
| 1936 | | 1976 | |
| 1937 | AstNode *fn_proto_node = node->data.fn_def.fn_proto; | 1977 | if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) { |
| 1938 | assert(fn_proto_node->type == NodeTypeFnProto); | 1978 | // we detected an error with this function definition which prevents us |
| | 1979 | // from further analyzing it. |
| | 1980 | return; |
| | 1981 | } |
| 1939 | | 1982 | |
| 1940 | alloc_codegen_node(node); | 1983 | AstNode *fn_proto_node = node->data.fn_def.fn_proto; |
| 1941 | BlockContext *context = new_block_context(node, import->block_context); | 1984 | assert(fn_proto_node->type == NodeTypeFnProto); |
| 1942 | node->codegen_node->data.fn_def_node.block_context = context; | | |
| 1943 | | | |
| 1944 | AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; | | |
| 1945 | bool is_exported = (fn_proto->visib_mod == FnProtoVisibModExport); | | |
| 1946 | for (int i = 0; i < fn_proto->params.length; i += 1) { | | |
| 1947 | AstNode *param_decl_node = fn_proto->params.at(i); | | |
| 1948 | assert(param_decl_node->type == NodeTypeParamDecl); | | |
| 1949 | | | |
| 1950 | // define local variables for parameters | | |
| 1951 | AstNodeParamDecl *param_decl = &param_decl_node->data.param_decl; | | |
| 1952 | assert(param_decl->type->type == NodeTypeType); | | |
| 1953 | TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; | | |
| 1954 | | | |
| 1955 | if (is_exported && type->id == TypeTableEntryIdStruct) { | | |
| 1956 | add_node_error(g, param_decl_node, | | |
| 1957 | buf_sprintf("byvalue struct parameters not yet supported on exported functions")); | | |
| 1958 | } | | |
| 1959 | | 1985 | |
| 1960 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); | 1986 | alloc_codegen_node(node); |
| 1961 | buf_init_from_buf(&variable_entry->name, &param_decl->name); | 1987 | BlockContext *context = new_block_context(node, import->block_context); |
| 1962 | variable_entry->type = type; | 1988 | node->codegen_node->data.fn_def_node.block_context = context; |
| 1963 | variable_entry->is_const = true; | 1989 | |
| 1964 | variable_entry->decl_node = param_decl_node; | 1990 | AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; |
| 1965 | variable_entry->arg_index = i; | 1991 | bool is_exported = (fn_proto->visib_mod == FnProtoVisibModExport); |
| | 1992 | for (int i = 0; i < fn_proto->params.length; i += 1) { |
| | 1993 | AstNode *param_decl_node = fn_proto->params.at(i); |
| | 1994 | assert(param_decl_node->type == NodeTypeParamDecl); |
| | 1995 | |
| | 1996 | // define local variables for parameters |
| | 1997 | AstNodeParamDecl *param_decl = &param_decl_node->data.param_decl; |
| | 1998 | assert(param_decl->type->type == NodeTypeType); |
| | 1999 | TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; |
| | 2000 | |
| | 2001 | if (is_exported && type->id == TypeTableEntryIdStruct) { |
| | 2002 | add_node_error(g, param_decl_node, |
| | 2003 | buf_sprintf("byvalue struct parameters not yet supported on exported functions")); |
| | 2004 | } |
| 1966 | | 2005 | |
| 1967 | alloc_codegen_node(param_decl_node); | 2006 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); |
| 1968 | param_decl_node->codegen_node->data.param_decl_node.variable = variable_entry; | 2007 | buf_init_from_buf(&variable_entry->name, &param_decl->name); |
| | 2008 | variable_entry->type = type; |
| | 2009 | variable_entry->is_const = true; |
| | 2010 | variable_entry->decl_node = param_decl_node; |
| | 2011 | variable_entry->arg_index = i; |
| 1969 | | 2012 | |
| 1970 | VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); | 2013 | alloc_codegen_node(param_decl_node); |
| 1971 | if (!existing_entry) { | 2014 | param_decl_node->codegen_node->data.param_decl_node.variable = variable_entry; |
| 1972 | // unique definition | | |
| 1973 | context->variable_table.put(&variable_entry->name, variable_entry); | | |
| 1974 | } else { | | |
| 1975 | add_node_error(g, node, | | |
| 1976 | buf_sprintf("redeclaration of parameter '%s'.", buf_ptr(&existing_entry->name))); | | |
| 1977 | if (existing_entry->type == variable_entry->type) { | | |
| 1978 | // types agree, so the type is probably good enough for the rest of analysis | | |
| 1979 | } else { | | |
| 1980 | // types disagree. don't trust either one of them. | | |
| 1981 | existing_entry->type = g->builtin_types.entry_invalid;; | | |
| 1982 | } | | |
| 1983 | } | | |
| 1984 | } | | |
| 1985 | | 2015 | |
| 1986 | TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry; | 2016 | VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); |
| 1987 | TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); | 2017 | if (!existing_entry) { |
| | 2018 | // unique definition |
| | 2019 | context->variable_table.put(&variable_entry->name, variable_entry); |
| | 2020 | } else { |
| | 2021 | add_node_error(g, node, |
| | 2022 | buf_sprintf("redeclaration of parameter '%s'.", buf_ptr(&existing_entry->name))); |
| | 2023 | if (existing_entry->type == variable_entry->type) { |
| | 2024 | // types agree, so the type is probably good enough for the rest of analysis |
| | 2025 | } else { |
| | 2026 | // types disagree. don't trust either one of them. |
| | 2027 | existing_entry->type = g->builtin_types.entry_invalid;; |
| | 2028 | } |
| | 2029 | } |
| | 2030 | } |
| 1988 | | 2031 | |
| 1989 | node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type; | 2032 | TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry; |
| | 2033 | TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); |
| 1990 | | 2034 | |
| 1991 | { | 2035 | node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type; |
| 1992 | FnTableEntry *fn_table_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; | | |
| 1993 | auto it = fn_table_entry->label_table.entry_iterator(); | | |
| 1994 | for (;;) { | | |
| 1995 | auto *entry = it.next(); | | |
| 1996 | if (!entry) | | |
| 1997 | break; | | |
| 1998 | | 2036 | |
| 1999 | LabelTableEntry *label_entry = entry->value; | 2037 | { |
| 2000 | if (!label_entry->used) { | 2038 | FnTableEntry *fn_table_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; |
| 2001 | add_node_error(g, label_entry->label_node, | 2039 | auto it = fn_table_entry->label_table.entry_iterator(); |
| 2002 | buf_sprintf("label '%s' defined but not used", | 2040 | for (;;) { |
| 2003 | buf_ptr(&label_entry->label_node->data.label.name))); | 2041 | auto *entry = it.next(); |
| 2004 | } | 2042 | if (!entry) |
| 2005 | } | 2043 | break; |
| 2006 | } | 2044 | |
| | 2045 | LabelTableEntry *label_entry = entry->value; |
| | 2046 | if (!label_entry->used) { |
| | 2047 | add_node_error(g, label_entry->label_node, |
| | 2048 | buf_sprintf("label '%s' defined but not used", |
| | 2049 | buf_ptr(&label_entry->label_node->data.label.name))); |
| 2007 | } | 2050 | } |
| 2008 | break; | 2051 | } |
| | 2052 | } |
| | 2053 | } |
| 2009 | | 2054 | |
| | 2055 | static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| | 2056 | switch (node->type) { |
| | 2057 | case NodeTypeFnDef: |
| | 2058 | analyze_top_level_fn_def(g, import, node); |
| | 2059 | break; |
| 2010 | case NodeTypeRootExportDecl: | 2060 | case NodeTypeRootExportDecl: |
| 2011 | case NodeTypeExternBlock: | 2061 | case NodeTypeExternBlock: |
| 2012 | // already looked at these in the preview pass | 2062 | // already looked at these in the preview pass |
| ... | @@ -2048,8 +2098,13 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, | ... | @@ -2048,8 +2098,13 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 2048 | break; | 2098 | break; |
| 2049 | } | 2099 | } |
| 2050 | case NodeTypeStructDecl: | 2100 | case NodeTypeStructDecl: |
| 2051 | // nothing to do | 2101 | { |
| 2052 | break; | 2102 | for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) { |
| | 2103 | AstNode *fn_def_node = node->data.struct_decl.fns.at(i); |
| | 2104 | analyze_top_level_fn_def(g, import, fn_def_node); |
| | 2105 | } |
| | 2106 | break; |
| | 2107 | } |
| 2053 | case NodeTypeVariableDeclaration: | 2108 | case NodeTypeVariableDeclaration: |
| 2054 | { | 2109 | { |
| 2055 | VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context, | 2110 | VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context, |