[macruby-changes] [3962] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Sun Apr 25 20:32:28 PDT 2010


Revision: 3962
          http://trac.macosforge.org/projects/ruby/changeset/3962
Author:   lsansonetti at apple.com
Date:     2010-04-25 20:32:23 -0700 (Sun, 25 Apr 2010)
Log Message:
-----------
added support for anonymous structs

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

Modified: MacRuby/trunk/bridgesupport.cpp
===================================================================
--- MacRuby/trunk/bridgesupport.cpp	2010-04-24 20:12:57 UTC (rev 3961)
+++ MacRuby/trunk/bridgesupport.cpp	2010-04-26 03:32:23 UTC (rev 3962)
@@ -526,6 +526,168 @@
     return true;
 }
 
+rb_vm_bs_boxed_t *
+RoxorCore::register_anonymous_bs_struct(const char *type)
+{
+    if (strlen(type) < 3 || type[0] != _C_STRUCT_B || type[1] != '?'
+	   || type[2] != '=') {
+	// Does not look like an anonymous struct...
+	return NULL;
+    }
+
+    // Prepare the list of field types.
+    std::vector<std::string> s_types;
+    char buf[100];
+    const char *p = &type[3];
+    while (*p != _C_STRUCT_E) {
+	p = GetFirstType(p, buf, sizeof buf);
+	assert(*p != '\0');
+	s_types.push_back(buf);
+    }
+
+    // Prepare the BridgeSupport structure.
+    bs_element_struct_t *bs_struct = (bs_element_struct_t *)
+	malloc(sizeof(bs_element_struct_t));
+    bs_struct->name = (char *)"?";
+    bs_struct->type = strdup(type);
+    bs_struct->fields_count = s_types.size();
+    assert(bs_struct->fields_count > 0);
+    bs_struct->fields = (bs_element_struct_field_t *)
+	malloc(sizeof(bs_element_struct_field_t) * bs_struct->fields_count);
+    for (unsigned i = 0; i < bs_struct->fields_count; i++) {
+	bs_element_struct_field_t *field = &bs_struct->fields[i];
+	field->name = (char *)"?";
+	field->type = strdup(s_types.at(i).c_str());
+    }
+    bs_struct->opaque = true;
+
+    // Prepare the boxed structure.
+    rb_vm_bs_boxed_t *boxed = (rb_vm_bs_boxed_t *)
+	malloc(sizeof(rb_vm_bs_boxed_t));
+    boxed->bs_type = BS_ELEMENT_STRUCT;
+    boxed->as.s = bs_struct;
+    boxed->type = NULL; // Lazy
+    boxed->klass = rb_cBoxed; // This type has no class
+
+    // Register it to the runtime.
+    bs_boxed[type] = boxed;
+    return boxed;
+}
+
+static inline long
+rebuild_new_struct_ary(const StructType *type, VALUE orig, VALUE new_ary)
+{
+    long n = 0;
+
+    for (StructType::element_iterator iter = type->element_begin();
+	 iter != type->element_end();
+	 ++iter) {
+
+	const Type *ftype = *iter;
+	
+	if (ftype->getTypeID() == Type::StructTyID) {
+            long i, n2;
+            VALUE tmp;
+
+            n2 = rebuild_new_struct_ary(cast<StructType>(ftype), orig, new_ary);
+            tmp = rb_ary_new();
+            for (i = 0; i < n2; i++) {
+                if (RARRAY_LEN(orig) == 0) {
+                    return 0;
+		}
+                rb_ary_push(tmp, rb_ary_shift(orig));
+            }
+            rb_ary_push(new_ary, tmp);
+        }
+        n++;
+    }
+
+    return n;
+}
+
+extern "C"
+void
+rb_vm_get_struct_fields(VALUE rval, VALUE *buf, rb_vm_bs_boxed_t *bs_boxed)
+{
+    if (TYPE(rval) == T_ARRAY) {
+	unsigned n = RARRAY_LEN(rval);
+	if (n < bs_boxed->as.s->fields_count) {
+	    rb_raise(rb_eArgError,
+		    "not enough elements in array `%s' to create " \
+		    "structure `%s' (%d for %d)",
+		    RSTRING_PTR(rb_inspect(rval)), bs_boxed->as.s->name, n,
+		    bs_boxed->as.s->fields_count);
+	}
+
+	if (n > bs_boxed->as.s->fields_count) {
+	    VALUE new_rval = rb_ary_new();
+	    VALUE orig = rval;
+	    rval = rb_ary_dup(rval);
+	    rebuild_new_struct_ary(cast<StructType>(bs_boxed->type), rval,
+		    new_rval);
+	    n = RARRAY_LEN(new_rval);
+	    if (RARRAY_LEN(rval) != 0 || n != bs_boxed->as.s->fields_count) {
+		rb_raise(rb_eArgError,
+			"too much elements in array `%s' to create " \
+			"structure `%s' (%ld for %d)",
+			RSTRING_PTR(rb_inspect(orig)),
+			bs_boxed->as.s->name, RARRAY_LEN(orig),
+			bs_boxed->as.s->fields_count);
+	    }
+	    rval = new_rval;
+	}
+
+	for (unsigned i = 0; i < n; i++) {
+	    buf[i] = RARRAY_AT(rval, i);
+	}
+    }
+    else {
+	if (!rb_obj_is_kind_of(rval, bs_boxed->klass)) {
+	    rb_raise(rb_eTypeError, 
+		    "expected instance of `%s', got `%s' (%s)",
+		    rb_class2name(bs_boxed->klass),
+		    RSTRING_PTR(rb_inspect(rval)),
+		    rb_obj_classname(rval));
+	}
+
+	if (bs_boxed->klass == rb_cBoxed) {
+	    // An anonymous type...
+	    // Let's check that the given boxed object matches the types.
+	    rb_vm_bs_boxed_t *rval_bs_boxed =
+		locate_bs_boxed(CLASS_OF(rval), true);
+	    assert(rval_bs_boxed != NULL);
+
+	    if (rval_bs_boxed->as.s->fields_count
+		    != bs_boxed->as.s->fields_count) {
+		rb_raise(rb_eTypeError,
+			"expected instance of Boxed with %d fields, got %d",
+			bs_boxed->as.s->fields_count, 
+			rval_bs_boxed->as.s->fields_count);
+	    }
+
+	    for (unsigned i = 0; i < bs_boxed->as.s->fields_count; i++) {
+		if (strcmp(bs_boxed->as.s->fields[i].type,
+			    rval_bs_boxed->as.s->fields[i].type) != 0) {
+		    rb_raise(rb_eTypeError,
+			"field %d of given instance of `%s' does not match " \
+			"the type expected (%s, got %s)",
+			i,
+			rb_class2name(bs_boxed->klass),
+			bs_boxed->as.s->fields[i].type,
+			rval_bs_boxed->as.s->fields[i].type);	
+		}
+	    }
+	}
+
+	VALUE *data;
+	Data_Get_Struct(rval, VALUE, data);
+
+	for (unsigned i = 0; i < bs_boxed->as.s->fields_count; i++) {
+	    buf[i] = data[i];
+	}	
+    }
+}
+
 static VALUE
 rb_boxed_objc_type(VALUE rcv, SEL sel)
 {
@@ -797,7 +959,16 @@
 RoxorCore::find_bs_struct(std::string type)
 {
     rb_vm_bs_boxed_t *boxed = find_bs_boxed(type);
-    return boxed == NULL ? NULL : boxed->is_struct() ? boxed : NULL;
+    if (boxed != NULL) {
+	if (boxed->is_struct()) {
+	    return boxed;
+	}
+	return NULL;
+    }
+
+    // Given structure type does not exist... but it may be an anonymous
+    // type (like {?=qq}) which is sometimes present in BridgeSupport files...
+    return register_anonymous_bs_struct(type.c_str());
 }
 
 rb_vm_bs_boxed_t *
@@ -1079,7 +1250,6 @@
 
 	case BS_ELEMENT_CFTYPE:
 	{
-	    
 	    bs_element_cftype_t *bs_cftype = (bs_element_cftype_t *)value;
 	    std::map<std::string, bs_element_cftype_t *>::iterator
 		iter = bs_cftypes.find(bs_cftype->type);
@@ -1132,7 +1302,8 @@
 
     char *error = NULL;
     const bool ok = bs_parser_parse(bs_parser, path, framework_path,
-	    (bs_parse_options_t)options, __bs_parse_cb, rb_cObject_dict, &error);
+	    (bs_parse_options_t)options, __bs_parse_cb, rb_cObject_dict,
+	    &error);
     if (!ok) {
 	rb_raise(rb_eRuntimeError, "%s", error);
     }

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2010-04-24 20:12:57 UTC (rev 3961)
+++ MacRuby/trunk/compiler.cpp	2010-04-26 03:32:23 UTC (rev 3962)
@@ -6029,17 +6029,6 @@
     return f;
 }
 
-static inline const char *
-GetFirstType(const char *p, char *buf, size_t buflen)
-{
-    const char *p2 = SkipFirstType(p);
-    const size_t len = p2 - p;
-    assert(len < buflen);
-    strncpy(buf, p, len);
-    buf[len] = '\0';
-    return SkipStackSize(p2);
-}
-
 static inline void
 convert_error(const char type, VALUE val)
 {
@@ -6248,92 +6237,7 @@
     return *cptr;
 }
 
-static inline long
-rebuild_new_struct_ary(const StructType *type, VALUE orig, VALUE new_ary)
-{
-    long n = 0;
-
-    for (StructType::element_iterator iter = type->element_begin();
-	 iter != type->element_end();
-	 ++iter) {
-
-	const Type *ftype = *iter;
-	
-	if (ftype->getTypeID() == Type::StructTyID) {
-            long i, n2;
-            VALUE tmp;
-
-            n2 = rebuild_new_struct_ary(cast<StructType>(ftype), orig, new_ary);
-            tmp = rb_ary_new();
-            for (i = 0; i < n2; i++) {
-                if (RARRAY_LEN(orig) == 0) {
-                    return 0;
-		}
-                rb_ary_push(tmp, rb_ary_shift(orig));
-            }
-            rb_ary_push(new_ary, tmp);
-        }
-        n++;
-    }
-
-    return n;
-}
-
-extern "C"
 void
-rb_vm_get_struct_fields(VALUE rval, VALUE *buf, rb_vm_bs_boxed_t *bs_boxed)
-{
-    if (TYPE(rval) == T_ARRAY) {
-	unsigned n = RARRAY_LEN(rval);
-	if (n < bs_boxed->as.s->fields_count) {
-	    rb_raise(rb_eArgError,
-		    "not enough elements in array `%s' to create " \
-		    "structure `%s' (%d for %d)",
-		    RSTRING_PTR(rb_inspect(rval)), bs_boxed->as.s->name, n,
-		    bs_boxed->as.s->fields_count);
-	}
-
-	if (n > bs_boxed->as.s->fields_count) {
-	    VALUE new_rval = rb_ary_new();
-	    VALUE orig = rval;
-	    rval = rb_ary_dup(rval);
-	    rebuild_new_struct_ary(cast<StructType>(bs_boxed->type), rval,
-		    new_rval);
-	    n = RARRAY_LEN(new_rval);
-	    if (RARRAY_LEN(rval) != 0 || n != bs_boxed->as.s->fields_count) {
-		rb_raise(rb_eArgError,
-			"too much elements in array `%s' to create " \
-			"structure `%s' (%ld for %d)",
-			RSTRING_PTR(rb_inspect(orig)),
-			bs_boxed->as.s->name, RARRAY_LEN(orig),
-			bs_boxed->as.s->fields_count);
-	    }
-	    rval = new_rval;
-	}
-
-	for (unsigned i = 0; i < n; i++) {
-	    buf[i] = RARRAY_AT(rval, i);
-	}
-    }
-    else {
-	if (!rb_obj_is_kind_of(rval, bs_boxed->klass)) {
-	    rb_raise(rb_eTypeError, 
-		    "expected instance of `%s', got `%s' (%s)",
-		    rb_class2name(bs_boxed->klass),
-		    RSTRING_PTR(rb_inspect(rval)),
-		    rb_obj_classname(rval));
-	}
-
-	VALUE *data;
-	Data_Get_Struct(rval, VALUE, data);
-
-	for (unsigned i = 0; i < bs_boxed->as.s->fields_count; i++) {
-	    buf[i] = data[i];
-	}	
-    }
-}
-
-void
 RoxorCompiler::compile_get_struct_fields(Value *val, Value *buf,
 					 rb_vm_bs_boxed_t *bs_boxed)
 {
@@ -6530,8 +6434,10 @@
 
         case _C_FPTR_B:
 	    {
-		GlobalVariable *proc_gvar = new GlobalVariable(*RoxorCompiler::module,
-			RubyObjTy, false, GlobalValue::InternalLinkage, nilVal, "");
+		GlobalVariable *proc_gvar =
+		    new GlobalVariable(*RoxorCompiler::module,
+			    RubyObjTy, false, GlobalValue::InternalLinkage,
+			    nilVal, "");
 		new StoreInst(val, proc_gvar, bb);
 
 		char buf[100];
@@ -6799,7 +6705,7 @@
 
 Value *
 RoxorCompiler::compile_conversion_to_ruby(const char *type,
-					  const Type *llvm_type, Value *val)
+	const Type *llvm_type, Value *val)
 {
     const char *func_name = NULL;
 

Modified: MacRuby/trunk/objc.h
===================================================================
--- MacRuby/trunk/objc.h	2010-04-24 20:12:57 UTC (rev 3961)
+++ MacRuby/trunk/objc.h	2010-04-26 03:32:23 UTC (rev 3962)
@@ -151,6 +151,17 @@
     }
 }
 
+static inline const char *
+GetFirstType(const char *p, char *buf, size_t buflen)
+{
+    const char *p2 = SkipFirstType(p);
+    const size_t len = p2 - p;
+    assert(len < buflen);
+    strncpy(buf, p, len);
+    buf[len] = '\0';
+    return SkipStackSize(p2);
+}
+
 static inline unsigned int
 TypeArity(const char *type)
 {

Modified: MacRuby/trunk/spec/macruby/fixtures/method.m
===================================================================
--- MacRuby/trunk/spec/macruby/fixtures/method.m	2010-04-24 20:12:57 UTC (rev 3961)
+++ MacRuby/trunk/spec/macruby/fixtures/method.m	2010-04-26 03:32:23 UTC (rev 3962)
@@ -720,6 +720,16 @@
     return ptr == NULL;
 }
 
+typedef struct {
+    CGFloat f1;
+    CGFloat f2;
+} anon_struct;
+
+- (BOOL)methodAcceptingAnonymousStructure:(anon_struct)s
+{
+    return s.f1 == 42 && s.f2 == 4200;
+}
+
 extern id objc_msgSend(id self, SEL op, ...);
 
 - (void)methodAcceptingSEL:(SEL)sel target:(id)target

Modified: MacRuby/trunk/spec/macruby/language/objc_method_spec.rb
===================================================================
--- MacRuby/trunk/spec/macruby/language/objc_method_spec.rb	2010-04-24 20:12:57 UTC (rev 3961)
+++ MacRuby/trunk/spec/macruby/language/objc_method_spec.rb	2010-04-26 03:32:23 UTC (rev 3962)
@@ -426,6 +426,22 @@
     end
     @o.methodAcceptingSEL('foo:arg1:arg2:', target:o)
   end
+
+  it "accepting an anonymous structure should be given a Boxed object that matches the types" do
+    @o.methodSignatureForSelector(:'methodAcceptingAnonymousStructure:').getArgumentTypeAtIndex(2).should == '{?=dd}'
+
+    @o.methodAcceptingAnonymousStructure(NSPoint.new(42, 4200)).should == 1
+    @o.methodAcceptingAnonymousStructure(NSSize.new(42, 4200)).should == 1
+    @o.methodAcceptingAnonymousStructure([42, 4200]).should == 1
+    @o.methodAcceptingAnonymousStructure(NSPoint.new(42, 4201)).should == 0
+    @o.methodAcceptingAnonymousStructure(NSSize.new(42, 4201)).should == 0
+    @o.methodAcceptingAnonymousStructure([42, 4201]).should == 0
+
+    lambda { @o.methodAcceptingAnonymousStructure([42]) }.should raise_error(ArgumentError)
+    lambda { @o.methodAcceptingAnonymousStructure([42, 4200, 42]) }.should raise_error(ArgumentError)
+    lambda { @o.methodAcceptingAnonymousStructure(nil) }.should raise_error(TypeError)
+    lambda { @o.methodAcceptingAnonymousStructure(NSRange.new(42, 4200)) }.should raise_error(TypeError)
+  end
 end
 
 describe "A pure MacRuby method" do

Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h	2010-04-24 20:12:57 UTC (rev 3961)
+++ MacRuby/trunk/vm.h	2010-04-26 03:32:23 UTC (rev 3962)
@@ -847,6 +847,7 @@
     private:
 	bool register_bs_boxed(bs_element_type_t type, void *value);
 	void register_bs_class(bs_element_class_t *bs_class);
+	rb_vm_bs_boxed_t *register_anonymous_bs_struct(const char *type);
 };
 
 #define GET_CORE() (RoxorCore::shared)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100425/5c765e8e/attachment-0001.html>


More information about the macruby-changes mailing list