Skip to content

Commit

Permalink
Move String#to_dbl to Rubinius::Type::coerce_to_float
Browse files Browse the repository at this point in the history
This change broke the behavior of many Math methods that do not accept
string arguments. To fix this, Rubinius::Type::coerce_to_float_for_numeric
was added and is analogous to MRI's rb_to_float.
  • Loading branch information
zaeleus committed Mar 27, 2012
1 parent 8601f64 commit d9b379a
Show file tree
Hide file tree
Showing 12 changed files with 80 additions and 66 deletions.
7 changes: 1 addition & 6 deletions kernel/bootstrap/string.rb
Expand Up @@ -10,7 +10,7 @@ def self.pattern(size, str)
end

def to_f
to_dbl(false)
Rubinius::Type::coerce_to_float self
end

alias_method :convert_float, :to_f
Expand Down Expand Up @@ -130,9 +130,4 @@ def resize_capacity(count)
Rubinius.primitive :string_resize_capacity
raise PrimitiveFailure, "String#resize_capacity failed"
end

def to_dbl(strict)
Rubinius.primitive :string_to_dbl
raise ArgumentError, "invalid value for Float"
end
end
11 changes: 11 additions & 0 deletions kernel/bootstrap/type18.rb
Expand Up @@ -11,5 +11,16 @@ def self.coerce_to_array(obj)
# array if it's not one.
return obj.to_a
end

def self.coerce_to_float(obj, strict=false)
case obj
when String
value = Rubinius.invoke_primitive :string_to_f, obj, strict
raise ArgumentError, "invalid value for Float" if value.nil?
value
else
Float(obj)
end
end
end
end
17 changes: 17 additions & 0 deletions kernel/bootstrap/type19.rb
Expand Up @@ -13,6 +13,23 @@ def self.coerce_to_array(obj)
return [obj]
end

def self.coerce_to_float(obj, strict=false)
case obj
when Numeric
coerce_to obj, Float, :to_f
when Float
return obj
when String
value = Rubinius.invoke_primitive :string_to_f, obj, strict
raise ArgumentError, "invalid value for Float" if value.nil?
value
when nil, true, false
raise TypeError, "can't convert #{obj.inspect} into Float"
else
raise TypeError, "can't convert #{obj.class} into Float"
end
end

def self.object_encoding(obj)
Rubinius.primitive :encoding_get_object_encoding
raise PrimitiveFailure, "Rubinius::Type.object_encoding primitive failed"
Expand Down
2 changes: 1 addition & 1 deletion kernel/common/kernel18.rb
Expand Up @@ -132,7 +132,7 @@ def Float(obj)
when Float
obj
when String
obj.to_dbl(true)
Rubinius::Type.coerce_to_float(obj, true)
else
coerced_value = Rubinius::Type.coerce_to(obj, Float, :to_f)
if coerced_value.nan?
Expand Down
2 changes: 1 addition & 1 deletion kernel/common/kernel19.rb
Expand Up @@ -220,7 +220,7 @@ def Float(obj)
when Float
obj
when String
obj.to_dbl(true)
Rubinius::Type.coerce_to_float(obj, true)
else
Rubinius::Type.coerce_to(obj, Float, :to_f)
end
Expand Down
50 changes: 25 additions & 25 deletions kernel/common/math.rb
Expand Up @@ -15,25 +15,25 @@ class DomainError < SystemCallError
end

def atan2(y, x)
y = Rubinius::Type.coerce_to_float y
x = Rubinius::Type.coerce_to_float x
y = Rubinius::Type.coerce_to_float_for_numeric y
x = Rubinius::Type.coerce_to_float_for_numeric x
FFI::Platform::Math.atan2 y, x
end

def cos(x)
FFI::Platform::Math.cos Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.cos Rubinius::Type.coerce_to_float_for_numeric(x)
end

def sin(x)
FFI::Platform::Math.sin Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.sin Rubinius::Type.coerce_to_float_for_numeric(x)
end

def tan(x)
FFI::Platform::Math.tan Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.tan Rubinius::Type.coerce_to_float_for_numeric(x)
end

def acos(x)
x = Rubinius::Type.coerce_to_float(x)
x = Rubinius::Type.coerce_to_float_for_numeric(x)

raise DomainError, 'acos' unless x.abs <= 1.0

Expand All @@ -45,43 +45,43 @@ def acos(x)
end

def asin(x)
x = Rubinius::Type.coerce_to_float(x)
x = Rubinius::Type.coerce_to_float_for_numeric(x)
raise DomainError, 'asin' unless x.abs <= 1.0
FFI::Platform::Math.asin x
end

def atan(x)
FFI::Platform::Math.atan Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.atan Rubinius::Type.coerce_to_float_for_numeric(x)
end

def cosh(x)
FFI::Platform::Math.cosh Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.cosh Rubinius::Type.coerce_to_float_for_numeric(x)
end

def sinh(x)
FFI::Platform::Math.sinh Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.sinh Rubinius::Type.coerce_to_float_for_numeric(x)
end

def tanh(x)
FFI::Platform::Math.tanh Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.tanh Rubinius::Type.coerce_to_float_for_numeric(x)
end

def acosh(x)
x = Rubinius::Type.coerce_to_float(x)
x = Rubinius::Type.coerce_to_float_for_numeric(x)
raise DomainError, 'acosh' unless x >= 1.0
FFI::Platform::Math.acosh x
end

def asinh(x)
FFI::Platform::Math.asinh Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.asinh Rubinius::Type.coerce_to_float_for_numeric(x)
end

# This is wierd, but we need to only do the ERANGE check if
# there is an ERANGE.
if Errno.const_defined?(:ERANGE)

def atanh(x)
x = Rubinius::Type.coerce_to_float(x)
x = Rubinius::Type.coerce_to_float_for_numeric(x)
raise DomainError, 'atanh' unless x.abs <= 1.0

FFI::Platform::POSIX.errno = 0
Expand All @@ -101,7 +101,7 @@ def atanh(x)
else

def atanh(x)
x = Rubinius::Type.coerce_to_float(x)
x = Rubinius::Type.coerce_to_float_for_numeric(x)
raise DomainError, 'atanh' unless x.abs <= 1.0

FFI::Platform::POSIX.errno = 0
Expand All @@ -114,29 +114,29 @@ def atanh(x)
end

def exp(x)
FFI::Platform::Math.exp Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.exp Rubinius::Type.coerce_to_float_for_numeric(x)
end

def log2(x)
x = Rubinius::Type.coerce_to_float(x)
x = Rubinius::Type.coerce_to_float_for_numeric(x)
raise DomainError, 'log2' unless x >= 0.0
FFI::Platform::Math.log2 x
end

def log10(x)
x = Rubinius::Type.coerce_to_float(x)
x = Rubinius::Type.coerce_to_float_for_numeric(x)
raise DomainError, 'log10' unless x >= 0.0
FFI::Platform::Math.log10 x
end

def sqrt(x)
x = Rubinius::Type.coerce_to_float(x)
x = Rubinius::Type.coerce_to_float_for_numeric(x)
raise DomainError, 'sqrt' unless x >= 0.0
FFI::Platform::Math.sqrt x
end

def frexp(x)
x = Rubinius::Type.coerce_to_float(x)
x = Rubinius::Type.coerce_to_float_for_numeric(x)
FFI::MemoryPointer.new :int do |exp|
result = FFI::Platform::Math.frexp x, exp
[result, exp.read_int]
Expand All @@ -146,7 +146,7 @@ def frexp(x)
def ldexp(x, n)
n = Rubinius::Type.coerce_to(n, Integer, :to_int)

FFI::Platform::Math.ldexp Rubinius::Type.coerce_to_float(x), n
FFI::Platform::Math.ldexp Rubinius::Type.coerce_to_float_for_numeric(x), n
end

# Rubinius-specific, used in Marshal
Expand All @@ -158,16 +158,16 @@ def modf(x)
end

def hypot(x, y)
x = Rubinius::Type.coerce_to_float x
y = Rubinius::Type.coerce_to_float y
x = Rubinius::Type.coerce_to_float_for_numeric x
y = Rubinius::Type.coerce_to_float_for_numeric y
FFI::Platform::Math.hypot x, y
end

def erf(x)
FFI::Platform::Math.erf Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.erf Rubinius::Type.coerce_to_float_for_numeric(x)
end

def erfc(x)
FFI::Platform::Math.erfc Rubinius::Type.coerce_to_float(x)
FFI::Platform::Math.erfc Rubinius::Type.coerce_to_float_for_numeric(x)
end
end
2 changes: 1 addition & 1 deletion kernel/common/math18.rb
Expand Up @@ -2,7 +2,7 @@

module Math
def log(x)
x = Rubinius::Type.coerce_to_float(x)
x = Rubinius::Type.coerce_to_float_for_numeric(x)
raise DomainError, 'log' unless x >= 0.0
FFI::Platform::Math.log x
end
Expand Down
10 changes: 5 additions & 5 deletions kernel/common/math19.rb
Expand Up @@ -28,11 +28,11 @@ module Math
]

def cbrt(x)
x = Rubinius::Type.coerce_to_float x
x = Rubinius::Type.coerce_to_float_for_numeric x
end

def gamma(x)
x = Rubinius::Type.coerce_to_float x
x = Rubinius::Type.coerce_to_float_for_numeric x

return Float::INFINITY if x == 0.0
return Float::NAN if x.nan?
Expand All @@ -57,7 +57,7 @@ def gamma(x)
end

def lgamma(x)
x = Rubinius::Type.coerce_to_float x
x = Rubinius::Type.coerce_to_float_for_numeric x

if sign = x.infinite?
raise DomainError, "lgamma" if sign == -1
Expand All @@ -72,12 +72,12 @@ def lgamma(x)
end

def log(x, base=undefined)
x = Rubinius::Type.coerce_to_float x
x = Rubinius::Type.coerce_to_float_for_numeric x
raise DomainError, 'log' unless x >= 0.0
return -Float::INFINITY if x == 0.0
y = FFI::Platform::Math.log x
unless base.equal? undefined
base = Rubinius::Type.coerce_to_float base
base = Rubinius::Type.coerce_to_float_for_numeric base
y /= log(base)
end
y
Expand Down
4 changes: 2 additions & 2 deletions kernel/common/type18.rb
Expand Up @@ -6,8 +6,8 @@ def self.coerce_to_path(obj)
StringValue(obj)
end

def self.coerce_to_float(obj)
Float(obj)
def self.coerce_to_float_for_numeric(obj)
coerce_to_float(obj, true)
end

def self.coerce_to_symbol(obj)
Expand Down
23 changes: 13 additions & 10 deletions kernel/common/type19.rb
Expand Up @@ -43,17 +43,20 @@ def self.coerce_to_path(obj)
end
end

def self.coerce_to_float(obj)
case obj
when Numeric
coerce_to obj, Float, :to_f
when Float
return obj
when nil, true, false
raise TypeError, "can't convert #{obj.inspect} into Float"
else
raise TypeError, "can't convert #{obj.class} into Float"
# Analogous to MRI's rb_to_float. This is primarily used in Math.
def self.coerce_to_float_for_numeric(obj)
return obj if object_kind_of? obj, Float

unless object_kind_of? obj, Numeric
case obj
when nil, true, false
raise TypeError, "can't convert #{obj.inspect} into Float"
else
raise TypeError, "can't convert #{obj.class} into Float"
end
end

coerce_to obj, Float, :to_f
end

def self.coerce_to_symbol(obj)
Expand Down
14 changes: 2 additions & 12 deletions vm/builtin/string.cpp
Expand Up @@ -906,23 +906,13 @@ namespace rubinius {
Float* String::to_f(STATE, Object* strict) {
const char* str = c_str(state);

if(strict == cTrue) {
if(byte_size() > (native_int)strlen(str)) return nil<Float>();
if(strict == cTrue && byte_size() > (native_int)strlen(str)) {
return nil<Float>();
}

return Float::from_cstr(state, str, strict);
}

Float* String::to_dbl_prim(STATE, Object* strict) {
Float* value = String::to_f(state, strict);

if(value->nil_p()) {
return (Float*)Primitives::failure();
}

return value;
}

// Character-wise logical AND of two strings. Modifies the receiver.
String* String::apply_and(STATE, String* other) {
native_int count;
Expand Down
4 changes: 1 addition & 3 deletions vm/builtin/string.hpp
Expand Up @@ -175,11 +175,9 @@ namespace rubinius {
/** Append length bytes from C string. Returns self. */
String* append(STATE, const char* other, native_int length);

// Rubinius.primitive :string_to_f
Float* to_f(STATE, Object* strict = cTrue);

// Rubinius.primitive :string_to_dbl
Float* to_dbl_prim(STATE, Object* strict);

Integer* to_i(STATE, Fixnum* base = Fixnum::from(0), Object* strict = cTrue);

// Rubinius.primitive :string_to_inum
Expand Down

0 comments on commit d9b379a

Please sign in to comment.