Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Applying Marcin's patch (compat.patch) to lopex/compat.

git-svn-id: http://svn.codehaus.org/jruby/branches/lopex@4373 961051c9-f516-0410-bf72-c9f7e237a7b7
  • Loading branch information...
commit 5ace9c7d619ebd85ed96e23f8373d607cf506e64 1 parent 68b9599
@bdortch bdortch authored
Showing with 12,948 additions and 12,581 deletions.
  1. +2 −3 compat/src/org/jruby/IncludedModuleWrapper.java
  2. +27 −20 compat/src/org/jruby/MetaClass.java
  3. +2,250 −1,897 compat/src/org/jruby/Ruby.java
  4. +2 −1  compat/src/org/jruby/RubyArray.java
  5. +769 −763 compat/src/org/jruby/RubyBigDecimal.java
  6. +3 −2 compat/src/org/jruby/RubyBignum.java
  7. +5 −4 compat/src/org/jruby/RubyBinding.java
  8. +8 −2 compat/src/org/jruby/RubyBoolean.java
  9. +239 −309 compat/src/org/jruby/RubyClass.java
  10. +98 −98 compat/src/org/jruby/RubyClassPathVariable.java
  11. +1 −0  compat/src/org/jruby/RubyComparable.java
  12. +4 −3 compat/src/org/jruby/RubyDir.java
  13. +556 −555 compat/src/org/jruby/RubyEnumerable.java
  14. +174 −174 compat/src/org/jruby/RubyEnumerator.java
  15. +2 −9 compat/src/org/jruby/RubyException.java
  16. +4 −5 compat/src/org/jruby/RubyFile.java
  17. +2 −1  compat/src/org/jruby/RubyFileStat.java
  18. +1 −0  compat/src/org/jruby/RubyFileTest.java
  19. +7 −2 compat/src/org/jruby/RubyFixnum.java
  20. +9 −5 compat/src/org/jruby/RubyFloat.java
  21. +1 −0  compat/src/org/jruby/RubyGC.java
  22. +2 −1  compat/src/org/jruby/RubyHash.java
  23. +7 −7 compat/src/org/jruby/RubyIO.java
  24. +3 −3 compat/src/org/jruby/RubyInteger.java
  25. +2 −2 compat/src/org/jruby/RubyJRuby.java
  26. +8 −7 compat/src/org/jruby/RubyKernel.java
  27. +1 −0  compat/src/org/jruby/RubyMarshal.java
  28. +2 −1  compat/src/org/jruby/RubyMatchData.java
  29. +1 −0  compat/src/org/jruby/RubyMath.java
  30. +2 −1  compat/src/org/jruby/RubyMethod.java
  31. +226 −239 compat/src/org/jruby/RubyModule.java
  32. +8 −3 compat/src/org/jruby/RubyNil.java
  33. +3 −2 compat/src/org/jruby/RubyNumeric.java
  34. +97 −115 compat/src/org/jruby/RubyObject.java
  35. +3 −2 compat/src/org/jruby/RubyObjectSpace.java
  36. +3 −2 compat/src/org/jruby/RubyPrecision.java
  37. +14 −6 compat/src/org/jruby/RubyProc.java
  38. +4 −2 compat/src/org/jruby/RubyProcess.java
  39. +29 −19 compat/src/org/jruby/RubyRange.java
  40. +4 −3 compat/src/org/jruby/RubyRegexp.java
  41. +3 −2 compat/src/org/jruby/RubyString.java
  42. +15 −16 compat/src/org/jruby/RubyStruct.java
  43. +7 −2 compat/src/org/jruby/RubySymbol.java
  44. +3 −2 compat/src/org/jruby/RubyThread.java
  45. +1 −0  compat/src/org/jruby/RubyThreadGroup.java
  46. +4 −3 compat/src/org/jruby/RubyTime.java
  47. +3 −2 compat/src/org/jruby/RubyUnboundMethod.java
  48. +305 −297 compat/src/org/jruby/RubyUndef.java
  49. +4 −4 compat/src/org/jruby/RubyZlib.java
  50. +342 −342 compat/src/org/jruby/ast/executable/RubiniusMachine.java
  51. +713 −713 compat/src/org/jruby/ast/executable/YARVMachine.java
  52. +495 −494 compat/src/org/jruby/compiler/MethodCompiler.java
  53. +2,923 −2,916 compat/src/org/jruby/compiler/NodeCompilerFactory.java
  54. +2,661 −2,657 compat/src/org/jruby/compiler/impl/StandardASMCompiler.java
  55. +61 −69 compat/src/org/jruby/evaluator/EvaluationState.java
  56. +15 −6 compat/src/org/jruby/javasupport/Java.java
  57. +4 −4 compat/src/org/jruby/javasupport/JavaArray.java
  58. +1 −1  compat/src/org/jruby/javasupport/JavaClass.java
  59. +549 −568 compat/src/org/jruby/javasupport/util/CompilerHelpers.java
  60. +143 −143 compat/src/org/jruby/libraries/FiberLibrary.java
  61. +28 −28 compat/src/org/jruby/runtime/ObjectAllocator.java
  62. +15 −5 compat/src/org/jruby/runtime/builtin/IRubyObject.java
  63. +23 −5 compat/src/org/jruby/runtime/marshal/MarshalStream.java
  64. +13 −1 compat/src/org/jruby/runtime/marshal/UnmarshalStream.java
  65. +1 −1  compat/test/org/jruby/test/MockRubyObject.java
  66. +1 −1  compat/test/org/jruby/test/TestRubyObject.java
  67. +32 −31 compat/test/test_autoload.rb
View
5 compat/src/org/jruby/IncludedModuleWrapper.java
@@ -48,8 +48,7 @@
private RubyModule delegate;
public IncludedModuleWrapper(Ruby runtime, RubyClass superClass, RubyModule delegate) {
- super(runtime, superClass, null, false);
- // FIXME: The null makes me nervous, but it makes sense that an included wrapper would never have an allocator
+ super(runtime, superClass, false);
this.delegate = delegate;
this.metaClass = delegate.metaClass;
}
@@ -123,7 +122,7 @@ public RubyClass getRealClass() {
return getSuperClass().getRealClass();
}
- public boolean isSame(RubyModule module) {
+ protected boolean isSame(RubyModule module) {
return delegate.isSame(module);
}
View
47 compat/src/org/jruby/MetaClass.java
@@ -29,46 +29,53 @@
***** END LICENSE BLOCK *****/
package org.jruby;
-import org.jruby.runtime.ClassIndex;
-import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.builtin.IRubyObject;
-public class MetaClass extends RubyClass {
+public final class MetaClass extends RubyClass {
+
+ private IRubyObject attached;
- public MetaClass(Ruby runtime, RubyClass superClass, ObjectAllocator allocator,
- RubyModule parent) {
- super(runtime, runtime.getClass("Class"), superClass, allocator, parent, null, false);
-
- this.index = ClassIndex.CLASS;
+ /** NEWOBJ (in RubyObject#getSingletonClassClone())
+ *
+ */
+ public MetaClass(Ruby runtime) {
+ super(runtime, null, false);
+ }
+
+ /** rb_class_boot (for MetaClasses) (in makeMetaClass(RubyClass))
+ *
+ */
+ public MetaClass(Ruby runtime, RubyClass superClass) {
+ super(runtime, superClass, false);
+ index = superClass.index; // use same ClassIndex as metaclass, since we're technically still of that type
}
public boolean isSingleton() {
return true;
}
- protected RubyClass subclass() {
- throw getRuntime().newTypeError("can't make subclass of virtual class");
- }
-
/**
* If an object uses an anonymous class 'class << obj', then this grabs the original
* metaclass and not the one that get injected as a result of 'class << obj'.
*/
public RubyClass getRealClass() {
- return getSuperClass().getRealClass();
+ return superClass.getRealClass();
}
+ public final IRubyObject allocate(){
+ throw getRuntime().newTypeError("can't create instance of virtual class");
+ }
+
public void methodAdded(RubySymbol symbol) {
- getAttachedObject().callMethod(getRuntime().getCurrentContext(), "singleton_method_added", symbol);
+ attached.callMethod(getRuntime().getCurrentContext(), "singleton_method_added", symbol);
}
- public IRubyObject getAttachedObject() {
- // Though it may not be obvious, attachToObject is always called just after instance
- // creation. Kind of a brittle arrangement here...
- return getInstanceVariable("__attached__");
+ public IRubyObject getAttached() {
+ return attached;
}
- public IRubyObject allocateObject() {
- throw getRuntime().newTypeError("can't create instance of virtual class");
+ public void setAttached(IRubyObject attached) {
+ this.attached = attached;
}
+
}
View
4,147 compat/src/org/jruby/Ruby.java
2,250 additions, 1,897 deletions not shown
View
3  compat/src/org/jruby/RubyArray.java
@@ -67,6 +67,7 @@
public static RubyClass createArrayClass(Ruby runtime) {
RubyClass arrayc = runtime.defineClass("Array", runtime.getObject(), ARRAY_ALLOCATOR);
+ runtime.setArray(arrayc);
arrayc.index = ClassIndex.ARRAY;
arrayc.kindOf = new RubyModule.KindOf() {
public boolean isKindOf(IRubyObject obj, RubyModule type) {
@@ -75,7 +76,7 @@ public boolean isKindOf(IRubyObject obj, RubyModule type) {
};
CallbackFactory callbackFactory = runtime.callbackFactory(RubyArray.class);
- arrayc.includeModule(runtime.getModule("Enumerable"));
+ arrayc.includeModule(runtime.getEnumerable());
arrayc.getMetaClass().defineMethod("[]", callbackFactory.getOptSingletonMethod("create"));
arrayc.defineMethod("initialize", callbackFactory.getOptMethod("initialize"));
View
1,532 compat/src/org/jruby/RubyBigDecimal.java
@@ -1,763 +1,769 @@
-/***** BEGIN LICENSE BLOCK *****
- * Version: CPL 1.0/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Common Public
- * License Version 1.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.eclipse.org/legal/cpl-v10.html
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * Copyright (C) 2006 Ola Bini <ola@ologix.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the CPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the CPL, the GPL or the LGPL.
- ***** END LICENSE BLOCK *****/
-package org.jruby;
-
-import java.math.BigDecimal;
-
-import org.jruby.runtime.Arity;
-
-import org.jruby.runtime.Block;
-import org.jruby.runtime.CallbackFactory;
-import org.jruby.runtime.MethodIndex;
-import org.jruby.runtime.ObjectAllocator;
-import org.jruby.runtime.builtin.IRubyObject;
-
-/**
- * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
- */
-public class RubyBigDecimal extends RubyNumeric {
- private static final ObjectAllocator BIGDECIMAL_ALLOCATOR = new ObjectAllocator() {
- public IRubyObject allocate(Ruby runtime, RubyClass klass) {
- return new RubyBigDecimal(runtime, klass);
- }
- };
-
- public static RubyClass createBigDecimal(Ruby runtime) {
- RubyClass result = runtime.defineClass("BigDecimal",runtime.getClass("Numeric"), BIGDECIMAL_ALLOCATOR);
-
- result.setConstant("ROUND_DOWN",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_DOWN));
- result.setConstant("SIGN_POSITIVE_INFINITE",RubyNumeric.int2fix(runtime,3));
- result.setConstant("EXCEPTION_OVERFLOW",RubyNumeric.int2fix(runtime,1));
- result.setConstant("SIGN_POSITIVE_ZERO",RubyNumeric.int2fix(runtime,1));
- result.setConstant("EXCEPTION_ALL",RubyNumeric.int2fix(runtime,255));
- result.setConstant("ROUND_CEILING",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_CEILING));
- result.setConstant("ROUND_UP",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_UP));
- result.setConstant("SIGN_NEGATIVE_FINITE",RubyNumeric.int2fix(runtime,-2));
- result.setConstant("EXCEPTION_UNDERFLOW",RubyNumeric.int2fix(runtime, 4));
- result.setConstant("SIGN_NaN",RubyNumeric.int2fix(runtime, 0));
- result.setConstant("BASE",RubyNumeric.int2fix(runtime,10000));
- result.setConstant("ROUND_HALF_DOWN",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_HALF_DOWN));
- result.setConstant("ROUND_MODE",RubyNumeric.int2fix(runtime,256));
- result.setConstant("SIGN_POSITIVE_FINITE",RubyNumeric.int2fix(runtime,2));
- result.setConstant("EXCEPTION_INFINITY",RubyNumeric.int2fix(runtime,1));
- result.setConstant("ROUND_HALF_EVEN",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_HALF_EVEN));
- result.setConstant("ROUND_HALF_UP",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_HALF_UP));
- result.setConstant("SIGN_NEGATIVE_INFINITE",RubyNumeric.int2fix(runtime,-3));
- result.setConstant("EXCEPTION_ZERODIVIDE",RubyNumeric.int2fix(runtime,1));
- result.setConstant("SIGN_NEGATIVE_ZERO",RubyNumeric.int2fix(runtime,-1));
- result.setConstant("EXCEPTION_NaN",RubyNumeric.int2fix(runtime,2));
- result.setConstant("ROUND_FLOOR",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_FLOOR));
-
- CallbackFactory callbackFactory = runtime.callbackFactory(RubyBigDecimal.class);
-
- runtime.getModule("Kernel").defineModuleFunction("BigDecimal",callbackFactory.getOptSingletonMethod("newBigDecimal"));
- result.getMetaClass().defineMethod("new", callbackFactory.getOptSingletonMethod("newInstance"));
- result.getMetaClass().defineFastMethod("ver", callbackFactory.getFastSingletonMethod("ver"));
- result.getMetaClass().defineMethod("_load", callbackFactory.getSingletonMethod("_load",RubyKernel.IRUBY_OBJECT));
- result.getMetaClass().defineFastMethod("double_fig", callbackFactory.getFastSingletonMethod("double_fig"));
- result.getMetaClass().defineFastMethod("limit", callbackFactory.getFastSingletonMethod("limit", RubyKernel.IRUBY_OBJECT));
- result.getMetaClass().defineFastMethod("mode", callbackFactory.getFastOptSingletonMethod("mode"));
-
- result.defineMethod("initialize", callbackFactory.getOptMethod("initialize"));
- result.defineFastMethod("%", callbackFactory.getFastMethod("mod",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("modulo", callbackFactory.getFastMethod("mod",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("*", callbackFactory.getFastOptMethod("mult"));
- result.defineFastMethod("mult", callbackFactory.getFastOptMethod("mult"));
- result.defineFastMethod("**", callbackFactory.getFastMethod("power",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("power", callbackFactory.getFastMethod("power",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("+", callbackFactory.getFastOptMethod("add"));
- result.defineFastMethod("add", callbackFactory.getFastOptMethod("add"));
- result.defineFastMethod("-", callbackFactory.getFastOptMethod("sub"));
- result.defineFastMethod("sub", callbackFactory.getFastOptMethod("sub"));
- result.defineFastMethod("/", callbackFactory.getFastOptMethod("div"));
- result.defineFastMethod("div", callbackFactory.getFastOptMethod("div"));
- result.defineFastMethod("quo", callbackFactory.getFastOptMethod("div"));
- result.defineFastMethod("<=>", callbackFactory.getFastMethod("spaceship",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("==", callbackFactory.getFastMethod("eql_p",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("===", callbackFactory.getFastMethod("eql_p",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("eql?", callbackFactory.getFastMethod("eql_p",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("!=", callbackFactory.getFastMethod("ne",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("<", callbackFactory.getFastMethod("lt",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("<=", callbackFactory.getFastMethod("le",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod(">", callbackFactory.getFastMethod("gt",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod(">=", callbackFactory.getFastMethod("ge",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("abs", callbackFactory.getFastMethod("abs"));
- result.defineFastMethod("ceil", callbackFactory.getFastMethod("ceil",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("coerce", callbackFactory.getFastMethod("coerce",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("divmod", callbackFactory.getFastMethod("divmod",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("exponent", callbackFactory.getFastMethod("exponent"));
- result.defineFastMethod("finite?", callbackFactory.getFastMethod("finite_p"));
- result.defineFastMethod("fix", callbackFactory.getFastMethod("fix"));
- result.defineFastMethod("floor", callbackFactory.getFastMethod("floor",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("frac", callbackFactory.getFastMethod("frac"));
- result.defineFastMethod("infinite?", callbackFactory.getFastMethod("infinite_p"));
- result.defineFastMethod("inspect", callbackFactory.getFastMethod("inspect"));
- result.defineFastMethod("nan?", callbackFactory.getFastMethod("nan_p"));
- result.defineFastMethod("nonzero?", callbackFactory.getFastMethod("nonzero_p"));
- result.defineFastMethod("precs", callbackFactory.getFastMethod("precs"));
- result.defineFastMethod("remainder", callbackFactory.getFastMethod("remainder",RubyKernel.IRUBY_OBJECT));
- result.defineFastMethod("round", callbackFactory.getFastOptMethod("round"));
- result.defineFastMethod("sign", callbackFactory.getFastMethod("sign"));
- result.defineFastMethod("split", callbackFactory.getFastMethod("split"));
- result.defineFastMethod("sqrt", callbackFactory.getFastOptMethod("sqrt"));
- result.defineFastMethod("to_f", callbackFactory.getFastMethod("to_f"));
- result.defineFastMethod("to_i", callbackFactory.getFastMethod("to_i"));
- result.defineFastMethod("to_int", callbackFactory.getFastMethod("to_int"));
- result.defineFastMethod("to_s", callbackFactory.getFastOptMethod("to_s"));
- result.defineFastMethod("truncate", callbackFactory.getFastOptMethod("truncate"));
- result.defineFastMethod("zero?", callbackFactory.getFastMethod("zero_p"));
-
- result.setClassVar("VpPrecLimit", RubyFixnum.zero(runtime));
- result.setClassVar("VpExceptionMode", RubyFixnum.zero(runtime));
- result.setClassVar("VpRoundingMode", RubyFixnum.zero(runtime));
-
- result.dispatcher = callbackFactory.createDispatcher(result);
-
- return result;
- }
-
- private BigDecimal value;
-
- public RubyBigDecimal(Ruby runtime, RubyClass klass) {
- super(runtime, klass);
- }
-
- public RubyBigDecimal(Ruby runtime, BigDecimal value) {
- super(runtime, runtime.getClass("BigDecimal"));
- this.value = value;
- }
-
- public static RubyBigDecimal newInstance(IRubyObject recv, IRubyObject[] args, Block unusedBlock) {
- RubyClass klass = (RubyClass)recv;
-
- RubyBigDecimal result = (RubyBigDecimal) klass.allocate();
-
- result.callInit(args, Block.NULL_BLOCK);
-
- return result;
- }
-
- public static RubyBigDecimal newBigDecimal(IRubyObject recv, IRubyObject[] args, Block unusedBlock) {
- return newInstance(recv.getRuntime().getClass("BigDecimal"), args, Block.NULL_BLOCK);
- }
-
- public static IRubyObject ver(IRubyObject recv) {
- return recv.getRuntime().newString("1.0.1");
- }
-
- public static IRubyObject _load(IRubyObject recv, IRubyObject p1, Block block) {
- // TODO: implement
- return recv.getRuntime().getNil();
- }
-
- public static IRubyObject double_fig(IRubyObject recv) {
- return recv.getRuntime().newFixnum(20);
- }
-
- public static IRubyObject limit(IRubyObject recv, IRubyObject arg1) {
- RubyModule c = (RubyModule)recv;
- IRubyObject nCur = c.getClassVar("VpPrecLimit");
-
- if (arg1.isNil()) {
- return nCur;
- }
-
- c.setClassVar("VpPrecLimit",arg1);
-
- return nCur;
- }
-
- public static IRubyObject mode(IRubyObject recv, IRubyObject[] args) {
- RubyModule c = (RubyModule)recv;
-
- args = Arity.scanArgs(recv.getRuntime(), args, 1, 1);
-
- IRubyObject mode = args[0];
- IRubyObject value = args[1];
-
- if (!(mode instanceof RubyFixnum)) {
- throw recv.getRuntime().newTypeError("wrong argument type " + mode.getMetaClass() + " (expected Fixnum)");
- }
-
- long longMode = ((RubyFixnum)mode).getLongValue();
- long EXCEPTION_ALL = ((RubyFixnum)recv.getRuntime().getModule("BigDecimal").getConstant("EXCEPTION_ALL")).getLongValue();
- if ((longMode & EXCEPTION_ALL) != 0) {
- if (value.isNil()) {
- return c.getClassVar("VpExceptionMode");
- }
- if (!(value.isNil()) && !(value instanceof RubyBoolean)) {
- throw recv.getRuntime().newTypeError("second argument must be true or false");
- }
-
- RubyFixnum currentExceptionMode = (RubyFixnum)c.getClassVar("VpExceptionMode");
- RubyFixnum newExceptionMode = new RubyFixnum(recv.getRuntime(), currentExceptionMode.getLongValue());
-
- RubyFixnum EXCEPTION_INFINITY = (RubyFixnum)recv.getRuntime().getModule("BigDecimal").getConstant("EXCEPTION_INFINITY");
- if ((longMode & EXCEPTION_INFINITY.getLongValue()) != 0) {
- newExceptionMode = (value.isTrue()) ? (RubyFixnum)currentExceptionMode.callCoerced("|", EXCEPTION_INFINITY)
- : (RubyFixnum)currentExceptionMode.callCoerced("&", new RubyFixnum(recv.getRuntime(), ~(EXCEPTION_INFINITY).getLongValue()));
- }
-
- RubyFixnum EXCEPTION_NaN = (RubyFixnum)recv.getRuntime().getModule("BigDecimal").getConstant("EXCEPTION_NaN");
- if ((longMode & EXCEPTION_NaN.getLongValue()) != 0) {
- newExceptionMode = (value.isTrue()) ? (RubyFixnum)currentExceptionMode.callCoerced("|", EXCEPTION_NaN)
- : (RubyFixnum)currentExceptionMode.callCoerced("&", new RubyFixnum(recv.getRuntime(), ~(EXCEPTION_NaN).getLongValue()));
- }
- c.setClassVar("VpExceptionMode", newExceptionMode);
- return newExceptionMode;
- }
-
- long ROUND_MODE = ((RubyFixnum)recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_MODE")).getLongValue();
- if (longMode == ROUND_MODE) {
- if (value.isNil()) {
- return c.getClassVar("VpRoundingMode");
- }
- if (!(value instanceof RubyFixnum)) {
- throw recv.getRuntime().newTypeError("wrong argument type " + mode.getMetaClass() + " (expected Fixnum)");
- }
-
- RubyFixnum roundingMode = (RubyFixnum)value;
- if (roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_UP") ||
- roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_DOWN") ||
- roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_FLOOR") ||
- roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_CEILING") ||
- roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_HALF_UP") ||
- roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_HALF_DOWN") ||
- roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_HALF_EVEN")) {
- c.setClassVar("VpRoundingMode", roundingMode);
- } else {
- throw recv.getRuntime().newTypeError("invalid rounding mode");
- }
- return c.getClassVar("VpRoundingMode");
- }
- throw recv.getRuntime().newTypeError("first argument for BigDecimal#mode invalid");
- }
-
- private RubyBigDecimal getVpValue(IRubyObject v, boolean must) {
- if(v instanceof RubyBigDecimal) {
- return (RubyBigDecimal)v;
- } else if(v instanceof RubyFixnum || v instanceof RubyBignum) {
- String s = v.toString();
- return newInstance(getRuntime().getClass("BigDecimal"),new IRubyObject[]{getRuntime().newString(s)}, Block.NULL_BLOCK);
- }
- if(must) {
- throw getRuntime().newTypeError(trueFalseNil(v.getMetaClass().getName() + " can't be coerced into BigDecimal"));
- }
- return null;
- }
-
- public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) {
- String ss = args[0].convertToString().toString();
-
- try {
- this.value = new BigDecimal(ss);
- } catch(NumberFormatException e) {
- this.value = new BigDecimal("0");
- }
-
- return this;
- }
-
- private RubyBigDecimal setResult() {
- return setResult(0);
- }
-
- private RubyBigDecimal setResult(int scale) {
- int prec = RubyFixnum.fix2int(getRuntime().getClass("BigDecimal").getClassVar("VpPrecLimit"));
- int prec2 = Math.max(scale,prec);
- if(prec2 > 0 && this.value.scale() > (prec2-exp())) {
- this.value = this.value.setScale(prec2-exp(),BigDecimal.ROUND_HALF_UP);
- }
- return this;
- }
-
- public IRubyObject mod(IRubyObject arg) {
- RubyBigDecimal val = getVpValue(arg,false);
- return new RubyBigDecimal(getRuntime(),this.value.divideAndRemainder(val.value)[1]).setResult();
- }
-
- public IRubyObject mult(IRubyObject[] args) {
- RubyBigDecimal val = getVpValue(args[0],false);
- if(val == null) {
- return callCoerced("*",args[0]);
- }
-
- return new RubyBigDecimal(getRuntime(),value.multiply(val.value)).setResult();
- }
-
- public IRubyObject power(IRubyObject arg) {
- if (!(arg instanceof RubyFixnum)) {
- throw getRuntime().newTypeError("wrong argument type " + arg.getMetaClass() + " (expected Fixnum)");
- }
-
- BigDecimal val = value;
-
- int times = RubyNumeric.fix2int(arg.convertToInteger());
- int sign = 0;
- if (times < 0) {
- sign = -1;
- times = -times;
- }
-
- BigDecimal result = BigDecimal.ONE;
- while (times > 0) {
- if (times % 2 != 0) {
- result = result.multiply(val);
- times -= 1;
- }
- val = val.multiply(val);
- times /= 2;
- }
-
- if (sign == -1) {
- result = BigDecimal.ONE.divide(result);
- }
-
- return new RubyBigDecimal(getRuntime(),result).setResult();
- }
-
- public IRubyObject add(IRubyObject[] args) {
- RubyBigDecimal val = getVpValue(args[0],false);
- if(val == null) {
- return callCoerced("+",args[0]);
- }
- return new RubyBigDecimal(getRuntime(),value.add(val.value)).setResult();
- }
-
- public IRubyObject sub(IRubyObject[] args) {
- RubyBigDecimal val = getVpValue(args[0],false);
- if(val == null) {
- return callCoerced("-",args[0]);
- }
- return new RubyBigDecimal(getRuntime(),value.subtract(val.value)).setResult();
- }
-
- public IRubyObject div(IRubyObject[] args) {
- int scale = 0;
- if(Arity.checkArgumentCount(getRuntime(), args,1,2) == 2) {
- scale = RubyNumeric.fix2int(args[1]);
- }
-
- RubyBigDecimal val = getVpValue(args[0],false);
- if(val == null) {
- return callCoerced("/",args[0]);
- }
-
- if(scale == 0) {
- return new RubyBigDecimal(getRuntime(),value.divide(val.value,200,BigDecimal.ROUND_HALF_UP)).setResult();
- } else {
- return new RubyBigDecimal(getRuntime(),value.divide(val.value,200,BigDecimal.ROUND_HALF_UP)).setResult(scale);
- }
- }
-
- private IRubyObject cmp(IRubyObject r, char op) {
- int e = 0;
- RubyBigDecimal rb = getVpValue(r,false);
- if(rb == null) {
- IRubyObject ee = callCoerced("<=>",r);
- if(ee.isNil()) {
- return getRuntime().getNil();
- }
- e = RubyNumeric.fix2int(ee);
- } else {
- e = value.compareTo(rb.value);
- }
- switch(op) {
- case '*': return getRuntime().newFixnum(e);
- case '=': return (e==0)?getRuntime().getTrue():getRuntime().getFalse();
- case '!': return (e!=0)?getRuntime().getTrue():getRuntime().getFalse();
- case 'G': return (e>=0)?getRuntime().getTrue():getRuntime().getFalse();
- case '>': return (e> 0)?getRuntime().getTrue():getRuntime().getFalse();
- case 'L': return (e<=0)?getRuntime().getTrue():getRuntime().getFalse();
- case '<': return (e< 0)?getRuntime().getTrue():getRuntime().getFalse();
- }
- return getRuntime().getNil();
- }
-
- public IRubyObject spaceship(IRubyObject arg) {
- return cmp(arg,'*');
- }
-
- public IRubyObject eql_p(IRubyObject arg) {
- return cmp(arg,'=');
- }
-
- public IRubyObject ne(IRubyObject arg) {
- return cmp(arg,'!');
- }
-
- public IRubyObject lt(IRubyObject arg) {
- return cmp(arg,'<');
- }
-
- public IRubyObject le(IRubyObject arg) {
- return cmp(arg,'L');
- }
-
- public IRubyObject gt(IRubyObject arg) {
- return cmp(arg,'>');
- }
-
- public IRubyObject ge(IRubyObject arg) {
- return cmp(arg,'G');
- }
-
- public IRubyObject abs() {
- return new RubyBigDecimal(getRuntime(),value.abs()).setResult();
- }
-
- public IRubyObject ceil(IRubyObject arg) {
- System.err.println("unimplemented: ceil");
- // TODO: implement correctly
- return this;
- }
-
- public IRubyObject coerce(IRubyObject other) {
- IRubyObject obj;
- if(other instanceof RubyFloat) {
- obj = getRuntime().newArray(other,to_f());
- } else {
- obj = getRuntime().newArray(getVpValue(other, true),this);
- }
- return obj;
- }
-
- public double getDoubleValue() { return value.doubleValue(); }
- public long getLongValue() { return value.longValue(); }
-
- public RubyNumeric multiplyWith(RubyInteger value) {
- return (RubyNumeric)mult(new IRubyObject[]{value});
- }
-
- public RubyNumeric multiplyWith(RubyFloat value) {
- return (RubyNumeric)mult(new IRubyObject[]{value});
- }
-
- public RubyNumeric multiplyWith(RubyBignum value) {
- return (RubyNumeric)mult(new IRubyObject[]{value});
- }
-
- public IRubyObject divmod(IRubyObject arg) {
- System.err.println("unimplemented: divmod");
- // TODO: implement
- return getRuntime().getNil();
- }
-
- public IRubyObject exponent() {
- return getRuntime().newFixnum(exp());
- }
-
- private int exp() {
- return value.abs().unscaledValue().toString().length() - value.abs().scale();
- }
-
- public IRubyObject finite_p() {
- System.err.println("unimplemented: finite?");
- // TODO: implement correctly
- return getRuntime().getTrue();
- }
-
- public IRubyObject fix() {
- System.err.println("unimplemented: fix");
- // TODO: implement correctly
- return this;
- }
-
- public IRubyObject floor(IRubyObject arg) {
- System.err.println("unimplemented: floor");
- // TODO: implement correctly
- return this;
- }
-
- public IRubyObject frac() {
- System.err.println("unimplemented: frac");
- // TODO: implement correctly
- return this;
- }
-
- public IRubyObject infinite_p() {
- System.err.println("unimplemented: infinite?");
- // TODO: implement correctly
- return getRuntime().getFalse();
- }
-
- public IRubyObject inspect() {
- StringBuffer val = new StringBuffer("#<BigDecimal:").append(Integer.toHexString(System.identityHashCode(this))).append(",");
- val.append("'").append(this.callMethod(getRuntime().getCurrentContext(), MethodIndex.TO_S, "to_s")).append("'").append(",");
- int len = value.abs().unscaledValue().toString().length();
- int pow = len/4;
- val.append(len).append("(").append((pow+1)*4).append(")").append(">");
- return getRuntime().newString(val.toString());
- }
-
- public IRubyObject nan_p() {
- System.err.println("unimplemented: nan?");
- // TODO: implement correctly
- return getRuntime().getFalse();
- }
-
- public IRubyObject nonzero_p() {
- return value.signum() != 0 ? getRuntime().getTrue() : getRuntime().getFalse();
- }
-
- public IRubyObject precs() {
- System.err.println("unimplemented: precs");
- // TODO: implement
- return getRuntime().getNil();
- }
-
- public IRubyObject remainder(IRubyObject arg) {
- System.err.println("unimplemented: remainder");
- // TODO: implement
- return this;
- }
-
- public IRubyObject round(IRubyObject[] args) {
- int scale = args.length > 0 ? num2int(args[0]) : 0;
- int mode = (args.length > 1) ? javaRoundingModeFromRubyRoundingMode(args[1]) : BigDecimal.ROUND_HALF_UP;
- // JRUBY-914: Java 1.4 BigDecimal does not allow a negative scale, so we have to simulate it
- if (scale < 0) {
- // shift the decimal point just to the right of the digit to be rounded to (divide by 10**(abs(scale)))
- // -1 -> 10's digit, -2 -> 100's digit, etc.
- BigDecimal normalized = value.movePointRight(scale);
- // ...round to that digit
- BigDecimal rounded = normalized.setScale(0,mode);
- // ...and shift the result back to the left (multiply by 10**(abs(scale)))
- return new RubyBigDecimal(getRuntime(), rounded.movePointLeft(scale));
- } else {
- return new RubyBigDecimal(getRuntime(), value.setScale(scale, mode));
- }
- }
-
- //this relies on the Ruby rounding enumerations == Java ones, which they (currently) all are
- private int javaRoundingModeFromRubyRoundingMode(IRubyObject arg) {
- return num2int(arg);
- }
-
- public IRubyObject sign() {
- System.err.println("unimplemented: sign");
- // TODO: implement correctly
- return getRuntime().newFixnum(value.signum());
- }
-
- public IRubyObject split() {
- System.err.println("unimplemented: split");
- // TODO: implement
- return getRuntime().getNil();
- }
-
- public IRubyObject sqrt(IRubyObject[] args) {
- System.err.println("unimplemented: sqrt");
- // TODO: implement correctly
- return new RubyBigDecimal(getRuntime(),new BigDecimal(Math.sqrt(value.doubleValue()))).setResult();
- }
-
- public IRubyObject to_f() {
- return RubyFloat.newFloat(getRuntime(),value.doubleValue());
- }
-
- public IRubyObject to_i() {
- return RubyNumeric.int2fix(getRuntime(),value.longValue());
- }
-
- public IRubyObject to_int() {
- // TODO: implement to handle infinity and stuff
- return RubyNumeric.int2fix(getRuntime(),value.longValue());
- }
-
- private String removeTrailingZeroes(String in) {
- while(in.length() > 0 && in.charAt(in.length()-1)=='0') {
- in = in.substring(0,in.length()-1);
- }
- return in;
- }
-
- private String toSpecialString(BigDecimal abs) {
- if (abs.compareTo(BigDecimal.valueOf(0))== 0) {
- return "0.0";
- }
- //TODO: match the MRI code below!
- //TODO: refactor the overly-long branches in to_s so we can reuse the sign processing here
- return null;
-// if(VpIsNaN(a)) {
-// sprintf(psz,SZ_NaN);
-// return 1;
-// }
-//
-// if(VpIsPosInf(a)) {
-// if(fPlus==1) {
-// *psz++ = ' ';
-// } else if(fPlus==2) {
-// *psz++ = '+';
-// }
-// sprintf(psz,SZ_INF);
-// return 1;
-// }
-// if(VpIsNegInf(a)) {
-// sprintf(psz,SZ_NINF);
-// return 1;
-// }
-// if(VpIsZero(a)) {
-// if(VpIsPosZero(a)) {
-// if(fPlus==1) sprintf(psz, " 0.0");
-// else if(fPlus==2) sprintf(psz, "+0.0");
-// else sprintf(psz, "0.0");
-// } else sprintf(psz, "-0.0");
-// return 1;
-// }
-// return 0;
-
- }
-
- public IRubyObject to_s(IRubyObject[] args) {
- boolean engineering = true;
- boolean pos_sign = false;
- boolean pos_space = false;
- int groups = 0;
-
- if(args.length != 0 && !args[0].isNil()) {
- String format = args[0].toString();
- int start = 0;
- int end = format.length();
- if(format.length() > 0 && format.charAt(0) == '+') {
- pos_sign = true;
- start++;
- } else if(format.length() > 0 && format.charAt(0) == ' ') {
- pos_sign = true;
- pos_space = true;
- start++;
- }
- if(format.length() > 0 && format.charAt(format.length()-1) == 'F') {
- engineering = false;
- end--;
- } else if(format.length() > 0 && format.charAt(format.length()-1) == 'E') {
- engineering = true;
- end--;
- }
- String nums = format.substring(start,end);
- if(nums.length()>0) {
- groups = Integer.parseInt(nums);
- }
- }
-
- String out = null;
- BigDecimal abs = value.abs();
- String unscaled = abs.unscaledValue().toString();
-
- //not beautiful, but parallel to MRI's VpToSpecialString
- if (null != (out = toSpecialString(abs))) {
- return getRuntime().newString(out);
- }
- if(engineering) {
- int exponent = exp();
- int signum = value.signum();
- StringBuffer build = new StringBuffer();
- build.append(signum == -1 ? "-" : (signum == 1 ? (pos_sign ? (pos_space ? " " : "+" ) : "") : ""));
- build.append("0.");
- if(0 == groups) {
- String s = removeTrailingZeroes(unscaled);
- if("".equals(s)) {
- build.append("0");
- } else {
- build.append(s);
- }
- } else {
- int index = 0;
- String sep = "";
- while(index < unscaled.length()) {
- int next = index+groups;
- if(next > unscaled.length()) {
- next = unscaled.length();
- }
- build.append(sep).append(unscaled.substring(index,next));
- sep = " ";
- index += groups;
- }
- }
- build.append("E").append(exponent);
- out = build.toString();
- } else {
- int ix = abs.toString().indexOf('.');
- String whole = unscaled;
- String after = null;
- if(ix != -1) {
- whole = unscaled.substring(0,ix);
- after = unscaled.substring(ix);
- }
- int signum = value.signum();
- StringBuffer build = new StringBuffer();
- build.append(signum == -1 ? "-" : (signum == 1 ? (pos_sign ? (pos_space ? " " : "+" ) : "") : ""));
- if(0 == groups) {
- build.append(whole);
- if(null != after) {
- build.append(".").append(after);
- }
- } else {
- int index = 0;
- String sep = "";
- while(index < whole.length()) {
- int next = index+groups;
- if(next > whole.length()) {
- next = whole.length();
- }
- build.append(sep).append(whole.substring(index,next));
- sep = " ";
- index += groups;
- }
- if(null != after) {
- System.out.println("AFTER: " + after);
- build.append(".");
- index = 0;
- sep = "";
- while(index < after.length()) {
- int next = index+groups;
- if(next > after.length()) {
- next = after.length();
- }
- build.append(sep).append(after.substring(index,next));
- sep = " ";
- index += groups;
- }
- }
- }
- out = build.toString();
- }
-
- return getRuntime().newString(out);
- }
-
- public IRubyObject truncate(IRubyObject[] args) {
- System.err.println("unimplemented: truncate");
- // TODO: implement
- return this;
- }
-
- public IRubyObject zero_p() {
- return value.signum() == 0 ? getRuntime().getTrue() : getRuntime().getFalse();
- }
-}// RubyBigdecimal
+/***** BEGIN LICENSE BLOCK *****
+ * Version: CPL 1.0/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Common Public
+ * License Version 1.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * Copyright (C) 2006 Ola Bini <ola@ologix.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the CPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the CPL, the GPL or the LGPL.
+ ***** END LICENSE BLOCK *****/
+package org.jruby;
+
+import java.math.BigDecimal;
+
+import org.jruby.runtime.Arity;
+
+import org.jruby.runtime.Block;
+import org.jruby.runtime.CallbackFactory;
+import org.jruby.runtime.MethodIndex;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.builtin.IRubyObject;
+
+/**
+ * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
+ */
+public class RubyBigDecimal extends RubyNumeric {
+ private static final ObjectAllocator BIGDECIMAL_ALLOCATOR = new ObjectAllocator() {
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
+ return new RubyBigDecimal(runtime, klass);
+ }
+ };
+
+ public static RubyClass createBigDecimal(Ruby runtime) {
+ RubyClass result = runtime.defineClass("BigDecimal",runtime.getNumeric(), BIGDECIMAL_ALLOCATOR);
+
+ result.setConstant("ROUND_DOWN",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_DOWN));
+ result.setConstant("SIGN_POSITIVE_INFINITE",RubyNumeric.int2fix(runtime,3));
+ result.setConstant("EXCEPTION_OVERFLOW",RubyNumeric.int2fix(runtime,1));
+ result.setConstant("SIGN_POSITIVE_ZERO",RubyNumeric.int2fix(runtime,1));
+ result.setConstant("EXCEPTION_ALL",RubyNumeric.int2fix(runtime,255));
+ result.setConstant("ROUND_CEILING",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_CEILING));
+ result.setConstant("ROUND_UP",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_UP));
+ result.setConstant("SIGN_NEGATIVE_FINITE",RubyNumeric.int2fix(runtime,-2));
+ result.setConstant("EXCEPTION_UNDERFLOW",RubyNumeric.int2fix(runtime, 4));
+ result.setConstant("SIGN_NaN",RubyNumeric.int2fix(runtime, 0));
+ result.setConstant("BASE",RubyNumeric.int2fix(runtime,10000));
+ result.setConstant("ROUND_HALF_DOWN",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_HALF_DOWN));
+ result.setConstant("ROUND_MODE",RubyNumeric.int2fix(runtime,256));
+ result.setConstant("SIGN_POSITIVE_FINITE",RubyNumeric.int2fix(runtime,2));
+ result.setConstant("EXCEPTION_INFINITY",RubyNumeric.int2fix(runtime,1));
+ result.setConstant("ROUND_HALF_EVEN",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_HALF_EVEN));
+ result.setConstant("ROUND_HALF_UP",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_HALF_UP));
+ result.setConstant("SIGN_NEGATIVE_INFINITE",RubyNumeric.int2fix(runtime,-3));
+ result.setConstant("EXCEPTION_ZERODIVIDE",RubyNumeric.int2fix(runtime,1));
+ result.setConstant("SIGN_NEGATIVE_ZERO",RubyNumeric.int2fix(runtime,-1));
+ result.setConstant("EXCEPTION_NaN",RubyNumeric.int2fix(runtime,2));
+ result.setConstant("ROUND_FLOOR",RubyNumeric.int2fix(runtime,BigDecimal.ROUND_FLOOR));
+
+ CallbackFactory callbackFactory = runtime.callbackFactory(RubyBigDecimal.class);
+
+ runtime.getKernel().defineModuleFunction("BigDecimal",callbackFactory.getOptSingletonMethod("newBigDecimal"));
+ result.getMetaClass().defineMethod("new", callbackFactory.getOptSingletonMethod("newInstance"));
+ result.getMetaClass().defineFastMethod("ver", callbackFactory.getFastSingletonMethod("ver"));
+ result.getMetaClass().defineMethod("_load", callbackFactory.getSingletonMethod("_load",RubyKernel.IRUBY_OBJECT));
+ result.getMetaClass().defineFastMethod("double_fig", callbackFactory.getFastSingletonMethod("double_fig"));
+ result.getMetaClass().defineFastMethod("limit", callbackFactory.getFastSingletonMethod("limit", RubyKernel.IRUBY_OBJECT));
+ result.getMetaClass().defineFastMethod("mode", callbackFactory.getFastOptSingletonMethod("mode"));
+
+ result.defineMethod("initialize", callbackFactory.getOptMethod("initialize"));
+ result.defineFastMethod("%", callbackFactory.getFastMethod("mod",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("modulo", callbackFactory.getFastMethod("mod",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("*", callbackFactory.getFastOptMethod("mult"));
+ result.defineFastMethod("mult", callbackFactory.getFastOptMethod("mult"));
+ result.defineFastMethod("**", callbackFactory.getFastMethod("power",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("power", callbackFactory.getFastMethod("power",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("+", callbackFactory.getFastOptMethod("add"));
+ result.defineFastMethod("add", callbackFactory.getFastOptMethod("add"));
+ result.defineFastMethod("-", callbackFactory.getFastOptMethod("sub"));
+ result.defineFastMethod("sub", callbackFactory.getFastOptMethod("sub"));
+ result.defineFastMethod("/", callbackFactory.getFastOptMethod("div"));
+ result.defineFastMethod("div", callbackFactory.getFastOptMethod("div"));
+ result.defineFastMethod("quo", callbackFactory.getFastOptMethod("div"));
+ result.defineFastMethod("<=>", callbackFactory.getFastMethod("spaceship",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("==", callbackFactory.getFastMethod("eql_p",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("===", callbackFactory.getFastMethod("eql_p",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("eql?", callbackFactory.getFastMethod("eql_p",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("!=", callbackFactory.getFastMethod("ne",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("<", callbackFactory.getFastMethod("lt",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("<=", callbackFactory.getFastMethod("le",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod(">", callbackFactory.getFastMethod("gt",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod(">=", callbackFactory.getFastMethod("ge",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("abs", callbackFactory.getFastMethod("abs"));
+ result.defineFastMethod("ceil", callbackFactory.getFastMethod("ceil",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("coerce", callbackFactory.getFastMethod("coerce",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("divmod", callbackFactory.getFastMethod("divmod",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("exponent", callbackFactory.getFastMethod("exponent"));
+ result.defineFastMethod("finite?", callbackFactory.getFastMethod("finite_p"));
+ result.defineFastMethod("fix", callbackFactory.getFastMethod("fix"));
+ result.defineFastMethod("floor", callbackFactory.getFastMethod("floor",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("frac", callbackFactory.getFastMethod("frac"));
+ result.defineFastMethod("infinite?", callbackFactory.getFastMethod("infinite_p"));
+ result.defineFastMethod("inspect", callbackFactory.getFastMethod("inspect"));
+ result.defineFastMethod("nan?", callbackFactory.getFastMethod("nan_p"));
+ result.defineFastMethod("nonzero?", callbackFactory.getFastMethod("nonzero_p"));
+ result.defineFastMethod("precs", callbackFactory.getFastMethod("precs"));
+ result.defineFastMethod("remainder", callbackFactory.getFastMethod("remainder",RubyKernel.IRUBY_OBJECT));
+ result.defineFastMethod("round", callbackFactory.getFastOptMethod("round"));
+ result.defineFastMethod("sign", callbackFactory.getFastMethod("sign"));
+ result.defineFastMethod("split", callbackFactory.getFastMethod("split"));
+ result.defineFastMethod("sqrt", callbackFactory.getFastOptMethod("sqrt"));
+ result.defineFastMethod("to_f", callbackFactory.getFastMethod("to_f"));
+ result.defineFastMethod("to_i", callbackFactory.getFastMethod("to_i"));
+ result.defineFastMethod("to_int", callbackFactory.getFastMethod("to_int"));
+ result.defineFastMethod("to_s", callbackFactory.getFastOptMethod("to_s"));
+ result.defineFastMethod("truncate", callbackFactory.getFastOptMethod("truncate"));
+ result.defineFastMethod("zero?", callbackFactory.getFastMethod("zero_p"));
+
+ result.setClassVar("VpPrecLimit", RubyFixnum.zero(runtime));
+ result.setClassVar("VpExceptionMode", RubyFixnum.zero(runtime));
+ result.setClassVar("VpRoundingMode", RubyFixnum.zero(runtime));
+
+ result.dispatcher = callbackFactory.createDispatcher(result);
+
+ return result;
+ }
+
+ private BigDecimal value;
+
+ public RubyBigDecimal(Ruby runtime, RubyClass klass) {
+ super(runtime, klass);
+ }
+
+ public RubyBigDecimal(Ruby runtime, BigDecimal value) {
+ super(runtime, runtime.getClass("BigDecimal"));
+ this.value = value;
+ }
+
+ public static RubyBigDecimal newInstance(IRubyObject recv, IRubyObject[] args, Block unusedBlock) {
+ RubyClass klass = (RubyClass)recv;
+
+ RubyBigDecimal result = (RubyBigDecimal) klass.allocate();
+
+ result.callInit(args, Block.NULL_BLOCK);
+
+ return result;
+ }
+
+ public static RubyBigDecimal newBigDecimal(IRubyObject recv, IRubyObject[] args, Block unusedBlock) {
+ return newInstance(recv.getRuntime().getClass("BigDecimal"), args, Block.NULL_BLOCK);
+ }
+
+ public static IRubyObject ver(IRubyObject recv) {
+ return recv.getRuntime().newString("1.0.1");
+ }
+
+ public static IRubyObject _load(IRubyObject recv, IRubyObject p1, Block block) {
+ // TODO: implement
+ return recv.getRuntime().getNil();
+ }
+
+ public static IRubyObject double_fig(IRubyObject recv) {
+ return recv.getRuntime().newFixnum(20);
+ }
+
+ public static IRubyObject limit(IRubyObject recv, IRubyObject arg1) {
+ RubyModule c = (RubyModule)recv;
+ IRubyObject nCur = c.getClassVar("VpPrecLimit");
+
+ if (arg1.isNil()) {
+ return nCur;
+ }
+
+ c.setClassVar("VpPrecLimit",arg1);
+
+ return nCur;
+ }
+
+ public static IRubyObject mode(IRubyObject recv, IRubyObject[] args) {
+ RubyModule c = (RubyModule)recv;
+
+ args = Arity.scanArgs(recv.getRuntime(), args, 1, 1);
+
+ IRubyObject mode = args[0];
+ IRubyObject value = args[1];
+
+ if (!(mode instanceof RubyFixnum)) {
+ throw recv.getRuntime().newTypeError("wrong argument type " + mode.getMetaClass() + " (expected Fixnum)");
+ }
+
+ long longMode = ((RubyFixnum)mode).getLongValue();
+ long EXCEPTION_ALL = ((RubyFixnum)recv.getRuntime().getModule("BigDecimal").getConstant("EXCEPTION_ALL")).getLongValue();
+ if ((longMode & EXCEPTION_ALL) != 0) {
+ if (value.isNil()) {
+ return c.getClassVar("VpExceptionMode");
+ }
+ if (!(value.isNil()) && !(value instanceof RubyBoolean)) {
+ throw recv.getRuntime().newTypeError("second argument must be true or false");
+ }
+
+ RubyFixnum currentExceptionMode = (RubyFixnum)c.getClassVar("VpExceptionMode");
+ RubyFixnum newExceptionMode = new RubyFixnum(recv.getRuntime(), currentExceptionMode.getLongValue());
+
+ RubyFixnum EXCEPTION_INFINITY = (RubyFixnum)recv.getRuntime().getModule("BigDecimal").getConstant("EXCEPTION_INFINITY");
+ if ((longMode & EXCEPTION_INFINITY.getLongValue()) != 0) {
+ newExceptionMode = (value.isTrue()) ? (RubyFixnum)currentExceptionMode.callCoerced("|", EXCEPTION_INFINITY)
+ : (RubyFixnum)currentExceptionMode.callCoerced("&", new RubyFixnum(recv.getRuntime(), ~(EXCEPTION_INFINITY).getLongValue()));
+ }
+
+ RubyFixnum EXCEPTION_NaN = (RubyFixnum)recv.getRuntime().getModule("BigDecimal").getConstant("EXCEPTION_NaN");
+ if ((longMode & EXCEPTION_NaN.getLongValue()) != 0) {
+ newExceptionMode = (value.isTrue()) ? (RubyFixnum)currentExceptionMode.callCoerced("|", EXCEPTION_NaN)
+ : (RubyFixnum)currentExceptionMode.callCoerced("&", new RubyFixnum(recv.getRuntime(), ~(EXCEPTION_NaN).getLongValue()));
+ }
+ c.setClassVar("VpExceptionMode", newExceptionMode);
+ return newExceptionMode;
+ }
+
+ long ROUND_MODE = ((RubyFixnum)recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_MODE")).getLongValue();
+ if (longMode == ROUND_MODE) {
+ if (value.isNil()) {
+ return c.getClassVar("VpRoundingMode");
+ }
+ if (!(value instanceof RubyFixnum)) {
+ throw recv.getRuntime().newTypeError("wrong argument type " + mode.getMetaClass() + " (expected Fixnum)");
+ }
+
+ RubyFixnum roundingMode = (RubyFixnum)value;
+ if (roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_UP") ||
+ roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_DOWN") ||
+ roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_FLOOR") ||
+ roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_CEILING") ||
+ roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_HALF_UP") ||
+ roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_HALF_DOWN") ||
+ roundingMode == recv.getRuntime().getModule("BigDecimal").getConstant("ROUND_HALF_EVEN")) {
+ c.setClassVar("VpRoundingMode", roundingMode);
+ } else {
+ throw recv.getRuntime().newTypeError("invalid rounding mode");
+ }
+ return c.getClassVar("VpRoundingMode");
+ }
+ throw recv.getRuntime().newTypeError("first argument for BigDecimal#mode invalid");
+ }
+
+ private RubyBigDecimal getVpValue(IRubyObject v, boolean must) {
+ if(v instanceof RubyBigDecimal) {
+ return (RubyBigDecimal)v;
+ } else if(v instanceof RubyFixnum || v instanceof RubyBignum) {
+ String s = v.toString();
+ return newInstance(getRuntime().getClass("BigDecimal"),new IRubyObject[]{getRuntime().newString(s)}, Block.NULL_BLOCK);
+ }
+ if(must) {
+ String err;
+ if (isImmediate()) {
+ err = RubyString.objAsString(callMethod(getRuntime().getCurrentContext(), "inspect")).toString();
+ } else {
+ err = getMetaClass().getBaseName();
+ }
+ throw getRuntime().newTypeError(err + " can't be coerced into BigDecimal");
+ }
+ return null;
+ }
+
+ public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) {
+ String ss = args[0].convertToString().toString();
+
+ try {
+ this.value = new BigDecimal(ss);
+ } catch(NumberFormatException e) {
+ this.value = new BigDecimal("0");
+ }
+
+ return this;
+ }
+
+ private RubyBigDecimal setResult() {
+ return setResult(0);
+ }
+
+ private RubyBigDecimal setResult(int scale) {
+ int prec = RubyFixnum.fix2int(getRuntime().getClass("BigDecimal").getClassVar("VpPrecLimit"));
+ int prec2 = Math.max(scale,prec);
+ if(prec2 > 0 && this.value.scale() > (prec2-exp())) {
+ this.value = this.value.setScale(prec2-exp(),BigDecimal.ROUND_HALF_UP);
+ }
+ return this;
+ }
+
+ public IRubyObject mod(IRubyObject arg) {
+ RubyBigDecimal val = getVpValue(arg,false);
+ return new RubyBigDecimal(getRuntime(),this.value.divideAndRemainder(val.value)[1]).setResult();
+ }
+
+ public IRubyObject mult(IRubyObject[] args) {
+ RubyBigDecimal val = getVpValue(args[0],false);
+ if(val == null) {
+ return callCoerced("*",args[0]);
+ }
+
+ return new RubyBigDecimal(getRuntime(),value.multiply(val.value)).setResult();
+ }
+
+ public IRubyObject power(IRubyObject arg) {
+ if (!(arg instanceof RubyFixnum)) {
+ throw getRuntime().newTypeError("wrong argument type " + arg.getMetaClass() + " (expected Fixnum)");
+ }
+
+ BigDecimal val = value;
+
+ int times = RubyNumeric.fix2int(arg.convertToInteger());
+ int sign = 0;
+ if (times < 0) {
+ sign = -1;
+ times = -times;
+ }
+
+ BigDecimal result = BigDecimal.ONE;
+ while (times > 0) {
+ if (times % 2 != 0) {
+ result = result.multiply(val);
+ times -= 1;
+ }
+ val = val.multiply(val);
+ times /= 2;
+ }
+
+ if (sign == -1) {
+ result = BigDecimal.ONE.divide(result);
+ }
+
+ return new RubyBigDecimal(getRuntime(),result).setResult();
+ }
+
+ public IRubyObject add(IRubyObject[] args) {
+ RubyBigDecimal val = getVpValue(args[0],false);
+ if(val == null) {
+ return callCoerced("+",args[0]);
+ }
+ return new RubyBigDecimal(getRuntime(),value.add(val.value)).setResult();
+ }
+
+ public IRubyObject sub(IRubyObject[] args) {
+ RubyBigDecimal val = getVpValue(args[0],false);
+ if(val == null) {
+ return callCoerced("-",args[0]);
+ }
+ return new RubyBigDecimal(getRuntime(),value.subtract(val.value)).setResult();
+ }
+
+ public IRubyObject div(IRubyObject[] args) {
+ int scale = 0;
+ if(Arity.checkArgumentCount(getRuntime(), args,1,2) == 2) {
+ scale = RubyNumeric.fix2int(args[1]);
+ }
+
+ RubyBigDecimal val = getVpValue(args[0],false);
+ if(val == null) {
+ return callCoerced("/",args[0]);
+ }
+
+ if(scale == 0) {
+ return new RubyBigDecimal(getRuntime(),value.divide(val.value,200,BigDecimal.ROUND_HALF_UP)).setResult();
+ } else {
+ return new RubyBigDecimal(getRuntime(),value.divide(val.value,200,BigDecimal.ROUND_HALF_UP)).setResult(scale);
+ }
+ }
+
+ private IRubyObject cmp(IRubyObject r, char op) {
+ int e = 0;
+ RubyBigDecimal rb = getVpValue(r,false);
+ if(rb == null) {
+ IRubyObject ee = callCoerced("<=>",r);
+ if(ee.isNil()) {
+ return getRuntime().getNil();
+ }
+ e = RubyNumeric.fix2int(ee);
+ } else {
+ e = value.compareTo(rb.value);
+ }
+ switch(op) {
+ case '*': return getRuntime().newFixnum(e);
+ case '=': return (e==0)?getRuntime().getTrue():getRuntime().getFalse();
+ case '!': return (e!=0)?getRuntime().getTrue():getRuntime().getFalse();
+ case 'G': return (e>=0)?getRuntime().getTrue():getRuntime().getFalse();
+ case '>': return (e> 0)?getRuntime().getTrue():getRuntime().getFalse();
+ case 'L': return (e<=0)?getRuntime().getTrue():getRuntime().getFalse();
+ case '<': return (e< 0)?getRuntime().getTrue():getRuntime().getFalse();
+ }
+ return getRuntime().getNil();
+ }
+
+ public IRubyObject spaceship(IRubyObject arg) {
+ return cmp(arg,'*');
+ }
+
+ public IRubyObject eql_p(IRubyObject arg) {
+ return cmp(arg,'=');
+ }
+
+ public IRubyObject ne(IRubyObject arg) {
+ return cmp(arg,'!');
+ }
+
+ public IRubyObject lt(IRubyObject arg) {
+ return cmp(arg,'<');
+ }
+
+ public IRubyObject le(IRubyObject arg) {
+ return cmp(arg,'L');
+ }
+
+ public IRubyObject gt(IRubyObject arg) {
+ return cmp(arg,'>');
+ }
+
+ public IRubyObject ge(IRubyObject arg) {
+ return cmp(arg,'G');
+ }
+
+ public IRubyObject abs() {
+ return new RubyBigDecimal(getRuntime(),value.abs()).setResult();
+ }
+
+ public IRubyObject ceil(IRubyObject arg) {
+ System.err.println("unimplemented: ceil");
+ // TODO: implement correctly
+ return this;
+ }
+
+ public IRubyObject coerce(IRubyObject other) {
+ IRubyObject obj;
+ if(other instanceof RubyFloat) {
+ obj = getRuntime().newArray(other,to_f());
+ } else {
+ obj = getRuntime().newArray(getVpValue(other, true),this);
+ }
+ return obj;
+ }
+
+ public double getDoubleValue() { return value.doubleValue(); }
+ public long getLongValue() { return value.longValue(); }
+
+ public RubyNumeric multiplyWith(RubyInteger value) {
+ return (RubyNumeric)mult(new IRubyObject[]{value});
+ }
+
+ public RubyNumeric multiplyWith(RubyFloat value) {
+ return (RubyNumeric)mult(new IRubyObject[]{value});
+ }
+
+ public RubyNumeric multiplyWith(RubyBignum value) {
+ return (RubyNumeric)mult(new IRubyObject[]{value});
+ }
+
+ public IRubyObject divmod(IRubyObject arg) {
+ System.err.println("unimplemented: divmod");
+ // TODO: implement
+ return getRuntime().getNil();
+ }
+
+ public IRubyObject exponent() {
+ return getRuntime().newFixnum(exp());
+ }
+
+ private int exp() {
+ return value.abs().unscaledValue().toString().length() - value.abs().scale();
+ }
+
+ public IRubyObject finite_p() {
+ System.err.println("unimplemented: finite?");
+ // TODO: implement correctly
+ return getRuntime().getTrue();
+ }
+
+ public IRubyObject fix() {
+ System.err.println("unimplemented: fix");
+ // TODO: implement correctly
+ return this;
+ }
+
+ public IRubyObject floor(IRubyObject arg) {
+ System.err.println("unimplemented: floor");
+ // TODO: implement correctly
+ return this;
+ }
+
+ public IRubyObject frac() {
+ System.err.println("unimplemented: frac");
+ // TODO: implement correctly
+ return this;
+ }
+
+ public IRubyObject infinite_p() {
+ System.err.println("unimplemented: infinite?");
+ // TODO: implement correctly
+ return getRuntime().getFalse();
+ }
+
+ public IRubyObject inspect() {
+ StringBuffer val = new StringBuffer("#<BigDecimal:").append(Integer.toHexString(System.identityHashCode(this))).append(",");
+ val.append("'").append(this.callMethod(getRuntime().getCurrentContext(), MethodIndex.TO_S, "to_s")).append("'").append(",");
+ int len = value.abs().unscaledValue().toString().length();
+ int pow = len/4;
+ val.append(len).append("(").append((pow+1)*4).append(")").append(">");
+ return getRuntime().newString(val.toString());
+ }
+
+ public IRubyObject nan_p() {
+ System.err.println("unimplemented: nan?");
+ // TODO: implement correctly
+ return getRuntime().getFalse();
+ }
+
+ public IRubyObject nonzero_p() {
+ return value.signum() != 0 ? getRuntime().getTrue() : getRuntime().getFalse();
+ }
+
+ public IRubyObject precs() {
+ System.err.println("unimplemented: precs");
+ // TODO: implement
+ return getRuntime().getNil();
+ }
+
+ public IRubyObject remainder(IRubyObject arg) {
+ System.err.println("unimplemented: remainder");
+ // TODO: implement
+ return this;
+ }
+
+ public IRubyObject round(IRubyObject[] args) {
+ int scale = args.length > 0 ? num2int(args[0]) : 0;
+ int mode = (args.length > 1) ? javaRoundingModeFromRubyRoundingMode(args[1]) : BigDecimal.ROUND_HALF_UP;
+ // JRUBY-914: Java 1.4 BigDecimal does not allow a negative scale, so we have to simulate it
+ if (scale < 0) {
+ // shift the decimal point just to the right of the digit to be rounded to (divide by 10**(abs(scale)))
+ // -1 -> 10's digit, -2 -> 100's digit, etc.
+ BigDecimal normalized = value.movePointRight(scale);
+ // ...round to that digit
+ BigDecimal rounded = normalized.setScale(0,mode);
+ // ...and shift the result back to the left (multiply by 10**(abs(scale)))
+ return new RubyBigDecimal(getRuntime(), rounded.movePointLeft(scale));
+ } else {
+ return new RubyBigDecimal(getRuntime(), value.setScale(scale, mode));
+ }
+ }
+
+ //this relies on the Ruby rounding enumerations == Java ones, which they (currently) all are
+ private int javaRoundingModeFromRubyRoundingMode(IRubyObject arg) {
+ return num2int(arg);
+ }
+
+ public IRubyObject sign() {
+ System.err.println("unimplemented: sign");
+ // TODO: implement correctly
+ return getRuntime().newFixnum(value.signum());
+ }
+
+ public IRubyObject split() {
+ System.err.println("unimplemented: split");
+ // TODO: implement
+ return getRuntime().getNil();
+ }
+
+ public IRubyObject sqrt(IRubyObject[] args) {
+ System.err.println("unimplemented: sqrt");
+ // TODO: implement correctly
+ return new RubyBigDecimal(getRuntime(),new BigDecimal(Math.sqrt(value.doubleValue()))).setResult();
+ }
+
+ public IRubyObject to_f() {
+ return RubyFloat.newFloat(getRuntime(),value.doubleValue());
+ }
+
+ public IRubyObject to_i() {
+ return RubyNumeric.int2fix(getRuntime(),value.longValue());
+ }
+
+ public IRubyObject to_int() {
+ // TODO: implement to handle infinity and stuff
+ return RubyNumeric.int2fix(getRuntime(),value.longValue());
+ }
+
+ private String removeTrailingZeroes(String in) {
+ while(in.length() > 0 && in.charAt(in.length()-1)=='0') {
+ in = in.substring(0,in.length()-1);
+ }
+ return in;
+ }
+
+ private String toSpecialString(BigDecimal abs) {
+ if (abs.compareTo(BigDecimal.valueOf(0))== 0) {
+ return "0.0";
+ }
+ //TODO: match the MRI code below!
+ //TODO: refactor the overly-long branches in to_s so we can reuse the sign processing here
+ return null;
+// if(VpIsNaN(a)) {
+// sprintf(psz,SZ_NaN);
+// return 1;
+// }
+//
+// if(VpIsPosInf(a)) {
+// if(fPlus==1) {
+// *psz++ = ' ';
+// } else if(fPlus==2) {
+// *psz++ = '+';
+// }
+// sprintf(psz,SZ_INF);
+// return 1;
+// }
+// if(VpIsNegInf(a)) {
+// sprintf(psz,SZ_NINF);
+// return 1;
+// }
+// if(VpIsZero(a)) {
+// if(VpIsPosZero(a)) {
+// if(fPlus==1) sprintf(psz, " 0.0");
+// else if(fPlus==2) sprintf(psz, "+0.0");
+// else sprintf(psz, "0.0");
+// } else sprintf(psz, "-0.0");
+// return 1;
+// }
+// return 0;
+
+ }
+
+ public IRubyObject to_s(IRubyObject[] args) {
+ boolean engineering = true;
+ boolean pos_sign = false;
+ boolean pos_space = false;
+ int groups = 0;
+
+ if(args.length != 0 && !args[0].isNil()) {
+ String format = args[0].toString();
+ int start = 0;
+ int end = format.length();
+ if(format.length() > 0 && format.charAt(0) == '+') {
+ pos_sign = true;
+ start++;
+ } else if(format.length() > 0 && format.charAt(0) == ' ') {
+ pos_sign = true;
+ pos_space = true;
+ start++;
+ }
+ if(format.length() > 0 && format.charAt(format.length()-1) == 'F') {
+ engineering = false;
+ end--;
+ } else if(format.length() > 0 && format.charAt(format.length()-1) == 'E') {
+ engineering = true;
+ end--;
+ }
+ String nums = format.substring(start,end);
+ if(nums.length()>0) {
+ groups = Integer.parseInt(nums);
+ }
+ }
+
+ String out = null;
+ BigDecimal abs = value.abs();
+ String unscaled = abs.unscaledValue().toString();
+
+ //not beautiful, but parallel to MRI's VpToSpecialString
+ if (null != (out = toSpecialString(abs))) {
+ return getRuntime().newString(out);
+ }
+ if(engineering) {
+ int exponent = exp();
+ int signum = value.signum();
+ StringBuffer build = new StringBuffer();
+ build.append(signum == -1 ? "-" : (signum == 1 ? (pos_sign ? (pos_space ? " " : "+" ) : "") : ""));
+ build.append("0.");
+ if(0 == groups) {
+ String s = removeTrailingZeroes(unscaled);
+ if("".equals(s)) {
+ build.append("0");
+ } else {
+ build.append(s);
+ }
+ } else {
+ int index = 0;
+ String sep = "";
+ while(index < unscaled.length()) {
+ int next = index+groups;
+ if(next > unscaled.length()) {
+ next = unscaled.length();
+ }
+ build.append(sep).append(unscaled.substring(index,next));
+ sep = " ";
+ index += groups;
+ }
+ }
+ build.append("E").append(exponent);
+ out = build.toString();
+ } else {
+ int ix = abs.toString().indexOf('.');
+ String whole = unscaled;
+ String after = null;
+ if(ix != -1) {
+ whole = unscaled.substring(0,ix);
+ after = unscaled.substring(ix);
+ }
+ int signum = value.signum();
+ StringBuffer build = new StringBuffer();
+ build.append(signum == -1 ? "-" : (signum == 1 ? (pos_sign ? (pos_space ? " " : "+" ) : "") : ""));
+ if(0 == groups) {
+ build.append(whole);
+ if(null != after) {
+ build.append(".").append(after);
+ }
+ } else {
+ int index = 0;
+ String sep = "";
+ while(index < whole.length()) {
+ int next = index+groups;
+ if(next > whole.length()) {
+ next = whole.length();
+ }
+ build.append(sep).append(whole.substring(index,next));
+ sep = " ";
+ index += groups;
+ }
+ if(null != after) {
+ System.out.println("AFTER: " + after);
+ build.append(".");
+ index = 0;
+ sep = "";
+ while(index < after.length()) {
+ int next = index+groups;
+ if(next > after.length()) {
+ next = after.length();
+ }
+ build.append(sep).append(after.substring(index,next));
+ sep = " ";
+ index += groups;
+ }
+ }
+ }
+ out = build.toString();
+ }
+
+ return getRuntime().newString(out);
+ }
+
+ public IRubyObject truncate(IRubyObject[] args) {
+ System.err.println("unimplemented: truncate");
+ // TODO: implement
+ return this;
+ }
+
+ public IRubyObject zero_p() {
+ return value.signum() == 0 ? getRuntime().getTrue() : getRuntime().getFalse();
+ }
+}// RubyBigdecimal
View
5 compat/src/org/jruby/RubyBignum.java
@@ -50,8 +50,9 @@
*/
public class RubyBignum extends RubyInteger {
public static RubyClass createBignumClass(Ruby runtime) {
- RubyClass bignum = runtime.defineClass("Bignum", runtime.getClass("Integer"),
+ RubyClass bignum = runtime.defineClass("Bignum", runtime.getInteger(),
ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
+ runtime.setBignum(bignum);
bignum.index = ClassIndex.BIGNUM;
CallbackFactory callbackFactory = runtime.callbackFactory(RubyBignum.class);
@@ -98,7 +99,7 @@ public static RubyClass createBignumClass(Ruby runtime) {
private final BigInteger value;
public RubyBignum(Ruby runtime, BigInteger value) {
- super(runtime, runtime.getClass("Bignum"));
+ super(runtime, runtime.getBignum());
this.value = value;
}
View
9 compat/src/org/jruby/RubyBinding.java
@@ -64,6 +64,7 @@ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
public static RubyClass createBindingClass(Ruby runtime) {
RubyClass bindingClass = runtime.defineClass("Binding", runtime.getObject(), BINDING_ALLOCATOR);
+ runtime.setBinding(bindingClass);
CallbackFactory callbackFactory = runtime.callbackFactory(RubyBinding.class);
bindingClass.getMetaClass().defineMethod("of_caller", callbackFactory.getSingletonMethod("of_caller"));
@@ -78,7 +79,7 @@ public Block getBlock() {
// Proc class
public static RubyBinding newBinding(Ruby runtime, Block block) {
- return new RubyBinding(runtime, runtime.getClass("Binding"), block);
+ return new RubyBinding(runtime, runtime.getBinding(), block);
}
public static RubyBinding newBinding(Ruby runtime) {
@@ -88,7 +89,7 @@ public static RubyBinding newBinding(Ruby runtime) {
Frame frame = context.getCurrentFrame();
Block bindingBlock = Block.createBinding(frame, context.getCurrentScope());
- return new RubyBinding(runtime, runtime.getClass("Binding"), bindingBlock);
+ return new RubyBinding(runtime, runtime.getBinding(), bindingBlock);
}
/**
@@ -119,7 +120,7 @@ public static RubyBinding newBindingForEval(Ruby runtime) {
Block bindingBlock = Block.createBinding(previousFrame, context.getCurrentScope());
- return new RubyBinding(runtime, runtime.getClass("Binding"), bindingBlock);
+ return new RubyBinding(runtime, runtime.getBinding(), bindingBlock);
}
public static RubyBinding newBindingOfCaller(Ruby runtime) {
@@ -129,7 +130,7 @@ public static RubyBinding newBindingOfCaller(Ruby runtime) {
Frame frame = context.getPreviousFrame();
Block bindingBlock = Block.createBinding(frame, context.getPreviousScope());
- return new RubyBinding(runtime, runtime.getClass("Binding"), bindingBlock);
+ return new RubyBinding(runtime, runtime.getBinding(), bindingBlock);
}
public static IRubyObject of_caller(IRubyObject recv, Block aBlock) {
View
10 compat/src/org/jruby/RubyBoolean.java
@@ -45,7 +45,7 @@
private final Ruby runtime;
public RubyBoolean(Ruby runtime, boolean value) {
- super(runtime, (value ? runtime.getClass("TrueClass") : runtime.getClass("FalseClass")), // Don't initialize with class
+ super(runtime, (value ? runtime.getTrueClass() : runtime.getFalseClass()), // Don't initialize with class
false); // Don't put in object space
if (!value) flags = FALSE_F;
@@ -64,7 +64,11 @@ public Ruby getRuntime() {
public boolean isImmediate() {
return true;
}
-
+
+ public RubyClass getSingletonClass() {
+ return metaClass;
+ }
+
public Class getJavaClass() {
return Boolean.TYPE;
}
@@ -81,6 +85,7 @@ public RubyFixnum id() {
public static RubyClass createFalseClass(Ruby runtime) {
RubyClass falseClass = runtime.defineClass("FalseClass", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
+ runtime.setFalseClass(falseClass);
falseClass.index = ClassIndex.FALSE;
CallbackFactory fact = runtime.callbackFactory(RubyBoolean.class);
@@ -100,6 +105,7 @@ public static RubyClass createFalseClass(Ruby runtime) {
public static RubyClass createTrueClass(Ruby runtime) {
RubyClass trueClass = runtime.defineClass("TrueClass", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
+ runtime.setTrueClass(trueClass);
trueClass.index = ClassIndex.TRUE;
CallbackFactory fact = runtime.callbackFactory(RubyBoolean.class);
View
548 compat/src/org/jruby/RubyClass.java
@@ -36,12 +36,13 @@
import java.util.Collections;
import java.util.Map;
import java.util.Set;
+
+import org.jruby.runtime.Arity;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallbackFactory;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ObjectMarshal;
-import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.marshal.MarshalStream;
import org.jruby.runtime.marshal.UnmarshalStream;
@@ -53,194 +54,205 @@
*/
public class RubyClass extends RubyModule {
- private final Ruby runtime;
-
- // the default allocator
- private final ObjectAllocator allocator;
-
- private ObjectMarshal marshal;
-
- private Set subclasses;
+ public static void createClassClass(Ruby runtime, RubyClass classClass) {
+ classClass.index = ClassIndex.CLASS;
+ classClass.kindOf = new RubyModule.KindOf() {
+ public boolean isKindOf(IRubyObject obj, RubyModule type) {
+ return obj instanceof RubyClass;
+ }
+ };
+
+ CallbackFactory callbackFactory = runtime.callbackFactory(RubyClass.class);
+ classClass.defineFastMethod("allocate", callbackFactory.getFastMethod("allocate"));
+ classClass.defineMethod("new", callbackFactory.getOptMethod("newInstance"));
+ classClass.defineFastMethod("superclass", callbackFactory.getFastMethod("superclass"));
+ classClass.defineMethod("initialize", callbackFactory.getOptMethod("initialize"));
+ classClass.defineFastMethod("initialize_copy", callbackFactory.getFastMethod("initialize_copy", RubyKernel.IRUBY_OBJECT));
+ classClass.defineFastMethod("inherited", callbackFactory.getFastSingletonMethod("inherited", RubyKernel.IRUBY_OBJECT));
+ classClass.undefineMethod("module_function");
+ classClass.undefineMethod("append_features");
+ classClass.undefineMethod("extend_object");
+
+ // This is a non-standard method; have we decided to start extending Ruby?
+ //classClass.defineFastMethod("subclasses", callbackFactory.getFastOptMethod("subclasses"));
+
+ // FIXME: for some reason this dispatcher causes a VerifyError...
+ //classClass.dispatcher = callbackFactory.createDispatcher(classClass);
+ }
- private static final ObjectMarshal DEFAULT_OBJECT_MARSHAL = new ObjectMarshal() {
- public void marshalTo(Ruby runtime, Object obj, RubyClass type,
- MarshalStream marshalStream) throws IOException {
- IRubyObject object = (IRubyObject)obj;
-
- Map iVars = object.getInstanceVariablesSnapshot();
-
- marshalStream.dumpInstanceVars(iVars);
- }
-
- public Object unmarshalFrom(Ruby runtime, RubyClass type,
- UnmarshalStream unmarshalStream) throws IOException {
- IRubyObject result = type.allocate();
-
- unmarshalStream.registerLinkTarget(result);
-
- unmarshalStream.defaultInstanceVarsUnmarshal(result);
-
- return result;
+ public static final ObjectAllocator CLASS_ALLOCATOR = new ObjectAllocator() {
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
+ RubyClass clazz = new RubyClass(runtime);
+ clazz.allocator = ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR; // Class.allocate object is not allocatable before it is initialized
+ return clazz;
}
};
- /**
- * @mri rb_boot_class
- */
-
- /**
- * @mri rb_boot_class
- */
-
- /**
- * @mri rb_boot_class
- */
-
- /**
- * @mri rb_boot_class
- */
- protected RubyClass(RubyClass superClass, ObjectAllocator allocator) {
- this(superClass.getRuntime(), superClass.getRuntime().getClass("Class"), superClass, allocator, null, null);
-
- infectBy(superClass);
+ public ObjectAllocator getAllocator() {
+ return allocator;
}
- protected RubyClass(Ruby runtime, RubyClass superClass, ObjectAllocator allocator, boolean useObjectSpace) {
- this(runtime, null, superClass, allocator, null, null, useObjectSpace);
- }
-
- protected RubyClass(Ruby runtime, RubyClass superClass, ObjectAllocator allocator) {
- this(runtime, null, superClass, allocator, null, null);
+ public void setAllocator(ObjectAllocator allocator) {
+ this.allocator = allocator;
}
- protected RubyClass(Ruby runtime, RubyClass metaClass, RubyClass superClass, ObjectAllocator allocator) {
- this(runtime, metaClass, superClass, allocator, null, null);
+ public IRubyObject allocate() {
+ if (superClass == null) throw runtime.newTypeError("can't instantiate uninitialized class");
+ IRubyObject obj = allocator.allocate(runtime, this);
+ if (obj.getMetaClass().getRealClass() != getRealClass()) throw runtime.newTypeError("wrong instance allocation");
+ return obj;
+ }
+
+ public int getNativeTypeIndex() {
+ return ClassIndex.CLASS;
}
- protected RubyClass(Ruby runtime, RubyClass metaClass, RubyClass superClass, ObjectAllocator allocator, RubyModule parent, String name) {
- this (runtime, metaClass, superClass, allocator, parent, name, runtime.isObjectSpaceEnabled());
+ public boolean isModule() {
+ return false;
}
-
- protected RubyClass(Ruby runtime, RubyClass metaClass, RubyClass superClass, ObjectAllocator allocator, RubyModule parent, String name, boolean useObjectSpace) {
- super(runtime, metaClass, superClass, parent, name, useObjectSpace);
- this.allocator = allocator;
- this.runtime = runtime;
-
- // use parent's marshal, or default object marshal by default
- if (superClass != null) {
- this.marshal = superClass.getMarshal();
- if (this.isClass()) {
- superClass.addSubclass(this);
- }
- } else {
- this.marshal = DEFAULT_OBJECT_MARSHAL;
- }
+
+ public boolean isClass() {
+ return true;
}
-
- public synchronized void addSubclass(RubyClass subclass) {
- if (subclasses == null) subclasses = new WeakHashSet();
- subclasses.add(subclass);
+
+ public boolean isSingleton() {
+ return false;
}
-
- /**
+
+ /** boot_defclass
* Create an initial Object meta class before Module and Kernel dependencies have
* squirreled themselves together.
*
* @param runtime we need it
* @return a half-baked meta class for object
*/
- public static RubyClass createBootstrapMetaClass(Ruby runtime, String className,
- RubyClass superClass, ObjectAllocator allocator, RubyModule parent) {
- RubyClass objectClass = new RubyClass(runtime, null, superClass, allocator, parent, className);
-
- return objectClass;
- }
-
- public int getNativeTypeIndex() {
- return ClassIndex.CLASS;
+ public static RubyClass createBootstrapClass(Ruby runtime, String name, RubyClass superClass, ObjectAllocator allocator) {
+ RubyClass obj;
+
+ if (superClass == null ) { // boot the Object class
+ obj = new RubyClass(runtime);
+ obj.marshal = DEFAULT_OBJECT_MARSHAL;
+ obj.setConstant(name, obj);
+ } else { // boot the Module and Class classes
+ obj = new RubyClass(runtime, superClass);
+ runtime.getObject().setConstant(name, obj);
+ }
+ obj.setAllocator(allocator);
+ obj.setBaseName(name);
+ return obj;
}
- public final IRubyObject allocate() {
- return getAllocator().allocate(getRuntime(), this);
- }
-
- public final ObjectMarshal getMarshal() {
- return marshal;
- }
-
- public final void setMarshal(ObjectMarshal marshal) {
- this.marshal = marshal;
- }
-
- public final void marshal(Object obj, MarshalStream marshalStream) throws IOException {
- getMarshal().marshalTo(getRuntime(), obj, this, marshalStream);
+ private final Ruby runtime;
+ private ObjectAllocator allocator; // the default allocator
+ protected ObjectMarshal marshal;
+ private Set subclasses;
+
+ /** separate path for MetaClass and IncludedModuleWrapper construction
+ * (rb_class_boot version for MetaClasses)
+ * no marshal, allocator initialization and addSubclass(this) here!
+ */
+ protected RubyClass(Ruby runtime, RubyClass superClass, boolean objectSpace) {
+ super(runtime, runtime.getClassClass(), objectSpace);
+ this.runtime = runtime;
+ this.superClass = superClass; // this is the only case it might be null here (in MetaClass construction)
}
- public final Object unmarshal(UnmarshalStream unmarshalStream) throws IOException {
- return getMarshal().unmarshalFrom(getRuntime(), this, unmarshalStream);
+ /** used by CLASS_ALLOCATOR (any Class' class will be a Class!)
+ * also used to bootstrap Object class
+ */
+ protected RubyClass(Ruby runtime) {
+ super(runtime, runtime.getClassClass());
+ this.runtime = runtime;
+ index = ClassIndex.CLASS;
}
- public static RubyClass newClassClass(Ruby runtime, RubyClass moduleClass) {
- ObjectAllocator defaultAllocator = new ObjectAllocator() {
- public IRubyObject allocate(Ruby runtime, RubyClass klass) {
- IRubyObject instance = new RubyObject(runtime, klass);
- instance.setMetaClass(klass);
-
- return instance;
- }
- };
-
- RubyClass classClass = new RubyClass(
- runtime,
- null /* FIXME: should be something else? */,
- moduleClass,
- defaultAllocator,
- null,
- "Class");
-
- classClass.index = ClassIndex.CLASS;
+ /** rb_class_boot (for plain Classes)
+ * also used to bootstrap Module and Class classes
+ */
+ protected RubyClass(Ruby runtime, RubyClass superClazz) {
+ this(runtime);
+ superClass = superClazz;
+ marshal = superClazz.marshal; // use parent's marshal
+ superClazz.addSubclass(this);
- return classClass;
+ infectBy(superClass);
}
-
- /* (non-Javadoc)
- * @see org.jruby.RubyObject#getRuntime()
- */
- public Ruby getRuntime() {
- return runtime;
- }
- public boolean isModule() {
- return false;
+ /** rb_class_new
+ *
+ */
+ public static RubyClass newClass(Ruby runtime, RubyClass superClass) {
+ if (superClass == runtime.getClassClass()) throw runtime.newTypeError("can't make subclass of Class");
+ if (superClass.isSingleton()) throw runtime.newTypeError("can't make subclass of virtual class");
+ return new RubyClass(runtime, superClass);
}
- public boolean isClass() {
- return true;
+ /** rb_class_new/rb_define_class_id/rb_name_class/rb_set_class_path
+ *
+ */
+ public static RubyClass newClass(Ruby runtime, RubyClass superClass, String name, ObjectAllocator allocator, RubyModule parent, boolean setParent) {
+ RubyClass clazz = newClass(runtime, superClass);
+ clazz.setBaseName(name);
+ clazz.setAllocator(allocator);
+ clazz.makeMetaClass(superClass.getMetaClass());
+ if (setParent) clazz.setParent(parent);
+ parent.setConstant(name, clazz);
+ clazz.inherit(superClass);
+ return clazz;
}