Skip to content

Commit

Permalink
Add some basic Numeric coercion
Browse files Browse the repository at this point in the history
  • Loading branch information
meh committed Oct 18, 2013
1 parent added4f commit e0ad1b0
Showing 1 changed file with 152 additions and 33 deletions.
185 changes: 152 additions & 33 deletions corelib/numeric.rb
Expand Up @@ -3,96 +3,215 @@ class Numeric

`def._isNumber = true`

def coerce(other)
%x{
if (other._isNumber) {
return #{[self, other]};
}
else {
return #{other.coerce(self)};
}
}
rescue
raise TypeError, "#{other.class} can't be coerce into Numeric"
end

def send_coerced(method, other)
a, b = coerce(other)
a.__send__ method, b
end

def +(other)
`#{self} + other`
%x{
if (other._isNumber) {
return self + other;
}
else {
return #{send_coerced :+, other};
}
}
end

def -(other)
`#{self} - other`
%x{
if (other._isNumber) {
return self - other;
}
else {
return #{send_coerced :-, other};
}
}
end

def *(other)
`#{self} * other`
%x{
if (other._isNumber) {
return self * other;
}
else {
return #{send_coerced :*, other};
}
}
end

def /(other)
`#{self} / other`
%x{
if (other._isNumber) {
return self / other;
}
else {
return #{send_coerced :/, other};
}
}
end

def %(other)
if other < 0 || self < 0
`(#{self} % other + other) % other`
else
`#{self} % other`
end
%x{
if (other._isNumber) {
if (other < 0 || self < 0) {
return (self % other + other) % other;
}
else {
return self % other;
}
}
else {
return #{send_coerced :%, other};
}
}
end

def &(other)
`#{self} & other`
%x{
if (other._isNumber) {
return self & other;
}
else {
return #{send_coerced :&, other};
}
}
end

def |(other)
`#{self} | other`
%x{
if (other._isNumber) {
return self | other;
}
else {
return #{send_coerced :|, other};
}
}
end

def ^(other)
`#{self} ^ other`
%x{
if (other._isNumber) {
return self ^ other;
}
else {
return #{send_coerced :^, other};
}
}
end

def <(other)
`#{self} < other`
%x{
if (other._isNumber) {
return self < other;
}
else {
return #{send_coerced :<, other};
}
}
end

def <=(other)
`#{self} <= other`
%x{
if (other._isNumber) {
return self <= other;
}
else {
return #{send_coerced :<=, other};
}
}
end

def >(other)
`#{self} > other`
%x{
if (other._isNumber) {
return self > other;
}
else {
return #{send_coerced :>, other};
}
}
end

def >=(other)
`#{self} >= other`
%x{
if (other._isNumber) {
return self >= other;
}
else {
return #{send_coerced :>=, other};
}
}
end

def <=>(other)
%x{
if (other._isNumber) {
if (self < other) {
return -1;
}
else if (self > other) {
return 1;
}
else {
return 0;
}
}
else {
return #{send_coerced :<=>, other};
}
}
end

def <<(count)
`#{self} << count`
`self << #{count.to_int}`
end

def >>(count)
`#{self} >> count`
`self >> #{count.to_int}`
end

def +@
`+#{self}`
`+self`
end

def -@
`-#{self}`
`-self`
end

def ~
`~#{self}`
`~self`
end

def **(other)
`Math.pow(#{self}, other)`
end

def ==(other)
`!!(other._isNumber) && #{self} == Number(other)`
end

def <=>(other)
%x{
if (typeof(other) !== 'number') {
return nil;
if (other._isNumber) {
return Math.pow(self, other);
}
else {
return #{send_coerced :**, other};
}
return #{self} < other ? -1 : (#{self} > other ? 1 : 0);
}
end

def ==(other)
`!!(other._isNumber) && self == Number(other)`
end

def abs
`Math.abs(#{self})`
end
Expand Down

4 comments on commit e0ad1b0

@DouweM
Copy link
Contributor

@DouweM DouweM commented on e0ad1b0 Oct 18, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code could be cleaned up considerably using something like:

class Numeric
  def_native_or_coerced :+
  def_native_or_coerced :-

  def self.def_native_or_coerced(meth)
    define_method(meth) do |other|
      %x{
        if (other._isNumber) {
          return self #{meth} other;
        }
        else {
          return #{send_coerced meth, other};
        }
      }
    end
  end
end

Only %, <=> and ** would need to be implemented manually.

@meh
Copy link
Member Author

@meh meh commented on e0ad1b0 Oct 18, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That wouldn't work, self #{meth} other would be compiled to self meth other.

@DouweM
Copy link
Contributor

@DouweM DouweM commented on e0ad1b0 Oct 18, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, damn, you're right. We obviously can't just dynamically insert a + in the generated JS. My bad :)

@meh
Copy link
Member Author

@meh meh commented on e0ad1b0 Oct 18, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the sadness of not having macros :)

Please sign in to comment.