[macruby-changes] [3845] MacRuby/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Mon Mar 22 21:29:32 PDT 2010
Revision: 3845
http://trac.macosforge.org/projects/ruby/changeset/3845
Author: lsansonetti at apple.com
Date: 2010-03-22 21:29:30 -0700 (Mon, 22 Mar 2010)
Log Message:
-----------
started NSNumber / NSString extensions
Modified Paths:
--------------
MacRuby/trunk/numeric.c
MacRuby/trunk/rakelib/builder/builder.rb
MacRuby/trunk/string.c
Added Paths:
-----------
MacRuby/trunk/NSNumber.m
MacRuby/trunk/NSString.m
Added: MacRuby/trunk/NSNumber.m
===================================================================
--- MacRuby/trunk/NSNumber.m (rev 0)
+++ MacRuby/trunk/NSNumber.m 2010-03-23 04:29:30 UTC (rev 3845)
@@ -0,0 +1,424 @@
+/*
+ * MacRuby extensions to NSNumber.
+ *
+ * This file is covered by the Ruby license. See COPYING for more details.
+ *
+ * Copyright (C) 2010, Apple Inc. All rights reserved.
+ */
+
+#import <Foundation/Foundation.h>
+
+#include "ruby/ruby.h"
+#include "ruby/node.h"
+#include "objc.h"
+#include "vm.h"
+
+VALUE rb_cNSNumber;
+
+ at interface NSNumber (IsFloatExtension)
+- (BOOL)isFloat;
+ at end
+
+static id
+get_nsnumber(VALUE obj)
+{
+ // TODO: handle bignums, #to_i / #to_f generic objects
+ id num = RB2OC(obj);
+ if (![num isKindOfClass:[NSNumber class]]) {
+ rb_raise(rb_eTypeError, "excepted NSNumber-like object, got `%s'",
+ [[[num class] description] UTF8String]);
+ }
+ return num;
+}
+
+static VALUE
+get_numeric(id obj)
+{
+ return [obj isFloat]
+ ? DOUBLE2NUM([obj doubleValue]) : LONG2NUM([obj longValue]);
+}
+
+static id
+nsnumber_to_s(id rcv, SEL sel)
+{
+ return [rcv stringValue];
+}
+
+static id
+nsnumber_to_i(id rcv, SEL sel)
+{
+ if ([rcv isFloat]) {
+ const long val = [rcv longValue];
+ return [NSNumber numberWithLong:val];
+ }
+ return rcv;
+}
+
+static id
+nsnumber_to_f(id rcv, SEL sel)
+{
+ if (![rcv isFloat]) {
+ const double val = [rcv doubleValue];
+ return [NSNumber numberWithDouble:val];
+ }
+ return rcv;
+}
+
+static VALUE
+nsnumber_coerce(id rcv, SEL sel, VALUE other)
+{
+ id num = get_nsnumber(other);
+ VALUE x = get_numeric(rcv);
+ VALUE y = get_numeric(num);
+
+ if (CLASS_OF(x) == CLASS_OF(y)) {
+ return rb_assoc_new(y, x);
+ }
+ return rb_assoc_new(rb_Float(y), rb_Float(x));
+}
+
+static id
+nsnumber_uplus(id rcv, SEL sel)
+{
+ return rcv;
+}
+
+static id
+nsnumber_uminus(id rcv, SEL sel)
+{
+ return [rcv isFloat]
+ ? [NSNumber numberWithDouble:-[rcv doubleValue]]
+ : [NSNumber numberWithLong:-[rcv longValue]];
+}
+
+static id
+nsnumber_plus(id rcv, SEL sel, VALUE other)
+{
+ id num = get_nsnumber(other);
+ if ([rcv isFloat] || [num isFloat]) {
+ return [NSNumber numberWithDouble:
+ [rcv doubleValue] + [num doubleValue]];
+ }
+ return [NSNumber numberWithLong:[rcv longValue] + [num longValue]];
+}
+
+static id
+nsnumber_minus(id rcv, SEL sel, VALUE other)
+{
+ id num = get_nsnumber(other);
+ if ([rcv isFloat] || [num isFloat]) {
+ return [NSNumber numberWithDouble:
+ [rcv doubleValue] - [num doubleValue]];
+ }
+ return [NSNumber numberWithLong:[rcv longValue] - [num longValue]];
+}
+
+static id
+nsnumber_mul(id rcv, SEL sel, VALUE other)
+{
+ id num = get_nsnumber(other);
+ if ([rcv isFloat] || [num isFloat]) {
+ return [NSNumber numberWithDouble:
+ [rcv doubleValue] * [num doubleValue]];
+ }
+ return [NSNumber numberWithLong:[rcv longValue] * [num longValue]];
+}
+
+static id
+nsnumber_divide(id x, id y, bool fdiv)
+{
+ if (fdiv) {
+ return [NSNumber numberWithDouble:
+ [x doubleValue] / [y doubleValue]];
+ }
+ const long val = [y longValue];
+ if (val == 0) {
+ rb_raise(rb_eZeroDivError, "divided by 0");
+ }
+ return [NSNumber numberWithLong:[x longValue] / val];
+}
+
+static id
+nsnumber_div(id rcv, SEL sel, VALUE other)
+{
+ id num = get_nsnumber(other);
+ return nsnumber_divide(rcv, num, [rcv isFloat] || [num isFloat]);
+}
+
+static id
+nsnumber_idiv(id rcv, SEL sel, VALUE other)
+{
+ id num = get_nsnumber(other);
+ return nsnumber_divide(rcv, num, false);
+}
+
+static id
+nsnumber_fdiv(id rcv, SEL sel, VALUE other)
+{
+ id num = get_nsnumber(other);
+ return nsnumber_divide(rcv, num, true);
+}
+
+static id
+nsnumber_mod(id rcv, SEL sel, VALUE other)
+{
+ id num = get_nsnumber(other);
+ if ([rcv isFloat] || [num isFloat]) {
+ return [NSNumber numberWithDouble:
+ fmod([rcv doubleValue], [num doubleValue])];
+ }
+ const long val = [num longValue];
+ if (val == 0) {
+ rb_raise(rb_eZeroDivError, "divided by 0");
+ }
+ return [NSNumber numberWithLong:[rcv longValue] % val];
+}
+
+static id
+nsnumber_divmod(id rcv, SEL sel, VALUE other)
+{
+ id num = get_nsnumber(other);
+ NSNumber *div, *mod;
+ if ([rcv isFloat] || [num isFloat]) {
+ div = [NSNumber numberWithDouble:
+ [rcv doubleValue] / [num doubleValue]];
+ mod = [NSNumber numberWithDouble:
+ fmod([rcv doubleValue], [num doubleValue])];
+ }
+ else {
+ const long val = [num longValue];
+ if (val == 0) {
+ rb_raise(rb_eZeroDivError, "divided by 0");
+ }
+ div = [NSNumber numberWithLong:[rcv longValue] / val];
+ mod = [NSNumber numberWithLong:[rcv longValue] % val];
+ }
+ return [NSArray arrayWithObjects:div, mod, NULL];
+}
+
+//static id
+//nsnumber_pow(id rcv, SEL sel, VALUE other)
+//{
+//}
+
+static id
+nsnumber_abs(id rcv, SEL sel)
+{
+ if ([rcv isFloat]) {
+ double val = [rcv doubleValue];
+ if (val < 0) {
+ val = -val;
+ return [NSNumber numberWithDouble:val];
+ }
+ return rcv;
+ }
+ long val = [rcv longValue];
+ if (val < 0) {
+ val = -val;
+ return [NSNumber numberWithLong:val];
+ }
+ return rcv;
+}
+
+static VALUE
+nsnumber_equal(id rcv, SEL sel, VALUE other)
+{
+ return [rcv isEqualToNumber:get_nsnumber(other)] ? Qtrue : Qfalse;
+}
+
+static VALUE
+nsnumber_cmp(id rcv, SEL sel, VALUE other)
+{
+ const int res = [rcv compare:get_nsnumber(other)];
+ return res == 0
+ ? INT2FIX(0)
+ : res < 0
+ ? INT2FIX(-1)
+ : INT2FIX(1);
+}
+
+static VALUE
+nsnumber_gt(id rcv, SEL sel, VALUE other)
+{
+ const int res = [rcv compare:get_nsnumber(other)];
+ return res > 0 ? Qtrue : Qfalse;
+}
+
+static VALUE
+nsnumber_ge(id rcv, SEL sel, VALUE other)
+{
+ const int res = [rcv compare:get_nsnumber(other)];
+ return res >= 0 ? Qtrue : Qfalse;
+}
+
+static VALUE
+nsnumber_lt(id rcv, SEL sel, VALUE other)
+{
+ const int res = [rcv compare:get_nsnumber(other)];
+ return res < 0 ? Qtrue : Qfalse;
+}
+
+static VALUE
+nsnumber_le(id rcv, SEL sel, VALUE other)
+{
+ const int res = [rcv compare:get_nsnumber(other)];
+ return res <= 0 ? Qtrue : Qfalse;
+}
+
+static void
+assume_integral(id obj)
+{
+ if ([obj isFloat]) {
+ rb_raise(rb_eTypeError, "expected integral (non-float) NSNumber");
+ }
+}
+
+static id
+nsnumber_rev(id rcv, SEL sel)
+{
+ assume_integral(rcv);
+ long val = [rcv longValue];
+ val = ~val;
+ return [NSNumber numberWithLong:val];
+}
+
+static id
+nsnumber_and(id rcv, SEL sel, VALUE other)
+{
+ assume_integral(rcv);
+ long val = [rcv longValue] & [get_nsnumber(other) longValue];
+ return [NSNumber numberWithLong:val];
+}
+
+static id
+nsnumber_or(id rcv, SEL sel, VALUE other)
+{
+ assume_integral(rcv);
+ long val = [rcv longValue] | [get_nsnumber(other) longValue];
+ return [NSNumber numberWithLong:val];
+}
+
+static id
+nsnumber_xor(id rcv, SEL sel, VALUE other)
+{
+ assume_integral(rcv);
+ long val = [rcv longValue] ^ [get_nsnumber(other) longValue];
+ return [NSNumber numberWithLong:val];
+}
+
+static VALUE
+nsnumber_aref(id rcv, SEL sel, VALUE other)
+{
+ assume_integral(rcv);
+ const long val = [rcv longValue];
+
+ const long i = FIX2LONG(other);
+ if (i < 0) {
+ return INT2FIX(0);
+ }
+ if (SIZEOF_LONG * CHAR_BIT-1 < i) {
+ if (val < 0) {
+ return INT2FIX(1);
+ }
+ return INT2FIX(0);
+ }
+ if (val & (1L << i)) {
+ return INT2FIX(1);
+ }
+ return INT2FIX(0);
+}
+
+static VALUE
+nsnumber_lshift(id rcv, SEL sel, VALUE other)
+{
+ assume_integral(rcv);
+ long val = [rcv longValue];
+ const long width = NUM2LONG(other);
+
+ if (width < 0) {
+ val = val >> -width;
+ }
+ else {
+ val = val << width;
+ }
+ return LONG2NUM(val);
+}
+
+static VALUE
+nsnumber_rshift(id rcv, SEL sel, VALUE other)
+{
+ assume_integral(rcv);
+ long val = [rcv longValue];
+ const long width = NUM2LONG(other);
+
+ if (width < 0) {
+ val = val << -width;
+ }
+ else {
+ val = val >> width;
+ }
+ return LONG2NUM(val);
+}
+
+static void *
+imp_nsnumber_to_int(void *rcv, SEL sel)
+{
+ // This is because some NSNumber subclasses must be converted to real
+ // CFNumber objects, in order to be coerced into Fixnum objects.
+ long val = 0;
+ if (!CFNumberGetValue((CFNumberRef)rcv, kCFNumberLongType, &val)) {
+ rb_raise(rb_eTypeError, "cannot get 'long' value out of NSNumber %p",
+ rcv);
+ }
+ CFNumberRef new_num = CFNumberCreate(NULL, kCFNumberLongType, &val);
+ CFMakeCollectable(new_num);
+ return (void *)new_num;
+}
+
+void
+Init_NSNumber(void)
+{
+ rb_cNSNumber = (VALUE)objc_getClass("NSNumber");
+ assert(rb_cNSNumber != 0);
+
+ rb_objc_define_method(rb_cNSNumber, "to_s", nsnumber_to_s, 0);
+ rb_objc_define_method(rb_cNSNumber, "to_i", nsnumber_to_i, 0);
+ rb_objc_define_method(rb_cNSNumber, "to_f", nsnumber_to_f, 0);
+ rb_objc_define_method(rb_cNSNumber, "coerce", nsnumber_coerce, 1);
+ rb_objc_define_method(rb_cNSNumber, "+@", nsnumber_uplus, 0);
+ rb_objc_define_method(rb_cNSNumber, "-@", nsnumber_uminus, 0);
+ rb_objc_define_method(rb_cNSNumber, "+", nsnumber_plus, 1);
+ rb_objc_define_method(rb_cNSNumber, "-", nsnumber_minus, 1);
+ rb_objc_define_method(rb_cNSNumber, "*", nsnumber_mul, 1);
+ rb_objc_define_method(rb_cNSNumber, "/", nsnumber_div, 1);
+ rb_objc_define_method(rb_cNSNumber, "div", nsnumber_idiv, 1);
+ rb_objc_define_method(rb_cNSNumber, "%", nsnumber_mod, 1);
+ rb_objc_define_method(rb_cNSNumber, "modulo", nsnumber_mod, 1);
+ rb_objc_define_method(rb_cNSNumber, "divmod", nsnumber_divmod, 1);
+ rb_objc_define_method(rb_cNSNumber, "fdiv", nsnumber_fdiv, 1);
+ //rb_objc_define_method(rb_cNSNumber, "**", nsnumber_pow, 1);
+ rb_objc_define_method(rb_cNSNumber, "abs", nsnumber_abs, 0);
+ rb_objc_define_method(rb_cNSNumber, "==", nsnumber_equal, 1);
+ rb_objc_define_method(rb_cNSNumber, "<=>", nsnumber_cmp, 1);
+ rb_objc_define_method(rb_cNSNumber, ">", nsnumber_gt, 1);
+ rb_objc_define_method(rb_cNSNumber, ">=", nsnumber_ge, 1);
+ rb_objc_define_method(rb_cNSNumber, "<", nsnumber_lt, 1);
+ rb_objc_define_method(rb_cNSNumber, "<=", nsnumber_le, 1);
+ rb_objc_define_method(rb_cNSNumber, "~", nsnumber_rev, 0);
+ rb_objc_define_method(rb_cNSNumber, "&", nsnumber_and, 1);
+ rb_objc_define_method(rb_cNSNumber, "|", nsnumber_or, 1);
+ rb_objc_define_method(rb_cNSNumber, "^", nsnumber_xor, 1);
+ rb_objc_define_method(rb_cNSNumber, "[]", nsnumber_aref, 1);
+ rb_objc_define_method(rb_cNSNumber, "<<", nsnumber_lshift, 1);
+ rb_objc_define_method(rb_cNSNumber, ">>", nsnumber_rshift, 1);
+
+ class_replaceMethod((Class)rb_cNSNumber, sel_registerName("to_int"),
+ (IMP)imp_nsnumber_to_int, "@@:");
+}
+
+ at implementation NSNumber (IsFLoatExtension)
+- (BOOL)isFloat
+{
+ return CFNumberIsFloatType((CFNumberRef)self);
+}
+ at end
Added: MacRuby/trunk/NSString.m
===================================================================
--- MacRuby/trunk/NSString.m (rev 0)
+++ MacRuby/trunk/NSString.m 2010-03-23 04:29:30 UTC (rev 3845)
@@ -0,0 +1,45 @@
+/*
+ * MacRuby extensions to NSString.
+ *
+ * This file is covered by the Ruby license. See COPYING for more details.
+ *
+ * Copyright (C) 2010, Apple Inc. All rights reserved.
+ */
+
+#import <Foundation/Foundation.h>
+
+#include "ruby/ruby.h"
+#include "ruby/node.h"
+#include "objc.h"
+#include "vm.h"
+#include "encoding.h"
+
+VALUE rb_cString;
+VALUE rb_cNSString;
+VALUE rb_cNSMutableString;
+
+static id
+nsstr_inspect(id rcv, SEL sel)
+{
+ return [NSString stringWithFormat:@"\"%@\"", rcv];
+}
+
+static id
+nsstr_to_s(id rcv, SEL sel)
+{
+ return rcv;
+}
+
+void
+Init_NSString(void)
+{
+ rb_cNSString = (VALUE)objc_getClass("NSString");
+ assert(rb_cNSString != 0);
+ rb_cString = rb_cNSString;
+ rb_include_module(rb_cString, rb_mComparable);
+ rb_cNSMutableString = (VALUE)objc_getClass("NSMutableString");
+ assert(rb_cNSMutableString != 0);
+
+ rb_objc_define_method(rb_cString, "inspect", nsstr_inspect, 0);
+ rb_objc_define_method(rb_cString, "to_s", nsstr_to_s, 0);
+}
Modified: MacRuby/trunk/numeric.c
===================================================================
--- MacRuby/trunk/numeric.c 2010-03-21 00:38:47 UTC (rev 3844)
+++ MacRuby/trunk/numeric.c 2010-03-23 04:29:30 UTC (rev 3845)
@@ -88,7 +88,6 @@
static ID id_to_i, id_eq;
VALUE rb_cNumeric;
-VALUE rb_cNSNumber;
VALUE rb_cFloat;
VALUE rb_cInteger;
VALUE rb_cFixnum;
@@ -3304,24 +3303,13 @@
return Qtrue;
}
-static void *
-imp_nsnumber_to_int(void *rcv, SEL sel)
-{
- // This is because some NSNumber subclasses must be converted to real
- // CFNumber objects, in order to be coerced into Fixnum objects.
- long val = 0;
- if (!CFNumberGetValue((CFNumberRef)rcv, kCFNumberLongType, &val)) {
- rb_raise(rb_eTypeError, "cannot get 'long' value out of NSNumber %p",
- rcv);
- }
- CFNumberRef new_num = CFNumberCreate(NULL, kCFNumberLongType, &val);
- CFMakeCollectable(new_num);
- return (void *)new_num;
-}
+void Init_NSNumber(void);
void
Init_Numeric(void)
{
+ Init_NSNumber();
+
sel_coerce = sel_registerName("coerce:");
selDiv = sel_registerName("div:");
selDivmod = sel_registerName("divmod:");
@@ -3332,7 +3320,6 @@
rb_eZeroDivError = rb_define_class("ZeroDivisionError", rb_eStandardError);
rb_eFloatDomainError = rb_define_class("FloatDomainError", rb_eRangeError);
- rb_cNSNumber = (VALUE)objc_getClass("NSNumber");
rb_cNumeric = rb_define_class("Numeric", rb_cNSNumber);
RCLASS_SET_VERSION_FLAG(rb_cNumeric, RCLASS_IS_OBJECT_SUBCLASS);
rb_define_object_special_methods(rb_cNumeric);
@@ -3500,7 +3487,4 @@
rb_objc_define_method(rb_cFloat, "nan?", flo_is_nan_p, 0);
rb_objc_define_method(rb_cFloat, "infinite?", flo_is_infinite_p, 0);
rb_objc_define_method(rb_cFloat, "finite?", flo_is_finite_p, 0);
-
- class_replaceMethod((Class)rb_cNSNumber, sel_registerName("to_int"),
- (IMP)imp_nsnumber_to_int, "@@:");
}
Modified: MacRuby/trunk/rakelib/builder/builder.rb
===================================================================
--- MacRuby/trunk/rakelib/builder/builder.rb 2010-03-21 00:38:47 UTC (rev 3844)
+++ MacRuby/trunk/rakelib/builder/builder.rb 2010-03-23 04:29:30 UTC (rev 3845)
@@ -7,6 +7,7 @@
util variable version thread id objc bs ucnv encoding main dln dmyext marshal
gcd vm_eval prelude miniprelude gc-stub bridgesupport compiler dispatcher vm
symbol debugger MacRuby MacRubyDebuggerConnector NSArray NSDictionary
+ NSString NSNumber
}
EXTENSIONS = %w{
Modified: MacRuby/trunk/string.c
===================================================================
--- MacRuby/trunk/string.c 2010-03-21 00:38:47 UTC (rev 3844)
+++ MacRuby/trunk/string.c 2010-03-23 04:29:30 UTC (rev 3845)
@@ -26,9 +26,6 @@
#include <unicode/unum.h>
#include <unicode/utrans.h>
-VALUE rb_cString;
-VALUE rb_cNSString;
-VALUE rb_cNSMutableString;
VALUE rb_cRubyString;
VALUE rb_fs;
@@ -5402,16 +5399,12 @@
CFDataGetLength(dataref));
}
+void Init_NSString(void);
+
void
Init_String(void)
{
- // TODO create NSString.m
- rb_cNSString = (VALUE)objc_getClass("NSString");
- assert(rb_cNSString != 0);
- rb_cString = rb_cNSString;
- rb_include_module(rb_cString, rb_mComparable);
- rb_cNSMutableString = (VALUE)objc_getClass("NSMutableString");
- assert(rb_cNSMutableString != 0);
+ Init_NSString();
// rb_cRubyString is defined earlier in Init_PreVM().
rb_set_class_path(rb_cRubyString, rb_cObject, "String");
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100322/2f150c5f/attachment-0001.html>
More information about the macruby-changes
mailing list