Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: a77c3fed567a
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: abcb62c6c818
Choose a head ref
  • 19 commits
  • 20 files changed
  • 1 contributor

Commits on May 4, 2016

  1. Copy the full SHA
    01aded5 View commit details
  2. Copy the full SHA
    6527cdc View commit details
  3. Copy the full SHA
    91c104f View commit details
  4. Copy the full SHA
    83b3602 View commit details

Commits on May 5, 2016

  1. Copy the full SHA
    319328e View commit details
  2. Copy the full SHA
    182da72 View commit details
  3. [Truffle] Formatting.

    chrisseaton committed May 5, 2016
    Copy the full SHA
    3369b12 View commit details
  4. Copy the full SHA
    f57a087 View commit details
  5. Copy the full SHA
    40e5fee View commit details
  6. Copy the full SHA
    d56594a View commit details
  7. Copy the full SHA
    b793e99 View commit details
  8. Copy the full SHA
    a490602 View commit details
  9. Copy the full SHA
    7f44e78 View commit details
  10. Copy the full SHA
    58617a1 View commit details
  11. Copy the full SHA
    697ad3d View commit details
  12. Copy the full SHA
    c87a7e5 View commit details
  13. Copy the full SHA
    40251e6 View commit details
  14. Copy the full SHA
    77b9f89 View commit details
  15. Copy the full SHA
    abcb62c View commit details
Showing with 2,603 additions and 2,152 deletions.
  1. +1 −1 truffle/src/main/java/org/jruby/truffle/core/CoreLibrary.java
  2. +2 −2 truffle/src/main/java/org/jruby/truffle/core/Layouts.java
  3. +16 −0 truffle/src/main/java/org/jruby/truffle/core/exception/CoreExceptions.java
  4. +4 −0 truffle/src/main/java/org/jruby/truffle/core/numeric/FixnumOrBignumNode.java
  5. +0 −2,145 truffle/src/main/java/org/jruby/truffle/stdlib/BigDecimalNodes.java
  6. +56 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/AbstractAddNode.java
  7. +149 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/AbstractDivNode.java
  8. +108 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/AbstractMultNode.java
  9. +56 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/AbstractSubNode.java
  10. +136 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/BigDecimalCastNode.java
  11. +66 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/BigDecimalCoerceNode.java
  12. +26 −0 ...fle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/BigDecimalCoreMethodArrayArgumentsNode.java
  13. +167 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/BigDecimalCoreMethodNode.java
  14. +4 −4 truffle/src/main/java/org/jruby/truffle/stdlib/{ → bigdecimal}/BigDecimalLayout.java
  15. +1,396 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/BigDecimalNodes.java
  16. +28 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/BigDecimalOpNode.java
  17. +30 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/BigDecimalType.java
  18. +285 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/CreateBigDecimalNode.java
  19. +49 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/GetIntegerConstantNode.java
  20. +24 −0 truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/RoundModeNode.java
Original file line number Diff line number Diff line change
@@ -100,7 +100,7 @@
import org.jruby.truffle.language.parser.ParserContext;
import org.jruby.truffle.platform.RubiniusTypes;
import org.jruby.truffle.platform.signal.SignalManager;
import org.jruby.truffle.stdlib.BigDecimalNodesFactory;
import org.jruby.truffle.stdlib.bigdecimal.BigDecimalNodesFactory;
import org.jruby.truffle.stdlib.CoverageNodesFactory;
import org.jruby.truffle.stdlib.EtcNodesFactory;
import org.jruby.truffle.stdlib.ObjSpaceNodesFactory;
4 changes: 2 additions & 2 deletions truffle/src/main/java/org/jruby/truffle/core/Layouts.java
Original file line number Diff line number Diff line change
@@ -82,8 +82,8 @@
import org.jruby.truffle.core.time.TimeLayoutImpl;
import org.jruby.truffle.core.tracepoint.TracePointLayout;
import org.jruby.truffle.core.tracepoint.TracePointLayoutImpl;
import org.jruby.truffle.stdlib.BigDecimalLayout;
import org.jruby.truffle.stdlib.BigDecimalLayoutImpl;
import org.jruby.truffle.stdlib.bigdecimal.BigDecimalLayout;
import org.jruby.truffle.stdlib.bigdecimal.BigDecimalLayoutImpl;
import org.jruby.truffle.stdlib.digest.DigestLayout;
import org.jruby.truffle.stdlib.digest.DigestLayoutImpl;
import org.jruby.truffle.stdlib.psych.EmitterLayout;
Original file line number Diff line number Diff line change
@@ -520,6 +520,22 @@ public DynamicObject floatDomainError(String value, Node currentNode) {
context.getCallStack().getBacktrace(currentNode));
}

public DynamicObject floatDomainErrorResultsToNaN(Node currentNode) {
return floatDomainError("Computation results to 'NaN'(Not a Number)", currentNode);
}

public DynamicObject floatDomainErrorResultsToInfinity(Node currentNode) {
return floatDomainError("Computation results to 'Infinity'", currentNode);
}

public DynamicObject floatDomainErrorResultsToNegInfinity(Node currentNode) {
return floatDomainError("Computation results to '-Infinity'", currentNode);
}

public DynamicObject floatDomainErrorSqrtNegative(Node currentNode) {
return floatDomainError("(VpSqrt) SQRT(negative value)", currentNode);
}

// IOError

@TruffleBoundary
Original file line number Diff line number Diff line change
@@ -28,6 +28,10 @@ public static FixnumOrBignumNode create(RubyContext context, SourceSection sourc
return new FixnumOrBignumNode(context, sourceSection);
}

public FixnumOrBignumNode() {
this(null, null);
}

public FixnumOrBignumNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}
2,145 changes: 0 additions & 2,145 deletions truffle/src/main/java/org/jruby/truffle/stdlib/BigDecimalNodes.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.core.Layouts;

import java.math.BigDecimal;
import java.math.MathContext;

public abstract class AbstractAddNode extends BigDecimalOpNode {

@CompilerDirectives.TruffleBoundary
private BigDecimal addBigDecimal(DynamicObject a, DynamicObject b, MathContext mathContext) {
return Layouts.BIG_DECIMAL.getValue(a).add(Layouts.BIG_DECIMAL.getValue(b), mathContext);
}

protected Object add(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
return createBigDecimal(frame, addBigDecimal(a, b, new MathContext(precision, getRoundMode(frame))));
}

protected Object addSpecial(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
final BigDecimalType aType = Layouts.BIG_DECIMAL.getType(a);
final BigDecimalType bType = Layouts.BIG_DECIMAL.getType(b);

if (aType == BigDecimalType.NAN || bType == BigDecimalType.NAN ||
(aType == BigDecimalType.POSITIVE_INFINITY && bType == BigDecimalType.NEGATIVE_INFINITY) ||
(aType == BigDecimalType.NEGATIVE_INFINITY && bType == BigDecimalType.POSITIVE_INFINITY)) {
return createBigDecimal(frame, BigDecimalType.NAN);
}

if (aType == BigDecimalType.POSITIVE_INFINITY || bType == BigDecimalType.POSITIVE_INFINITY) {
return createBigDecimal(frame, BigDecimalType.POSITIVE_INFINITY);
}

if (aType == BigDecimalType.NEGATIVE_INFINITY || bType == BigDecimalType.NEGATIVE_INFINITY) {
return createBigDecimal(frame, BigDecimalType.NEGATIVE_INFINITY);
}

// one is NEGATIVE_ZERO and second is NORMAL
if (isNormal(a)) {
return a;
} else {
return b;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.jruby.truffle.core.Layouts;

import java.math.BigDecimal;
import java.math.MathContext;

public abstract class AbstractDivNode extends BigDecimalOpNode {

private final ConditionProfile normalZero = ConditionProfile.createBinaryProfile();

private Object divBigDecimalWithProfile(DynamicObject a, DynamicObject b, MathContext mathContext) {
final BigDecimal aBigDecimal = Layouts.BIG_DECIMAL.getValue(a);
final BigDecimal bBigDecimal = Layouts.BIG_DECIMAL.getValue(b);
if (normalZero.profile(bBigDecimal.signum() == 0)) {
switch (aBigDecimal.signum()) {
case 1:
return BigDecimalType.POSITIVE_INFINITY;
case 0:
return BigDecimalType.NAN;
case -1:
return BigDecimalType.NEGATIVE_INFINITY;
default:
throw new UnsupportedOperationException("unreachable code branch for value: " + aBigDecimal.signum());
}
} else {
return divBigDecimal(aBigDecimal, bBigDecimal, mathContext);
}
}

@CompilerDirectives.TruffleBoundary
private BigDecimal divBigDecimal(BigDecimal a, BigDecimal b, MathContext mathContext) {
return a.divide(b, mathContext);
}

protected Object div(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
return createBigDecimal(frame, divBigDecimalWithProfile(a, b, new MathContext(precision, getRoundMode(frame))));
}

protected Object divNormalSpecial(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
switch (Layouts.BIG_DECIMAL.getType(b)) {
case NAN:
return createBigDecimal(frame, BigDecimalType.NAN);
case NEGATIVE_ZERO:
switch (Layouts.BIG_DECIMAL.getValue(a).signum()) {
case 1:
return createBigDecimal(frame, BigDecimalType.NEGATIVE_INFINITY);
case 0:
return createBigDecimal(frame, BigDecimalType.NAN);
case -1:
return createBigDecimal(frame, BigDecimalType.POSITIVE_INFINITY);
}
case POSITIVE_INFINITY:
switch (Layouts.BIG_DECIMAL.getValue(a).signum()) {
case 1:
case 0:
return createBigDecimal(frame, BigDecimal.ZERO);
case -1:
return createBigDecimal(frame, BigDecimalType.NEGATIVE_ZERO);
}
case NEGATIVE_INFINITY:
switch (Layouts.BIG_DECIMAL.getValue(b).signum()) {
case 1:
return createBigDecimal(frame, BigDecimalType.NEGATIVE_ZERO);
case 0:
case -1:
return createBigDecimal(frame, BigDecimal.ZERO);
}
default:
throw new UnsupportedOperationException("unreachable code branch for value: " + Layouts.BIG_DECIMAL.getType(b));
}
}

protected Object divSpecialNormal(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
switch (Layouts.BIG_DECIMAL.getType(a)) {
case NAN:
return createBigDecimal(frame, BigDecimalType.NAN);
case NEGATIVE_ZERO:
switch (Layouts.BIG_DECIMAL.getValue(b).signum()) {
case 1:
return createBigDecimal(frame, BigDecimalType.NEGATIVE_ZERO);
case 0:
return createBigDecimal(frame, BigDecimalType.NAN);
case -1:
return createBigDecimal(frame, BigDecimal.ZERO);
}
case POSITIVE_INFINITY:
switch (Layouts.BIG_DECIMAL.getValue(b).signum()) {
case 1:
case 0:
return createBigDecimal(frame, BigDecimalType.POSITIVE_INFINITY);
case -1:
return createBigDecimal(frame, BigDecimalType.NEGATIVE_INFINITY);
}
case NEGATIVE_INFINITY:
switch (Layouts.BIG_DECIMAL.getValue(b).signum()) {
case 1:
case 0:
return createBigDecimal(frame, BigDecimalType.NEGATIVE_INFINITY);
case -1:
return createBigDecimal(frame, BigDecimalType.POSITIVE_INFINITY);
}
default:
throw new UnsupportedOperationException("unreachable code branch for value: " + Layouts.BIG_DECIMAL.getType(a));
}
}

protected Object divSpecialSpecial(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
final BigDecimalType aType = Layouts.BIG_DECIMAL.getType(a);
final BigDecimalType bType = Layouts.BIG_DECIMAL.getType(b);

if (aType == BigDecimalType.NAN || bType == BigDecimalType.NAN ||
(aType == BigDecimalType.NEGATIVE_ZERO && bType == BigDecimalType.NEGATIVE_ZERO)) {
return createBigDecimal(frame, BigDecimalType.NAN);
}

if (aType == BigDecimalType.NEGATIVE_ZERO) {
if (bType == BigDecimalType.POSITIVE_INFINITY) {
return createBigDecimal(frame, BigDecimalType.NEGATIVE_ZERO);
} else {
return createBigDecimal(frame, BigDecimalType.POSITIVE_INFINITY);
}
}

if (bType == BigDecimalType.NEGATIVE_ZERO) {
if (aType == BigDecimalType.POSITIVE_INFINITY) {
return createBigDecimal(frame, BigDecimalType.NEGATIVE_INFINITY);
} else {
return createBigDecimal(frame, BigDecimalType.POSITIVE_INFINITY);
}
}

// a and b are only +-Infinity
return createBigDecimal(frame, BigDecimalType.NAN);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.jruby.truffle.core.Layouts;

import java.math.BigDecimal;
import java.math.MathContext;

public abstract class AbstractMultNode extends BigDecimalOpNode {

private final ConditionProfile zeroNormal = ConditionProfile.createBinaryProfile();

private Object multBigDecimalWithProfile(DynamicObject a, DynamicObject b, MathContext mathContext) {
final BigDecimal bBigDecimal = Layouts.BIG_DECIMAL.getValue(b);

if (zeroNormal.profile(isNormalZero(a) && bBigDecimal.signum() == -1)) {
return BigDecimalType.NEGATIVE_ZERO;
}

return multBigDecimal(Layouts.BIG_DECIMAL.getValue(a), bBigDecimal, mathContext);
}

@CompilerDirectives.TruffleBoundary
private Object multBigDecimal(BigDecimal a, BigDecimal b, MathContext mathContext) {
return a.multiply(b, mathContext);
}

protected Object mult(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
return createBigDecimal(frame, multBigDecimalWithProfile(a, b, new MathContext(precision, getRoundMode(frame))));
}

protected Object multNormalSpecial(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
return multSpecialNormal(frame, b, a, precision);
}

protected Object multSpecialNormal(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
switch (Layouts.BIG_DECIMAL.getType(a)) {
case NAN:
return createBigDecimal(frame, BigDecimalType.NAN);
case NEGATIVE_ZERO:
switch (Layouts.BIG_DECIMAL.getValue(b).signum()) {
case 1:
case 0:
return createBigDecimal(frame, BigDecimalType.NEGATIVE_ZERO);
case -1:
return createBigDecimal(frame, BigDecimal.ZERO);
}
case POSITIVE_INFINITY:
switch (Layouts.BIG_DECIMAL.getValue(b).signum()) {
case 1:
return createBigDecimal(frame, BigDecimalType.POSITIVE_INFINITY);
case 0:
return createBigDecimal(frame, BigDecimalType.NAN);
case -1:
return createBigDecimal(frame, BigDecimalType.NEGATIVE_INFINITY);
}
case NEGATIVE_INFINITY:
switch (Layouts.BIG_DECIMAL.getValue(b).signum()) {
case 1:
return createBigDecimal(frame, BigDecimalType.NEGATIVE_INFINITY);
case 0:
return createBigDecimal(frame, BigDecimalType.NAN);
case -1:
return createBigDecimal(frame, BigDecimalType.POSITIVE_INFINITY);
}
default:
throw new UnsupportedOperationException("unreachable code branch");
}
}

protected Object multSpecial(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
final BigDecimalType aType = Layouts.BIG_DECIMAL.getType(a);
final BigDecimalType bType = Layouts.BIG_DECIMAL.getType(b);

if (aType == BigDecimalType.NAN || bType == BigDecimalType.NAN) {
return createBigDecimal(frame, BigDecimalType.NAN);
}
if (aType == BigDecimalType.NEGATIVE_ZERO && bType == BigDecimalType.NEGATIVE_ZERO) {
return createBigDecimal(frame, BigDecimal.ZERO);
}
if (aType == BigDecimalType.NEGATIVE_ZERO || bType == BigDecimalType.NEGATIVE_ZERO) {
return createBigDecimal(frame, BigDecimalType.NAN);
}

// a and b are only +-Infinity

if (aType == BigDecimalType.POSITIVE_INFINITY) {
return bType == BigDecimalType.POSITIVE_INFINITY ? a : createBigDecimal(frame, BigDecimalType.NEGATIVE_INFINITY);
}
if (aType == BigDecimalType.NEGATIVE_INFINITY) {
return bType == BigDecimalType.POSITIVE_INFINITY ? a : createBigDecimal(frame, (BigDecimalType.POSITIVE_INFINITY));
}

throw new UnsupportedOperationException("unreachable code branch");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.core.Layouts;

import java.math.BigDecimal;
import java.math.MathContext;

public abstract class AbstractSubNode extends BigDecimalOpNode {

@CompilerDirectives.TruffleBoundary
private BigDecimal subBigDecimal(DynamicObject a, DynamicObject b, MathContext mathContext) {
return Layouts.BIG_DECIMAL.getValue(a).subtract(Layouts.BIG_DECIMAL.getValue(b), mathContext);
}

protected Object subNormal(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
return createBigDecimal(frame, subBigDecimal(a, b, new MathContext(precision, getRoundMode(frame))));
}

protected Object subSpecial(VirtualFrame frame, DynamicObject a, DynamicObject b, int precision) {
final BigDecimalType aType = Layouts.BIG_DECIMAL.getType(a);
final BigDecimalType bType = Layouts.BIG_DECIMAL.getType(b);

if (aType == BigDecimalType.NAN || bType == BigDecimalType.NAN ||
(aType == BigDecimalType.POSITIVE_INFINITY && bType == BigDecimalType.POSITIVE_INFINITY) ||
(aType == BigDecimalType.NEGATIVE_INFINITY && bType == BigDecimalType.NEGATIVE_INFINITY)) {
return createBigDecimal(frame, BigDecimalType.NAN);
}

if (aType == BigDecimalType.POSITIVE_INFINITY || bType == BigDecimalType.NEGATIVE_INFINITY) {
return createBigDecimal(frame, BigDecimalType.POSITIVE_INFINITY);
}

if (aType == BigDecimalType.NEGATIVE_INFINITY || bType == BigDecimalType.POSITIVE_INFINITY) {
return createBigDecimal(frame, BigDecimalType.NEGATIVE_INFINITY);
}

// one is NEGATIVE_ZERO and second is NORMAL
if (isNormal(a)) {
return a;
} else {
return createBigDecimal(frame, Layouts.BIG_DECIMAL.getValue(b).negate());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.RubyBignum;
import org.jruby.RubyFixnum;
import org.jruby.RubyRational;
import org.jruby.ext.bigdecimal.RubyBigDecimal;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.SnippetNode;
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;

import java.math.BigDecimal;
import java.math.RoundingMode;

@NodeChildren({
@NodeChild(value = "value", type = RubyNode.class),
@NodeChild(value = "roundingMode", type = RubyNode.class)
})
@ImportStatic(BigDecimalCoreMethodNode.class)
public abstract class BigDecimalCastNode extends RubyNode {
public BigDecimalCastNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public abstract BigDecimal executeBigDecimal(VirtualFrame frame, Object value, RoundingMode roundingMode);

public abstract Object executeObject(VirtualFrame frame, Object value, RoundingMode roundingMode);

@Specialization
public BigDecimal doInt(long value, Object roundingMode) {
return BigDecimal.valueOf(value);
}

@Specialization
public BigDecimal doDouble(double value, Object roundingMode) {
return BigDecimal.valueOf(value);
}

@Specialization(guards = "isRubyBignum(value)")
public BigDecimal doBignum(DynamicObject value, Object roundingMode) {
return new BigDecimal(Layouts.BIGNUM.getValue(value));
}

@Specialization(guards = "isNormalRubyBigDecimal(value)")
public BigDecimal doBigDecimal(DynamicObject value, Object roundingMode) {
return Layouts.BIG_DECIMAL.getValue(value);
}

@Specialization(guards = {"!isRubyBignum(value)", "!isRubyBigDecimal(value)"})
public Object doOther(
VirtualFrame frame,
DynamicObject value,
Object roundingMode,
@Cached("new()") SnippetNode isRationalSnippet,
@Cached("createMethodCall()") CallDispatchHeadNode numeratorCallNode,
@Cached("createMethodCall()") CallDispatchHeadNode denominatorCallNode,
@Cached("createMethodCall()") CallDispatchHeadNode toFCallNode) {
if (roundingMode instanceof RoundingMode && (boolean) isRationalSnippet.execute(frame, "value.is_a?(Rational)", "value", value)) {

final Object numerator = numeratorCallNode.call(frame, value, "numerator", null);

final IRubyObject numeratorValue;

if (numerator instanceof Integer) {
numeratorValue = RubyFixnum.newFixnum(getContext().getJRubyRuntime(), (int) numerator);
} else if (numerator instanceof Long) {
numeratorValue = RubyFixnum.newFixnum(getContext().getJRubyRuntime(), (long) numerator);
} else if (RubyGuards.isRubyBignum(numerator)) {
numeratorValue = RubyBignum.newBignum(getContext().getJRubyRuntime(), Layouts.BIGNUM.getValue((DynamicObject) numerator));
} else {
throw new UnsupportedOperationException(numerator.toString());
}

final Object denominator = denominatorCallNode.call(frame, value, "denominator", null);

final IRubyObject denominatorValue;

if (denominator instanceof Integer) {
denominatorValue = RubyFixnum.newFixnum(getContext().getJRubyRuntime(), (int) denominator);
} else if (denominator instanceof Long) {
denominatorValue = RubyFixnum.newFixnum(getContext().getJRubyRuntime(), (long) denominator);
} else if (RubyGuards.isRubyBignum(denominator)) {
denominatorValue = RubyBignum.newBignum(getContext().getJRubyRuntime(), Layouts.BIGNUM.getValue((DynamicObject) denominator));
} else {
throw new UnsupportedOperationException(denominator.toString());
}

final RubyRational rubyRationalValue = RubyRational.newRationalRaw(getContext().getJRubyRuntime(), numeratorValue, denominatorValue);

final RubyBigDecimal rubyBigDecimalValue;

try {
rubyBigDecimalValue = RubyBigDecimal.getVpRubyObjectWithPrec19Inner(getContext().getJRubyRuntime().getCurrentContext(), rubyRationalValue, (RoundingMode) roundingMode);
} catch (Exception e) {
e.printStackTrace();
throw e;
}

return rubyBigDecimalValue.getBigDecimalValue();
} else {
final Object result = toFCallNode.call(frame, value, "to_f", null);
if (result != nil()) {
return new BigDecimal((double) result);
} else {
return result;
}
}
}

@Fallback
public Object doBigDecimalFallback(Object value, Object roundingMode) {
return nil();
}
// TODO (pitr 22-Jun-2015): How to better communicate failure without throwing
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;

import java.math.BigDecimal;
import java.math.RoundingMode;

@NodeChildren({
@NodeChild(value = "value", type = RubyNode.class),
@NodeChild(value = "roundingMode", type = RoundModeNode.class),
@NodeChild(value = "cast", type = BigDecimalCastNode.class, executeWith = {"value", "roundingMode"})

})
public abstract class BigDecimalCoerceNode extends RubyNode {
@Child private CreateBigDecimalNode createBigDecimal;

public static BigDecimalCoerceNode create(RubyContext context, SourceSection sourceSection, RubyNode value) {
return BigDecimalCoerceNodeGen.create(value,
RoundModeNodeFactory.create(),
BigDecimalCastNodeGen.create(context, sourceSection, null, null));
}

private void setupCreateBigDecimal() {
if (createBigDecimal == null) {
CompilerDirectives.transferToInterpreter();
createBigDecimal = insert(CreateBigDecimalNodeFactory.create(getContext(), getSourceSection(), null, null, null));
}
}

protected DynamicObject createBigDecimal(VirtualFrame frame, Object value) {
setupCreateBigDecimal();
return createBigDecimal.executeCreate(frame, value);
}

public abstract DynamicObject executeBigDecimal(VirtualFrame frame, RoundingMode roundingMode, Object value);

@Specialization
public DynamicObject doBigDecimal(VirtualFrame frame, Object value, RoundingMode roundingMode, BigDecimal cast) {
return createBigDecimal(frame, cast);
}

@Specialization(guards = { "isRubyBigDecimal(value)", "isNil(cast)" })
public Object doBigDecimal(DynamicObject value, RoundingMode roundingMode, DynamicObject cast) {
return value;
}

// TODO (pitr 22-Jun-2015): deal with not-coerce-able values

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;

@NodeChild(value = "arguments", type = RubyNode[].class)
public abstract class BigDecimalCoreMethodArrayArgumentsNode extends BigDecimalCoreMethodNode {

public BigDecimalCoreMethodArrayArgumentsNode() {
}

public BigDecimalCoreMethodArrayArgumentsNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package org.jruby.truffle.stdlib.bigdecimal;

/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.CoreMethodNode;
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.core.cast.IntegerCastNode;
import org.jruby.truffle.core.cast.IntegerCastNodeGen;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.language.dispatch.DispatchHeadNodeFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;

public abstract class BigDecimalCoreMethodNode extends CoreMethodNode {

@Child
private CreateBigDecimalNode createBigDecimal;
@Child
private CallDispatchHeadNode limitCall;
@Child
private IntegerCastNode limitIntegerCast;
@Child
private CallDispatchHeadNode roundModeCall;
@Child
private IntegerCastNode roundModeIntegerCast;

public BigDecimalCoreMethodNode() {
}

public BigDecimalCoreMethodNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public static boolean isNormal(DynamicObject value) {
return Layouts.BIG_DECIMAL.getType(value) == BigDecimalType.NORMAL;
}

public static boolean isNormalRubyBigDecimal(DynamicObject value) {
return RubyGuards.isRubyBigDecimal(value) && Layouts.BIG_DECIMAL.getType(value) == BigDecimalType.NORMAL;
}

public static boolean isSpecialRubyBigDecimal(DynamicObject value) {
return RubyGuards.isRubyBigDecimal(value) && Layouts.BIG_DECIMAL.getType(value) != BigDecimalType.NORMAL;
}

public static boolean isNormalZero(DynamicObject value) {
return Layouts.BIG_DECIMAL.getValue(value).compareTo(BigDecimal.ZERO) == 0;
}

public static boolean isNan(DynamicObject value) {
return Layouts.BIG_DECIMAL.getType(value) == BigDecimalType.NAN;
}

private void setupCreateBigDecimal() {
if (createBigDecimal == null) {
CompilerDirectives.transferToInterpreter();
createBigDecimal = insert(CreateBigDecimalNodeFactory.create(getContext(), getSourceSection(), null, null, null));
}
}

protected DynamicObject createBigDecimal(VirtualFrame frame, Object value) {
setupCreateBigDecimal();
return createBigDecimal.executeCreate(frame, value);
}

protected DynamicObject initializeBigDecimal(VirtualFrame frame, Object value, DynamicObject self, Object digits) {
setupCreateBigDecimal();
return createBigDecimal.executeInitialize(frame, value, self, digits);
}

private void setupLimitCall() {
if (limitCall == null) {
CompilerDirectives.transferToInterpreter();
limitCall = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}
}

private void setupLimitIntegerCast() {
if (limitIntegerCast == null) {
CompilerDirectives.transferToInterpreter();
limitIntegerCast = insert(IntegerCastNodeGen.create(getContext(), getSourceSection(), null));
}
}

protected int getLimit(VirtualFrame frame) {
setupLimitCall();
setupLimitIntegerCast();

return limitIntegerCast.executeCastInt(limitCall.call(frame, getBigDecimalClass(), "limit", null));
}

private void setupRoundModeCall() {
if (roundModeCall == null) {
CompilerDirectives.transferToInterpreter();
roundModeCall = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}
}

private void setupRoundModeIntegerCast() {
if (roundModeIntegerCast == null) {
CompilerDirectives.transferToInterpreter();
roundModeIntegerCast = insert(IntegerCastNodeGen.create(getContext(), getSourceSection(), null));
}
}

protected RoundingMode getRoundMode(VirtualFrame frame) {
setupRoundModeCall();
setupRoundModeIntegerCast();

return toRoundingMode(roundModeIntegerCast.executeCastInt(
// TODO (pitr 21-Jun-2015): read the actual constant
roundModeCall.call(frame, getBigDecimalClass(), "mode", null, 256)));
}

protected DynamicObject getBigDecimalClass() {
return coreLibrary().getBigDecimalClass();
}

protected static RoundingMode toRoundingMode(int constValue) {
switch (constValue) {
case 1:
return RoundingMode.UP;
case 2:
return RoundingMode.DOWN;
case 3:
return RoundingMode.HALF_UP;
case 4:
return RoundingMode.HALF_DOWN;
case 5:
return RoundingMode.CEILING;
case 6:
return RoundingMode.FLOOR;
case 7:
return RoundingMode.HALF_EVEN;
default:
throw new UnsupportedOperationException("unknown value: " + constValue);
}
}

protected static int nearestBiggerMultipleOf4(int value) {
return ((value / 4) + 1) * 4;
}

protected static int defaultDivisionPrecision(int precisionA, int precisionB, int limit) {
final int combination = nearestBiggerMultipleOf4(precisionA + precisionB) * 4;
return (limit > 0 && limit < combination) ? limit : combination;
}

protected static int defaultDivisionPrecision(BigDecimal a, BigDecimal b, int limit) {
return defaultDivisionPrecision(a.precision(), b.precision(), limit);
}

}
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib;
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectFactory;
@@ -26,14 +26,14 @@ DynamicObjectFactory createBigDecimalShape(
DynamicObject createBigDecimal(
DynamicObjectFactory factory,
BigDecimal value,
BigDecimalNodes.Type type);
BigDecimalType type);

boolean isBigDecimal(DynamicObject object);

BigDecimal getValue(DynamicObject object);
void setValue(DynamicObject object, BigDecimal value);

BigDecimalNodes.Type getType(DynamicObject object);
void setType(DynamicObject object, BigDecimalNodes.Type value);
BigDecimalType getType(DynamicObject object);
void setType(DynamicObject object, BigDecimalType value);

}
1,396 changes: 1,396 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/stdlib/bigdecimal/BigDecimalNodes.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.dsl.CreateCast;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import org.jruby.truffle.language.RubyNode;

@NodeChildren({
@NodeChild(value = "a", type = RubyNode.class),
@NodeChild(value = "b", type = RubyNode.class),
})
public abstract class BigDecimalOpNode extends BigDecimalCoreMethodNode {

@CreateCast("b")
protected RubyNode castB(RubyNode b) {
return BigDecimalCoerceNodeGen.create(null, null, b);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

public enum BigDecimalType {
NEGATIVE_INFINITY("-Infinity"),
POSITIVE_INFINITY("Infinity"),
NAN("NaN"),
NEGATIVE_ZERO("-0"),
NORMAL(null);

private final String representation;

BigDecimalType(String representation) {
this.representation = representation;
}

public String getRepresentation() {
assert representation != null;
return representation;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.core.cast.BooleanCastNode;
import org.jruby.truffle.core.cast.BooleanCastNodeGen;
import org.jruby.truffle.language.NotProvided;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.language.dispatch.DispatchHeadNodeFactory;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@NodeChildren({
@NodeChild(value = "value", type = RubyNode.class),
@NodeChild(value = "self", type = RubyNode.class),
@NodeChild(value = "digits", type = RubyNode.class)
})
@ImportStatic(BigDecimalType.class)
public abstract class CreateBigDecimalNode extends BigDecimalCoreMethodNode {

private final static Pattern NUMBER_PATTERN;
private final static Pattern ZERO_PATTERN;

static {
final String exponent = "([eE][+-]?)?(\\d*)";
NUMBER_PATTERN = Pattern.compile("^([+-]?\\d*\\.?\\d*" + exponent + ").*");
ZERO_PATTERN = Pattern.compile("^[+-]?0*\\.?0*" + exponent);
}

@Child
private BigDecimalCastNode bigDecimalCast;
@Child
private CallDispatchHeadNode modeCall;
@Child
private GetIntegerConstantNode getIntegerConstant;
@Child
private BooleanCastNode booleanCast;
@Child
private CallDispatchHeadNode allocateNode;

public CreateBigDecimalNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
bigDecimalCast = BigDecimalCastNodeGen.create(context, sourceSection, null, null);
}

private void setBigDecimalValue(DynamicObject bigdecimal, BigDecimal value) {
Layouts.BIG_DECIMAL.setValue(bigdecimal, value);
}

private void setBigDecimalValue(DynamicObject bigdecimal, BigDecimalType type) {
Layouts.BIG_DECIMAL.setType(bigdecimal, type);
}

public abstract DynamicObject executeInitialize(VirtualFrame frame, Object value, DynamicObject alreadyAllocatedSelf, Object digits);

public final DynamicObject executeCreate(VirtualFrame frame, Object value) {
if (allocateNode == null) {
CompilerDirectives.transferToInterpreter();
allocateNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext(), true));
}

DynamicObject rubyClass = (getBigDecimalClass());
return executeInitialize(frame, value, (DynamicObject) allocateNode.call(frame, rubyClass, "allocate", null), NotProvided.INSTANCE);
}

@Specialization
public DynamicObject create(VirtualFrame frame, long value, DynamicObject self, NotProvided digits) {
return create(frame, value, self, 0);
}

@Specialization
public DynamicObject create(VirtualFrame frame, long value, DynamicObject self, int digits) {
setBigDecimalValue(self,
bigDecimalCast.executeBigDecimal(frame, value, getRoundMode(frame)).round(new MathContext(digits, getRoundMode(frame))));
return self;
}

@Specialization
public DynamicObject create(VirtualFrame frame, double value, DynamicObject self, NotProvided digits) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(coreExceptions().argumentError("can't omit precision for a Float.", this));
}

@Specialization
public DynamicObject create(VirtualFrame frame, double value, DynamicObject self, int digits) {
setBigDecimalValue(self,
bigDecimalCast.executeBigDecimal(frame, value, getRoundMode(frame)).round(new MathContext(digits, getRoundMode(frame))));
return self;
}

@Specialization(guards = "value == NEGATIVE_INFINITY || value == POSITIVE_INFINITY")
public DynamicObject createInfinity(VirtualFrame frame, BigDecimalType value, DynamicObject self, Object digits) {
return createWithMode(frame, value, self, "EXCEPTION_INFINITY", "Computation results to 'Infinity'");
}

@Specialization(guards = "value == NAN")
public DynamicObject createNaN(VirtualFrame frame, BigDecimalType value, DynamicObject self, Object digits) {
return createWithMode(frame, value, self, "EXCEPTION_NaN", "Computation results to 'NaN'(Not a Number)");
}

@Specialization(guards = "value == NEGATIVE_ZERO")
public DynamicObject createNegativeZero(VirtualFrame frame, BigDecimalType value, DynamicObject self, Object digits) {
setBigDecimalValue(self, value);
return self;
}

@Specialization
public DynamicObject create(VirtualFrame frame, BigDecimal value, DynamicObject self, NotProvided digits) {
return create(frame, value, self, 0);
}

@Specialization
public DynamicObject create(VirtualFrame frame, BigDecimal value, DynamicObject self, int digits) {
setBigDecimalValue(self, value.round(new MathContext(digits, getRoundMode(frame))));
return self;
}

@Specialization(guards = "isRubyBignum(value)")
public DynamicObject createBignum(VirtualFrame frame, DynamicObject value, DynamicObject self, NotProvided digits) {
return createBignum(frame, value, self, 0);
}

@Specialization(guards = "isRubyBignum(value)")
public DynamicObject createBignum(VirtualFrame frame, DynamicObject value, DynamicObject self, int digits) {
setBigDecimalValue(self,
new BigDecimal(Layouts.BIGNUM.getValue(value)).round(new MathContext(digits, getRoundMode(frame))));
return self;
}

@Specialization(guards = "isRubyBigDecimal(value)")
public DynamicObject createBigDecimal(VirtualFrame frame, DynamicObject value, DynamicObject self, NotProvided digits) {
return createBigDecimal(frame, value, self, 0);
}

@Specialization(guards = "isRubyBigDecimal(value)")
public DynamicObject createBigDecimal(VirtualFrame frame, DynamicObject value, DynamicObject self, int digits) {
setBigDecimalValue(self,
Layouts.BIG_DECIMAL.getValue(value).round(new MathContext(digits, getRoundMode(frame))));
return self;
}

@Specialization(guards = "isRubyString(value)")
public DynamicObject createString(VirtualFrame frame, DynamicObject value, DynamicObject self, NotProvided digits) {
return createString(frame, value, self, 0);
}

@Specialization(guards = "isRubyString(value)")
public DynamicObject createString(VirtualFrame frame, DynamicObject value, DynamicObject self, int digits) {
return executeInitialize(frame, getValueFromString(value.toString(), digits), self, digits);
}

@Specialization(guards = {"!isRubyBignum(value)", "!isRubyBigDecimal(value)", "!isRubyString(value)"})
public DynamicObject create(VirtualFrame frame, DynamicObject value, DynamicObject self, int digits) {
final Object castedValue = bigDecimalCast.executeObject(frame, value, getRoundMode(frame));
if (castedValue == nil()) {
throw new RaiseException(coreExceptions().typeError("could not be casted to BigDecimal", this));
}

setBigDecimalValue(
self,
((BigDecimal) castedValue).round(new MathContext(digits, getRoundMode(frame))));

return self;
}

// TODO (pitr 21-Jun-2015): raise on underflow

private DynamicObject createWithMode(VirtualFrame frame, BigDecimalType value, DynamicObject self,
String constantName, String errorMessage) {
setupModeCall();
setupGetIntegerConstant();
setupBooleanCast();

final int exceptionConstant = getIntegerConstant.executeGetIntegerConstant(frame, getBigDecimalClass(), constantName);
final boolean raise = booleanCast.executeBoolean(frame,
modeCall.call(frame, getBigDecimalClass(), "boolean_mode", null, exceptionConstant));
if (raise) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(coreExceptions().floatDomainError(errorMessage, this));
}

setBigDecimalValue(self, value);
return self;
}

private void setupBooleanCast() {
if (booleanCast == null) {
CompilerDirectives.transferToInterpreter();
booleanCast = insert(BooleanCastNodeGen.create(getContext(), getSourceSection(), null));
}
}

private void setupGetIntegerConstant() {
if (getIntegerConstant == null) {
CompilerDirectives.transferToInterpreter();
getIntegerConstant = insert(GetIntegerConstantNodeGen.create(getContext(), getSourceSection(), null, null));
}
}

private void setupModeCall() {
if (modeCall == null) {
CompilerDirectives.transferToInterpreter();
modeCall = insert(DispatchHeadNodeFactory.createMethodCall(getContext(), true));
}
}

@CompilerDirectives.TruffleBoundary
private Object getValueFromString(String string, int digits) {
String strValue = string.trim();

// TODO (pitr 26-May-2015): create specialization without trims and other cleanups, use rewriteOn

switch (strValue) {
case "NaN":
return BigDecimalType.NAN;
case "Infinity":
case "+Infinity":
return BigDecimalType.POSITIVE_INFINITY;
case "-Infinity":
return BigDecimalType.NEGATIVE_INFINITY;
case "-0":
return BigDecimalType.NEGATIVE_ZERO;
}

// Convert String to Java understandable format (for BigDecimal).
strValue = strValue.replaceFirst("[dD]", "E"); // 1. MRI allows d and D as exponent separators
strValue = strValue.replaceAll("_", ""); // 2. MRI allows underscores anywhere

final MatchResult result;
{
final Matcher matcher = NUMBER_PATTERN.matcher(strValue);
strValue = matcher.replaceFirst("$1"); // 3. MRI ignores the trailing junk
result = matcher.toMatchResult();
}

try {
final BigDecimal value = new BigDecimal(strValue, new MathContext(digits));
if (value.compareTo(BigDecimal.ZERO) == 0 && strValue.startsWith("-")) {
return BigDecimalType.NEGATIVE_ZERO;
} else {
return value;
}

} catch (NumberFormatException e) {
if (ZERO_PATTERN.matcher(strValue).matches()) {
return BigDecimal.ZERO;
}

final BigInteger exponent = new BigInteger(result.group(3));
if (exponent.signum() == 1) {
return BigDecimalType.POSITIVE_INFINITY;
}
// TODO (pitr 21-Jun-2015): raise on underflow
if (exponent.signum() == -1) {
return BigDecimal.ZERO;
}

throw e;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.cast.IntegerCastNode;
import org.jruby.truffle.core.cast.IntegerCastNodeGen;
import org.jruby.truffle.core.cast.ToIntNode;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.constants.ReadConstantNode;

@NodeChildren({@NodeChild("module"), @NodeChild("name")})
public abstract class GetIntegerConstantNode extends RubyNode {

@Child
ReadConstantNode readConstantNode;
@Child
ToIntNode toIntNode;
@Child
IntegerCastNode integerCastNode;

public GetIntegerConstantNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
readConstantNode = new ReadConstantNode(context, sourceSection, false, false, null, null);
toIntNode = ToIntNode.create();
integerCastNode = IntegerCastNodeGen.create(context, sourceSection, null);
}

public abstract int executeGetIntegerConstant(VirtualFrame frame, DynamicObject module, String name);

@Specialization(guards = "isRubyModule(module)")
public int doInteger(VirtualFrame frame, DynamicObject module, String name) {
final Object value = readConstantNode.readConstant(frame, module, name);
return integerCastNode.executeCastInt(toIntNode.executeIntOrLong(frame, value));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.stdlib.bigdecimal;

import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;

import java.math.RoundingMode;

public abstract class RoundModeNode extends BigDecimalCoreMethodNode {

@Specialization
public RoundingMode doGetRoundMode(VirtualFrame frame) {
return getRoundMode(frame);
}

}