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

source_changes at macosforge.org source_changes at macosforge.org
Thu Apr 23 15:50:17 PDT 2009


Revision: 1477
          http://trac.macosforge.org/projects/ruby/changeset/1477
Author:   lsansonetti at apple.com
Date:     2009-04-23 15:50:17 -0700 (Thu, 23 Apr 2009)
Log Message:
-----------
implemented struct writers

Modified Paths:
--------------
    MacRuby/branches/experimental/roxor.cpp
    MacRuby/branches/experimental/spec/macruby/struct_spec.rb

Modified: MacRuby/branches/experimental/roxor.cpp
===================================================================
--- MacRuby/branches/experimental/roxor.cpp	2009-04-23 05:38:29 UTC (rev 1476)
+++ MacRuby/branches/experimental/roxor.cpp	2009-04-23 22:50:17 UTC (rev 1477)
@@ -201,6 +201,8 @@
 	Function *compile_write_attr(ID name);
 	Function *compile_stub(const char *types, int argc, bool is_objc);
 	Function *compile_bs_struct_new(rb_vm_bs_boxed_t *bs_boxed);
+	Function *compile_bs_struct_writer(rb_vm_bs_boxed_t *bs_boxed,
+		int field);
 
     private:
 	const char *fname;
@@ -266,6 +268,7 @@
 	Function *newStructFunc;
 	Function *getStructFieldsFunc;
 	Function *checkArityFunc;
+	Function *setStructFunc;
 	Function *newRangeFunc;
 	Function *newRegexpFunc;
 	Function *strInternFunc;
@@ -351,6 +354,7 @@
 	void compile_get_struct_fields(Value *val, Value *buf,
 		rb_vm_bs_boxed_t *bs_boxed);
 	void compile_check_arity(Value *given, Value *requested);
+	void compile_set_struct(Value *rcv, int field, Value *val);
 
 	Value *compile_conversion_to_c(const char *type, Value *val,
 				       Value *slot);
@@ -661,6 +665,7 @@
     newStructFunc = NULL;
     getStructFieldsFunc = NULL;
     checkArityFunc = NULL;
+    setStructFunc = NULL;
     newRangeFunc = NULL;
     newRegexpFunc = NULL;
     strInternFunc = NULL;
@@ -8334,9 +8339,65 @@
     compile_protected_call(checkArityFunc, params);
 }
 
+extern "C"
+void
+rb_vm_set_struct(VALUE rcv, int field, VALUE val)
+{
+    VALUE *data;
+    Data_Get_Struct(rcv, VALUE, data);
+    GC_WB(&data[field], val);    
+}
+
+void
+RoxorCompiler::compile_set_struct(Value *rcv, int field, Value *val)
+{
+    if (setStructFunc == NULL) {
+	// void rb_vm_set_struct(VALUE rcv, int field, VALUE val);
+	setStructFunc = cast<Function>(module->getOrInsertFunction(
+		    "rb_vm_set_struct",
+		    Type::VoidTy, RubyObjTy, Type::Int32Ty, RubyObjTy, NULL));
+    }
+
+    std::vector<Value *> params;
+    params.push_back(rcv);
+    params.push_back(ConstantInt::get(Type::Int32Ty, field));
+    params.push_back(val);
+
+    CallInst::Create(setStructFunc, params.begin(), params.end(), "", bb);
+}
+
 Function *
+RoxorCompiler::compile_bs_struct_writer(rb_vm_bs_boxed_t *bs_boxed, int field)
+{
+    // VALUE foo(VALUE self, SEL sel, VALUE val);
+    Function *f = cast<Function>(module->getOrInsertFunction("",
+		RubyObjTy, RubyObjTy, PtrTy, RubyObjTy, NULL));
+    Function::arg_iterator arg = f->arg_begin();
+    Value *self = arg++; 	// self
+    arg++;			// sel
+    Value *val = arg++; 	// val
+
+    bb = BasicBlock::Create("EntryBlock", f);
+
+    assert((unsigned)field < bs_boxed->as.s->fields_count);
+    const char *ftype = bs_boxed->as.s->fields[field].type;
+    const Type *llvm_type = convert_type(ftype);
+
+    Value *fval = new AllocaInst(llvm_type, "", bb);
+    val = compile_conversion_to_c(ftype, val, fval);
+    val = compile_conversion_to_ruby(ftype, llvm_type, val);
+
+    compile_set_struct(self, field, val);
+
+    ReturnInst::Create(val, bb);
+
+    return f;
+}
+
+Function *
 RoxorCompiler::compile_bs_struct_new(rb_vm_bs_boxed_t *bs_boxed)
 {
+    // VALUE foo(VALUE self, SEL sel, int argc, VALUE *argv);
     Function *f = cast<Function>(module->getOrInsertFunction("",
 		RubyObjTy, RubyObjTy, PtrTy, Type::Int32Ty, RubyObjPtrTy,
 		NULL));
@@ -8415,16 +8476,21 @@
 
 static ID boxed_ivar_type = 0;
 
-static VALUE
-rb_vm_struct_fake_new(VALUE rcv, SEL sel, int argc, VALUE *argv)
+static inline rb_vm_bs_boxed_t *
+locate_bs_boxed(VALUE klass)
 {
-    // Locate the boxed structure.
-    VALUE type = rb_ivar_get(rcv, boxed_ivar_type);
+    VALUE type = rb_ivar_get(klass, boxed_ivar_type);
     assert(type != Qnil);
     rb_vm_bs_boxed_t *bs_boxed = GET_VM()->find_bs_struct(RSTRING_PTR(type));
     assert(bs_boxed != NULL);
+    return bs_boxed;
+}
 
+static VALUE
+rb_vm_struct_fake_new(VALUE rcv, SEL sel, int argc, VALUE *argv)
+{
     // Generate the real #new method.
+    rb_vm_bs_boxed_t *bs_boxed = locate_bs_boxed(rcv);
     Function *f = RoxorCompiler::shared->compile_bs_struct_new(bs_boxed);
     IMP imp = GET_VM()->compile(f);
 
@@ -8435,6 +8501,43 @@
     return ((VALUE (*)(VALUE, SEL, int, VALUE *))imp)(rcv, sel, argc, argv);
 }
 
+static VALUE
+rb_vm_struct_fake_set(VALUE rcv, SEL sel, VALUE val)
+{
+    // Locate the given field.
+    char buf[100];
+    const char *selname = sel_getName(sel);
+    size_t s = strlcpy(buf, selname, sizeof buf);
+    if (buf[s - 1] == ':') {
+	s--;
+    }
+    assert(buf[s - 1] == '=');
+    buf[s - 1] = '\0';
+    rb_vm_bs_boxed_t *bs_boxed = locate_bs_boxed(CLASS_OF(rcv));
+    int field = -1;
+    for (unsigned i = 0; i < bs_boxed->as.s->fields_count; i++) {
+	const char *fname = bs_boxed->as.s->fields[i].name;
+	if (strcmp(fname, buf) == 0) {
+	    field = i;
+	    break;
+	}
+    }
+    assert(field != -1); 
+
+    // Generate the new setter method.
+    Function *f = RoxorCompiler::shared->compile_bs_struct_writer(
+	    bs_boxed, field);
+    IMP imp = GET_VM()->compile(f);
+
+    // Replace the fake method with the new one in the runtime.
+    buf[s - 1] = '=';
+    buf[s] = '\0';
+    rb_objc_define_method(*(VALUE *)rcv, buf, (void *)imp, 1); 
+
+    // Call the new method.
+    return ((VALUE (*)(VALUE, SEL, VALUE))imp)(rcv, sel, val);
+}
+
 // Readers are statically generated.
 #include "bs_struct_readers.c"
 
@@ -8472,7 +8575,11 @@
 	    // Readers.
 	    rb_objc_define_method(boxed->klass, boxed->as.s->fields[i].name,
 		    (void *)struct_readers[i], 0);
-	    // Writers. (TODO)
+	    // Writers.
+	    char buf[100];
+	    snprintf(buf, sizeof buf, "%s=", boxed->as.s->fields[i].name);
+	    rb_objc_define_method(boxed->klass, buf,
+		    (void *)rb_vm_struct_fake_set, 1);
 	}
     }
 

Modified: MacRuby/branches/experimental/spec/macruby/struct_spec.rb
===================================================================
--- MacRuby/branches/experimental/spec/macruby/struct_spec.rb	2009-04-23 05:38:29 UTC (rev 1476)
+++ MacRuby/branches/experimental/spec/macruby/struct_spec.rb	2009-04-23 22:50:17 UTC (rev 1477)
@@ -13,34 +13,34 @@
   it "can be created with null values using the #new method with no argument" do
     o = NSPoint.new
     o.x.class.should == Float
+    o.y.class.should == Float
     o.x.should == 0.0
-    o.y.class.should == Float
     o.y.should == 0.0
 
     o = NSRect.new
     o.origin.class.should == NSPoint
     o.origin.x.class.should == Float
+    o.origin.y.class.should == Float
     o.origin.x.should == 0.0
-    o.origin.y.class.should == Float
     o.origin.y.should == 0.0
     o.size.class.should == NSSize
     o.size.width.class.should == Float
+    o.size.height.class.should == Float
     o.size.width.should == 0.0
-    o.size.height.class.should == Float
     o.size.height.should == 0.0
   end
 
   it "can be created with given values using the #new method with arguments" do
     o = NSPoint.new(1.0, 2.0)
+    o.y.class.should == Float
     o.x.class.should == Float
     o.x.should == 1.0
-    o.y.class.should == Float
     o.y.should == 2.0
 
     o = NSPoint.new(1, 2)
     o.x.class.should == Float
+    o.y.class.should == Float
     o.x.should == 1.0
-    o.y.class.should == Float
     o.y.should == 2.0
 
     fix1 = Object.new; def fix1.to_f; 1.0; end
@@ -48,8 +48,8 @@
 
     o = NSPoint.new(fix1, fix2)
     o.x.class.should == Float
+    o.y.class.should == Float
     o.x.should == 1.0
-    o.y.class.should == Float
     o.y.should == 2.0
 
     lambda { NSPoint.new(1) }.should raise_error(ArgumentError) 
@@ -60,13 +60,13 @@
     o = NSRect.new(NSPoint.new(1, 2), NSSize.new(3, 4))
     o.origin.class.should == NSPoint
     o.origin.x.class.should == Float
+    o.origin.y.class.should == Float
     o.origin.x == 1.0
-    o.origin.y.class.should == Float
     o.origin.y == 2.0
     o.size.class.should == NSSize
     o.size.width.class.should == Float
+    o.size.height.class.should == Float
     o.size.width == 3.0
-    o.size.height.class.should == Float
     o.size.height == 4.0
 
     lambda { NSRect.new(1) }.should raise_error(ArgumentError)
@@ -77,4 +77,42 @@
     lambda { NSRect.new(nil, nil) }.should raise_error(TypeError)
   end
 
+  it "has accessors for every field" do
+    p = NSPoint.new
+    p.x = 1
+    p.y = 2
+    p.x.class.should == Float
+    p.y.class.should == Float
+    p.x.should == 1.0
+    p.y.should == 2.0
+
+    s = NSSize.new
+    s.width = 3
+    s.height = 4
+    s.width.class.should == Float
+    s.height.class.should == Float
+    s.width.should == 3.0
+    s.height.should == 4.0
+
+    r = NSRect.new
+    r.origin = p
+    r.size = s
+    r.origin.class.should == NSPoint
+    r.size.class.should == NSSize
+
+    lambda { r.origin = nil }.should raise_error(TypeError)
+    lambda { r.origin = Object.new }.should raise_error(TypeError)
+
+    r.origin = [123, 456]
+    r.size = [789, 100]
+    
+    r.origin.x.class.should == Float
+    r.origin.y.class.should == Float
+    r.size.width.class.should == Float
+    r.size.height.class.should == Float
+    r.origin.x.should == 123.0
+    r.origin.y.should == 456.0
+    r.size.width.should == 789.0
+    r.size.height.should == 100.0
+  end
 end
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090423/c832f230/attachment.html>


More information about the macruby-changes mailing list