authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-04 16:57:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-04 16:57:22-07:00
log4514661cfef1cd0090ba9888b69037af3ef9805a
treea298e8c90440837a9cbf7ec83d9c6408ca59c768
parentfcacc85b4e7f0a60ae11bbefcdae620665426297

add member functions


7 files changed, 327 insertions(+), 202 deletions(-)

doc/langref.md+3-1
......@@ -36,7 +36,9 @@ TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | Variabl
3636
3737VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
3838
39StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace)
39StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
40
41StructMember: StructField | FnDecl
4042
4143StructField : token(Symbol) token(Colon) Type token(Comma)
4244
src/analyze.cpp+245-190
......@@ -106,6 +106,11 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
106106 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
107107 entry->arrays_by_size.init(2);
108108 entry->id = id;
109
110 if (id == TypeTableEntryIdStruct) {
111 entry->data.structure.fn_table.init(8);
112 }
113
109114 return entry;
110115}
111116
......@@ -461,6 +466,68 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
461466 struct_type->di_type = replacement_di_type;
462467}
463468
469static 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}
464531
465532static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) {
466533 switch (node->type) {
......@@ -500,61 +567,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
500567 }
501568 break;
502569 case NodeTypeFnDef:
503 {
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 }
570 preview_fn_def(g, import, node, nullptr);
558571 break;
559572 case NodeTypeRootExportDecl:
560573 if (import == g->root_import) {
......@@ -605,6 +618,11 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
605618 TypeTableEntry *type_entry = struct_codegen->type_entry;
606619
607620 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 }
608626 break;
609627 }
610628 case NodeTypeUse:
......@@ -1624,6 +1642,94 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im
16241642 }
16251643}
16261644
1645static 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
16271733static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
16281734 TypeTableEntry *expected_type, AstNode *node)
16291735{
......@@ -1739,67 +1845,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
17391845 break;
17401846
17411847 case NodeTypeFnCallExpr:
1742 {
1743 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
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 }
1848 return_type = analyze_fn_call_expr(g, import, context, expected_type, node);
1849 break;
18031850
18041851 case NodeTypeArrayAccessExpr:
18051852 // for reading array access; assignment handled elsewhere
......@@ -1924,89 +1971,92 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
19241971 return return_type;
19251972}
19261973
1927static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) {
1928 switch (node->type) {
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 }
1974static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) {
1975 assert(node->type == NodeTypeFnDef);
19361976
1937 AstNode *fn_proto_node = node->data.fn_def.fn_proto;
1938 assert(fn_proto_node->type == NodeTypeFnProto);
1977 if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) {
1978 // we detected an error with this function definition which prevents us
1979 // from further analyzing it.
1980 return;
1981 }
19391982
1940 alloc_codegen_node(node);
1941 BlockContext *context = new_block_context(node, import->block_context);
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 }
1983 AstNode *fn_proto_node = node->data.fn_def.fn_proto;
1984 assert(fn_proto_node->type == NodeTypeFnProto);
19591985
1960 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
1961 buf_init_from_buf(&variable_entry->name, &param_decl->name);
1962 variable_entry->type = type;
1963 variable_entry->is_const = true;
1964 variable_entry->decl_node = param_decl_node;
1965 variable_entry->arg_index = i;
1986 alloc_codegen_node(node);
1987 BlockContext *context = new_block_context(node, import->block_context);
1988 node->codegen_node->data.fn_def_node.block_context = context;
1989
1990 AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
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 }
19662005
1967 alloc_codegen_node(param_decl_node);
1968 param_decl_node->codegen_node->data.param_decl_node.variable = variable_entry;
2006 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
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;
19692012
1970 VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name);
1971 if (!existing_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 }
2013 alloc_codegen_node(param_decl_node);
2014 param_decl_node->codegen_node->data.param_decl_node.variable = variable_entry;
19852015
1986 TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry;
1987 TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body);
2016 VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name);
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 }
19882031
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);
19902034
1991 {
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;
2035 node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type;
19982036
1999 LabelTableEntry *label_entry = entry->value;
2000 if (!label_entry->used) {
2001 add_node_error(g, label_entry->label_node,
2002 buf_sprintf("label '%s' defined but not used",
2003 buf_ptr(&label_entry->label_node->data.label.name)));
2004 }
2005 }
2006 }
2037 {
2038 FnTableEntry *fn_table_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;
2039 auto it = fn_table_entry->label_table.entry_iterator();
2040 for (;;) {
2041 auto *entry = it.next();
2042 if (!entry)
2043 break;
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)));
20072050 }
2008 break;
2051 }
2052 }
2053}
20092054
2055static 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;
20102060 case NodeTypeRootExportDecl:
20112061 case NodeTypeExternBlock:
20122062 // already looked at these in the preview pass
......@@ -2048,8 +2098,13 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
20482098 break;
20492099 }
20502100 case NodeTypeStructDecl:
2051 // nothing to do
2052 break;
2101 {
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 }
20532108 case NodeTypeVariableDeclaration:
20542109 {
20552110 VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context,
src/analyze.hpp+2
......@@ -45,6 +45,8 @@ struct TypeTableEntryStruct {
4545 int field_count;
4646 TypeStructField *fields;
4747 uint64_t size_bytes;
48 // reminder: hash tables must be initialized before use
49 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
4850
4951 // set this flag temporarily to detect infinite loops
5052 bool embedded_in_current;
src/codegen.cpp+25-6
......@@ -142,15 +142,31 @@ static TypeTableEntry *get_expr_type(AstNode *node) {
142142static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
143143 assert(node->type == NodeTypeFnCallExpr);
144144
145 Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
145 FnTableEntry *fn_table_entry;
146 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
147 TypeTableEntry *struct_type;
148 AstNode *first_param_expr;
149 if (fn_ref_expr->type == NodeTypeFieldAccessExpr) {
150 Buf *name = &fn_ref_expr->data.field_access_expr.field_name;
151 first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr;
152 struct_type = get_expr_type(first_param_expr);
153 fn_table_entry = struct_type->data.structure.fn_table.get(name);
154 } else if (fn_ref_expr->type == NodeTypeSymbol) {
155 Buf *name = hack_get_fn_call_name(g, fn_ref_expr);
156 struct_type = nullptr;
157 first_param_expr = nullptr;
158 fn_table_entry = g->cur_fn->import_entry->fn_table.get(name);
159 } else {
160 zig_unreachable();
161 }
146162
147 FnTableEntry *fn_table_entry = g->cur_fn->import_entry->fn_table.get(name);
148163
149164 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
150165 AstNodeFnProto *fn_proto_data = &fn_table_entry->proto_node->data.fn_proto;
151166
152167 int expected_param_count = fn_proto_data->params.length;
153 int actual_param_count = node->data.fn_call_expr.params.length;
168 int fn_call_param_count = node->data.fn_call_expr.params.length;
169 int actual_param_count = fn_call_param_count + (struct_type ? 1 : 0);
154170 bool is_var_args = fn_proto_data->is_var_args;
155171 assert((is_var_args && actual_param_count >= expected_param_count) ||
156172 actual_param_count == expected_param_count);
......@@ -164,10 +180,13 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
164180 }
165181 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(gen_param_count);
166182
167 int loop_end = max(gen_param_count, actual_param_count);
168
169183 int gen_param_index = 0;
170 for (int i = 0; i < loop_end; i += 1) {
184 if (struct_type) {
185 gen_param_values[gen_param_index] = gen_expr(g, first_param_expr);
186 gen_param_index += 1;
187 }
188
189 for (int i = 0; i < fn_call_param_count; i += 1) {
171190 AstNode *expr_node = node->data.fn_call_expr.params.at(i);
172191 LLVMValueRef param_value = gen_expr(g, expr_node);
173192 if (is_var_args ||
src/parser.cpp+32-4
......@@ -395,6 +395,14 @@ void ast_print(AstNode *node, int indent) {
395395 case NodeTypeStructDecl:
396396 fprintf(stderr, "%s '%s'\n",
397397 node_type_str(node->type), buf_ptr(&node->data.struct_decl.name));
398 for (int i = 0; i < node->data.struct_decl.fields.length; i += 1) {
399 AstNode *child = node->data.struct_decl.fields.at(i);
400 ast_print(child, indent + 2);
401 }
402 for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) {
403 AstNode *child = node->data.struct_decl.fns.at(i);
404 ast_print(child, indent + 2);
405 }
398406 break;
399407 case NodeTypeStructField:
400408 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_field.name));
......@@ -2572,7 +2580,8 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index) {
25722580}
25732581
25742582/*
2575StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace)
2583StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
2584StructMember: StructField | FnDecl
25762585StructField : token(Symbol) token(Colon) Type token(Comma)
25772586*/
25782587static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
......@@ -2590,16 +2599,38 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
25902599
25912600 ast_eat_token(pc, token_index, TokenIdLBrace);
25922601
2602 node->data.struct_decl.directives = pc->directive_list;
2603 pc->directive_list = nullptr;
2604
25932605 for (;;) {
2606 assert(!pc->directive_list);
2607 pc->directive_list = allocate<ZigList<AstNode*>>(1);
2608 Token *directive_token = &pc->tokens->at(*token_index);
2609 ast_parse_directives(pc, token_index, pc->directive_list);
2610
2611 AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false);
2612 if (fn_def_node) {
2613 node->data.struct_decl.fns.append(fn_def_node);
2614 continue;
2615 }
2616
25942617 Token *token = &pc->tokens->at(*token_index);
25952618
25962619 if (token->id == TokenIdRBrace) {
2620 if (pc->directive_list->length > 0) {
2621 ast_error(pc, directive_token, "invalid directive");
2622 }
2623 pc->directive_list = nullptr;
2624
25972625 *token_index += 1;
25982626 break;
25992627 } else if (token->id == TokenIdSymbol) {
26002628 AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token);
26012629 *token_index += 1;
26022630
2631 field_node->data.struct_field.directives = pc->directive_list;
2632 pc->directive_list = nullptr;
2633
26032634 ast_buf_from_token(pc, token, &field_node->data.struct_field.name);
26042635
26052636 ast_eat_token(pc, token_index, TokenIdColon);
......@@ -2615,9 +2646,6 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
26152646 }
26162647
26172648
2618 node->data.struct_decl.directives = pc->directive_list;
2619 pc->directive_list = nullptr;
2620
26212649 return node;
26222650}
26232651
src/parser.hpp+2
......@@ -281,12 +281,14 @@ struct AstNodeAsmExpr {
281281struct AstNodeStructDecl {
282282 Buf name;
283283 ZigList<AstNode *> fields;
284 ZigList<AstNode *> fns;
284285 ZigList<AstNode *> *directives;
285286};
286287
287288struct AstNodeStructField {
288289 Buf name;
289290 AstNode *type;
291 ZigList<AstNode *> *directives;
290292};
291293
292294struct AstNodeStringLiteral {
test/run_tests.cpp+18-1
......@@ -56,7 +56,6 @@ static TestCase *add_simple_case(const char *case_name, const char *source, cons
5656 test_case->compiler_args.append(tmp_exe_path);
5757 test_case->compiler_args.append("--release");
5858 test_case->compiler_args.append("--strip");
59 //test_case->compiler_args.append("--verbose");
6059 test_case->compiler_args.append("--color");
6160 test_case->compiler_args.append("on");
6261
......@@ -740,6 +739,24 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
740739 return 0;
741740}
742741 )SOURCE", "2\n");
742
743 add_simple_case("member functions", R"SOURCE(
744use "std.zig";
745struct Rand {
746 seed: u32,
747 pub fn get_seed(r: Rand) -> u32 {
748 r.seed
749 }
750}
751pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
752 const r = Rand {.seed = 1234};
753 if (r.get_seed() != 1234) {
754 print_str("BAD seed\n");
755 }
756 print_str("OK\n");
757 return 0;
758}
759 )SOURCE", "OK\n");
743760}
744761
745762////////////////////////////////////////////////////////////////////////////////////