[macruby-changes] [1623] MacRuby/branches/experimental

source_changes at macosforge.org source_changes at macosforge.org
Thu May 28 13:38:11 PDT 2009


Revision: 1623
          http://trac.macosforge.org/projects/ruby/changeset/1623
Author:   lsansonetti at apple.com
Date:     2009-05-28 13:38:09 -0700 (Thu, 28 May 2009)
Log Message:
-----------
implemented informal protocol method definition + some refactoring

Modified Paths:
--------------
    MacRuby/branches/experimental/bridgesupport.cpp
    MacRuby/branches/experimental/objc.h
    MacRuby/branches/experimental/objc.m
    MacRuby/branches/experimental/spec/macruby/fixtures/method.bridgesupport
    MacRuby/branches/experimental/spec/macruby/fixtures/method.m
    MacRuby/branches/experimental/spec/macruby/fixtures/method.rb
    MacRuby/branches/experimental/spec/macruby/language/objc_method_spec.rb
    MacRuby/branches/experimental/vm.cpp
    MacRuby/branches/experimental/vm.h

Modified: MacRuby/branches/experimental/bridgesupport.cpp
===================================================================
--- MacRuby/branches/experimental/bridgesupport.cpp	2009-05-28 08:06:03 UTC (rev 1622)
+++ MacRuby/branches/experimental/bridgesupport.cpp	2009-05-28 20:38:09 UTC (rev 1623)
@@ -827,20 +827,15 @@
 
 	case BS_ELEMENT_INFORMAL_PROTOCOL_METHOD:
 	{
-#if 0
 	    bs_element_informal_protocol_method_t *bs_inf_prot_method = 
 		(bs_element_informal_protocol_method_t *)value;
-	    struct st_table *t = bs_inf_prot_method->class_method
-		? bs_inf_prot_cmethods
-		: bs_inf_prot_imethods;
 
-	    st_insert(t, (st_data_t)bs_inf_prot_method->name,
-		(st_data_t)bs_inf_prot_method->type);
+	    std::map<SEL, std::string> &map =
+		bs_inf_prot_method->class_method
+		? GET_VM()->bs_informal_protocol_cmethods
+		: GET_VM()->bs_informal_protocol_imethods;
 
-	    free(bs_inf_prot_method->protocol_name);
-	    free(bs_inf_prot_method);
-	    do_not_free = true;
-#endif
+	    map[bs_inf_prot_method->name] = bs_inf_prot_method->type;
 	    break;
 	}
 

Modified: MacRuby/branches/experimental/objc.h
===================================================================
--- MacRuby/branches/experimental/objc.h	2009-05-28 08:06:03 UTC (rev 1622)
+++ MacRuby/branches/experimental/objc.h	2009-05-28 20:38:09 UTC (rev 1623)
@@ -1,3 +1,11 @@
+/*
+ * MacRuby ObjC helpers.
+ *
+ * This file is covered by the Ruby license. See COPYING for more details.
+ * 
+ * Copyright (C) 2007-2009, Apple Inc. All rights reserved.
+ */
+
 #ifndef __OBJC_H_
 #define __OBJC_H_
 
@@ -12,16 +20,14 @@
   unsigned int argc;
 };
 
-bs_element_method_t * rb_bs_find_method(Class klass, SEL sel);
-
-bool rb_objc_get_types(VALUE recv, Class klass, SEL sel,
+bool rb_objc_get_types(VALUE recv, Class klass, SEL sel, Method m,
 	bs_element_method_t *bs_method, char *buf, size_t buflen);
 
 VALUE rb_objc_call(VALUE recv, SEL sel, int argc, VALUE *argv);
 
 VALUE rb_objc_call2(VALUE recv, VALUE klass, SEL sel, IMP imp, 
-	struct rb_objc_method_sig *sig, bs_element_method_t *bs_method, int argc, 
-	VALUE *argv);
+	struct rb_objc_method_sig *sig, bs_element_method_t *bs_method,
+	int argc, VALUE *argv);
 
 void rb_objc_define_kvo_setter(VALUE klass, ID mid);
 void rb_objc_change_ruby_method_signature(VALUE mod, ID mid, VALUE sig);
@@ -33,14 +39,16 @@
 
     method = class_getInstanceMethod(klass, sel);
     if (method == NULL) {
-	printf("method %s not found on class %p - aborting\n", sel_getName(sel), klass);
+	printf("method %s not found on class %p - aborting\n",
+		sel_getName(sel), klass);
 	abort();
     }
     assert(method != NULL);
  
     method2 = class_getInstanceMethod((Class)RCLASS_SUPER(klass), sel);
     if (method == method2)  {
-	assert(class_addMethod(klass, sel, imp, method_getTypeEncoding(method)));
+	assert(class_addMethod(klass, sel, imp,
+		    method_getTypeEncoding(method)));
     }
     else {
 	method_setImplementation(method, imp);
@@ -73,10 +81,12 @@
 rb_objc_is_placeholder(id obj)
 {
     void *klass = *(void **)obj;
-    return klass == placeholder_String || klass == placeholder_Dictionary || klass == placeholder_Array;
+    return klass == placeholder_String || klass == placeholder_Dictionary
+	|| klass == placeholder_Array;
 }
 
-bool rb_objc_symbolize_address(void *addr, void **start, char *name, size_t name_len);
+bool rb_objc_symbolize_address(void *addr, void **start, char *name,
+	size_t name_len);
 
 static inline int
 SubtypeUntil(const char *type, char end)

Modified: MacRuby/branches/experimental/objc.m
===================================================================
--- MacRuby/branches/experimental/objc.m	2009-05-28 08:06:03 UTC (rev 1622)
+++ MacRuby/branches/experimental/objc.m	2009-05-28 20:38:09 UTC (rev 1623)
@@ -1,29 +1,9 @@
-/*  
- *  Copyright (c) 2008, Apple Inc. All rights reserved.
+/*
+ * MacRuby ObjC helpers.
  *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions
- *  are met:
- *  1.  Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *  2.  Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the
- *      documentation and/or other materials provided with the distribution.
- *  3.  Neither the name of Apple Inc. ("Apple") nor the names of
- *      its contributors may be used to endorse or promote products derived
- *      from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
- *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
- *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- *  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *  POSSIBILITY OF SUCH DAMAGE.
+ * This file is covered by the Ruby license. See COPYING for more details.
+ * 
+ * Copyright (C) 2007-2009, Apple Inc. All rights reserved.
  */
 
 #include <Foundation/Foundation.h>
@@ -67,14 +47,12 @@
 }
 
 bool
-rb_objc_get_types(VALUE recv, Class klass, SEL sel,
+rb_objc_get_types(VALUE recv, Class klass, SEL sel, Method method,
 		  bs_element_method_t *bs_method, char *buf, size_t buflen)
 {
-    Method method;
     const char *type;
     unsigned i;
 
-    method = class_getInstanceMethod(klass, sel);
     if (method != NULL) {
 	if (bs_method == NULL) {
 	    type = method_getTypeEncoding(method);

Modified: MacRuby/branches/experimental/spec/macruby/fixtures/method.bridgesupport
===================================================================
--- MacRuby/branches/experimental/spec/macruby/fixtures/method.bridgesupport	2009-05-28 08:06:03 UTC (rev 1622)
+++ MacRuby/branches/experimental/spec/macruby/fixtures/method.bridgesupport	2009-05-28 20:38:09 UTC (rev 1623)
@@ -21,4 +21,8 @@
       <arg index='0' type='B'/>
     </method>
   </class>
+  <informal_protocol name='Foo'>
+    <method type="i@:i" selector="informalProtocolMethod1:"/>
+    <method type="B@:ii" selector="informalProtocolMethod2:withValue:"/>
+  </informal_protocol>
 </signatures>

Modified: MacRuby/branches/experimental/spec/macruby/fixtures/method.m
===================================================================
--- MacRuby/branches/experimental/spec/macruby/fixtures/method.m	2009-05-28 08:06:03 UTC (rev 1622)
+++ MacRuby/branches/experimental/spec/macruby/fixtures/method.m	2009-05-28 20:38:09 UTC (rev 1623)
@@ -1,5 +1,12 @@
 #import <Foundation/Foundation.h>
 
+ at interface NSObject (TestInformalProtocolMethod)
+
+- (int)informalProtocolMethod1:(int)arg;
+- (BOOL)informalProtocolMethod2:(int)arg1 withValue:(int)arg2;
+
+ at end
+
 @interface TestMethod : NSObject
 {
     id _foo;
@@ -665,6 +672,16 @@
     return ptr == NULL;
 }
 
++ (BOOL)testInformalProtocolMethod1:(id)o
+{
+    return [o informalProtocolMethod1:41] == 42;
+}
+
++ (BOOL)testInformalProtocolMethod2:(id)o
+{
+    return [o informalProtocolMethod2:40 withValue:2];
+}
+
 @end
 
 void

Modified: MacRuby/branches/experimental/spec/macruby/fixtures/method.rb
===================================================================
--- MacRuby/branches/experimental/spec/macruby/fixtures/method.rb	2009-05-28 08:06:03 UTC (rev 1622)
+++ MacRuby/branches/experimental/spec/macruby/fixtures/method.rb	2009-05-28 20:38:09 UTC (rev 1623)
@@ -58,3 +58,12 @@
   def methodAcceptingInt(a, float:a2, double:a3, short:a4, NSPoint:a5,
                          NSRect:a6, char:a7); super; end
 end
+
+class TestInformalProtocolMethod
+  def informalProtocolMethod1(x)
+    x + 1
+  end
+  def informalProtocolMethod2(x, withValue:x2)
+    x + x2 == 42
+  end
+end

Modified: MacRuby/branches/experimental/spec/macruby/language/objc_method_spec.rb
===================================================================
--- MacRuby/branches/experimental/spec/macruby/language/objc_method_spec.rb	2009-05-28 08:06:03 UTC (rev 1622)
+++ MacRuby/branches/experimental/spec/macruby/language/objc_method_spec.rb	2009-05-28 20:38:09 UTC (rev 1623)
@@ -628,3 +628,14 @@
     TestMethodOverride.testMethodAcceptingComplexTypes(@o).should == 1
   end
 end
+
+describe "A pure MacRuby method" do
+  before :each do
+    @o = TestInformalProtocolMethod.new
+  end
+  
+  it "whose selector matches an informal protocol is defined on the Objective-C side with the correct type encoding" do
+    TestMethod.testInformalProtocolMethod1(@o).should == 1 
+    TestMethod.testInformalProtocolMethod2(@o).should == 1 
+  end
+end

Modified: MacRuby/branches/experimental/vm.cpp
===================================================================
--- MacRuby/branches/experimental/vm.cpp	2009-05-28 08:06:03 UTC (rev 1622)
+++ MacRuby/branches/experimental/vm.cpp	2009-05-28 20:38:09 UTC (rev 1623)
@@ -1119,35 +1119,53 @@
     return -1;
 }
 
-static void
-resolve_method(Class klass, SEL sel, Function *func, NODE *node, IMP imp,
-	       Method m)
+static inline void 
+resolve_method_type(char *buf, const size_t buflen, Class klass, Method m,
+		    SEL sel, const unsigned int oc_arity)
 {
-    const int oc_arity = rb_vm_node_arity(node).real + 3;
-
-    char types[100];
     bs_element_method_t *bs_method = GET_VM()->find_bs_method(klass, sel);
 
-    if (m == NULL || !rb_objc_get_types(Qnil, klass, sel, bs_method, types,
-					sizeof types)) {
-	assert((unsigned int)oc_arity < sizeof(types));
-	types[0] = '@';
-	types[1] = '@';
-	types[2] = ':';
-	for (int i = 3; i < oc_arity; i++) {
-	    types[i] = '@';
+    if (m == NULL
+	|| !rb_objc_get_types(Qnil, klass, sel, m, bs_method, buf, buflen)) {
+
+	std::map<SEL, std::string> &map = class_isMetaClass(klass)
+	    ? GET_VM()->bs_informal_protocol_cmethods
+	    : GET_VM()->bs_informal_protocol_imethods;
+
+	std::map<SEL, std::string>::iterator iter = map.find(sel);	
+	if (iter != map.end()) {
+	    strncpy(buf, iter->second.c_str(), sizeof buf);
 	}
-	types[oc_arity] = '\0';
+	else {
+	    assert(oc_arity < buflen);
+	    buf[0] = '@';
+	    buf[1] = '@';
+	    buf[2] = ':';
+	    for (unsigned int i = 3; i < oc_arity; i++) {
+		buf[i] = '@';
+	    }
+	    buf[oc_arity] = '\0';
+	}
     }
     else {
-	const int m_argc = method_getNumberOfArguments(m);
+	const unsigned int m_argc = method_getNumberOfArguments(m);
 	if (m_argc < oc_arity) {
-	    for (int i = m_argc; i < oc_arity; i++) {
-		strcat(types, "@");
+	    for (unsigned int i = m_argc; i < oc_arity; i++) {
+		strcat(buf, "@");
 	    }
 	}
     }
+}
 
+static void
+resolve_method(Class klass, SEL sel, Function *func, NODE *node, IMP imp,
+	       Method m)
+{
+    const int oc_arity = rb_vm_node_arity(node).real + 3;
+
+    char types[100];
+    resolve_method_type(types, sizeof types, klass, m, sel, oc_arity);
+
     std::map<Function *, IMP>::iterator iter =
 	GET_VM()->objc_to_ruby_stubs.find(func);
     IMP objc_imp;
@@ -1607,23 +1625,11 @@
     IMP ruby_imp = node == NULL ? imp : node->ruby_imp;
 
 define_method:
-    char *types;
     Method method = class_getInstanceMethod(klass, sel);
-    if (method != NULL) {
-	types = (char *)method_getTypeEncoding(method);
-    }
-    else {
-	// TODO look at informal protocols list
-	types = (char *)alloca(oc_arity + 4);
-	types[0] = '@';
-	types[1] = '@';
-	types[2] = ':';
-	for (int i = 0; i < oc_arity; i++) {
-	    types[3 + i] = '@';
-	}
-	types[3 + oc_arity] = '\0';
-    }
 
+    char types[100];
+    resolve_method_type(types, sizeof types, klass, method, sel, oc_arity);
+
     GET_VM()->add_method(klass, sel, imp, ruby_imp, arity, flags, types);
 
     if (!redefined) {
@@ -1661,7 +1667,8 @@
 
 extern "C"
 void 
-rb_vm_define_method2(Class klass, SEL sel, rb_vm_method_node_t *node, bool direct)
+rb_vm_define_method2(Class klass, SEL sel, rb_vm_method_node_t *node,
+		     bool direct)
 {
     assert(node != NULL);
 
@@ -2127,7 +2134,7 @@
 
 static force_inline void
 fill_ocache(struct mcache *cache, VALUE self, Class klass, IMP imp, SEL sel,
-	    int argc)
+	    Method method, int argc)
 {
     cache->flag = MCACHE_OCALL;
     ocache.klass = klass;
@@ -2135,7 +2142,7 @@
     ocache.bs_method = GET_VM()->find_bs_method(klass, sel);
 
     char types[200];
-    if (!rb_objc_get_types(self, klass, sel, ocache.bs_method,
+    if (!rb_objc_get_types(self, klass, sel, method, ocache.bs_method,
 		types, sizeof types)) {
 	printf("cannot get encoding types for %c[%s %s]\n",
 		class_isMetaClass(klass) ? '+' : '-',
@@ -2184,7 +2191,7 @@
 	    }
 	    else {
 		// objc call
-		fill_ocache(cache, self, klass, imp, sel, argc);
+		fill_ocache(cache, self, klass, imp, sel, method, argc);
 	    }
 	}
 	else {
@@ -2941,11 +2948,12 @@
 	oklass = k;
     }
 
+    Method method = class_getInstanceMethod((Class)klass, sel);
+    assert(method != NULL);
+
     int arity;
     if (node == NULL) {
-	Method m = class_getInstanceMethod((Class)klass, sel);
-	assert(m != NULL);
-	arity = method_getNumberOfArguments(m) - 2;
+	arity = method_getNumberOfArguments(method) - 2;
     }
     else {
 	arity = node->arity.min;
@@ -2967,7 +2975,7 @@
     // point to the method it was created from.
     struct mcache *c = (struct mcache *)xmalloc(sizeof(struct mcache));
     if (node == NULL) {
-	fill_ocache(c, obj, oklass, imp, sel, arity);
+	fill_ocache(c, obj, oklass, imp, sel, method, arity);
     }
     else {
 	rb_vm_method_node_t *node = GET_VM()->method_node_get(imp);

Modified: MacRuby/branches/experimental/vm.h
===================================================================
--- MacRuby/branches/experimental/vm.h	2009-05-28 08:06:03 UTC (rev 1622)
+++ MacRuby/branches/experimental/vm.h	2009-05-28 20:38:09 UTC (rev 1623)
@@ -519,6 +519,8 @@
 	std::map<std::string, std::map<SEL, bs_element_method_t *> *>
 	    bs_classes_class_methods, bs_classes_instance_methods;
 	std::map<std::string, bs_element_cftype_t *> bs_cftypes;
+	std::map<SEL, std::string> bs_informal_protocol_imethods,
+	    bs_informal_protocol_cmethods;
 
 	bs_element_method_t *find_bs_method(Class klass, SEL sel);
 	rb_vm_bs_boxed_t *find_bs_boxed(std::string type);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090528/df4a7b34/attachment-0001.html>


More information about the macruby-changes mailing list