[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