From 974d69ea3d0db71b97af00e325fdfb421c0906c2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 28 Jan 2016 16:55:54 -0700 Subject: [PATCH] ability to call member functions directly see #14 --- src/analyze.cpp | 22 +++++++++++++++++----- src/codegen.cpp | 25 +++++++++++++++++-------- test/run_tests.cpp | 16 ++++++++++++++++ 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index cd743710e..5f3c83f3e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3694,17 +3694,17 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import } else if (struct_type->id == TypeTableEntryIdInvalid) { return struct_type; } else if (struct_type->id == TypeTableEntryIdMetaType) { - TypeTableEntry *enum_type = resolve_type(g, first_param_expr); + TypeTableEntry *child_type = resolve_type(g, first_param_expr); - if (enum_type->id == TypeTableEntryIdInvalid) { + if (child_type->id == TypeTableEntryIdInvalid) { return g->builtin_types.entry_invalid; - } else if (enum_type->id == TypeTableEntryIdEnum) { + } else if (child_type->id == TypeTableEntryIdEnum) { Buf *field_name = &fn_ref_expr->data.field_access_expr.field_name; int param_count = node->data.fn_call_expr.params.length; if (param_count > 1) { add_node_error(g, first_executing_node(node->data.fn_call_expr.params.at(1)), buf_sprintf("enum values accept only one parameter")); - return enum_type; + return child_type; } else { AstNode *value_node; if (param_count == 1) { @@ -3714,7 +3714,19 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import } return analyze_enum_value_expr(g, import, context, fn_ref_expr, value_node, - enum_type, field_name); + child_type, field_name); + } + } else if (child_type->id == TypeTableEntryIdStruct) { + Buf *field_name = &fn_ref_expr->data.field_access_expr.field_name; + auto entry = child_type->data.structure.fn_table.maybe_get(field_name); + if (entry) { + return analyze_fn_call_raw(g, import, context, expected_type, node, + entry->value, nullptr); + } else { + add_node_error(g, node, + buf_sprintf("struct '%s' has no function called '%s'", + buf_ptr(&child_type->name), buf_ptr(field_name))); + return g->builtin_types.entry_invalid; } } else { add_node_error(g, first_param_expr, buf_sprintf("member reference base type not struct or enum")); diff --git a/src/codegen.cpp b/src/codegen.cpp index 6f4ba6c58..97b03d14d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -496,16 +496,25 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { assert(struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct); fn_table_entry = node->data.fn_call_expr.fn_entry; } else if (struct_type->id == TypeTableEntryIdMetaType) { - TypeTableEntry *enum_type = get_type_for_type_node(first_param_expr); - int param_count = node->data.fn_call_expr.params.length; - AstNode *arg1_node; - if (param_count == 1) { - arg1_node = node->data.fn_call_expr.params.at(0); + TypeTableEntry *child_type = get_type_for_type_node(first_param_expr); + + if (child_type->id == TypeTableEntryIdEnum) { + int param_count = node->data.fn_call_expr.params.length; + AstNode *arg1_node; + if (param_count == 1) { + arg1_node = node->data.fn_call_expr.params.at(0); + } else { + assert(param_count == 0); + arg1_node = nullptr; + } + return gen_enum_value_expr(g, fn_ref_expr, child_type, arg1_node); + } else if (child_type->id == TypeTableEntryIdStruct) { + struct_type = nullptr; + first_param_expr = nullptr; + fn_table_entry = node->data.fn_call_expr.fn_entry; } else { - assert(param_count == 0); - arg1_node = nullptr; + zig_unreachable(); } - return gen_enum_value_expr(g, fn_ref_expr, enum_type, arg1_node); } else { zig_unreachable(); } diff --git a/test/run_tests.cpp b/test/run_tests.cpp index b15f6e2ec..84704d5f6 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1407,6 +1407,22 @@ pub fn main(args: [][]u8) -> %void { %%stdout.printf("BAD\n"); } %%stdout.printf("OK\n"); +} + )SOURCE", "OK\n"); + + add_simple_case("call member function directly", R"SOURCE( +import "std.zig"; +struct Foo { + x: i32, + fn member(foo: Foo) -> i32 { foo.x } +} +pub fn main(args: [][]u8) -> %void { + const instance = Foo { .x = 1234, }; + const result = Foo.member(instance); + if (result != 1234) { + %%stdout.printf("BAD\n"); + } + %%stdout.printf("OK\n"); } )SOURCE", "OK\n"); }