Commit 974d69ea3d

Andrew Kelley <superjoe30@gmail.com>
2016-01-29 00:55:54
ability to call member functions directly
see #14
1 parent bb4f783
Changed files (3)
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"));
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();
         }
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");
 }