diff --git a/core-lib b/core-lib index c67b309..12ddd9b 160000 --- a/core-lib +++ b/core-lib @@ -1 +1 @@ -Subproject commit c67b309fdb6c41ec0c31a414f86dd3cb53cabb32 +Subproject commit 12ddd9b8544de968c0d437c9dbdbe2f589872c4a diff --git a/integration-tests.yml b/integration-tests.yml index 717ce12..db581d8 100644 --- a/integration-tests.yml +++ b/integration-tests.yml @@ -1,5 +1,6 @@ known_failures: [] +version: 4 failing_as_unspecified: - Tests/arbint_double_div_err.som @@ -9,6 +10,7 @@ failing_as_unspecified: - Tests/array_at_idx2_err.som - Tests/array_at_idx_err.som - Tests/array_at_negative_idx_err.som + - Tests/array_at_put_idx_err.som - Tests/array_at_put_idx0_err.som - Tests/array_at_put_idx2_err.som - Tests/call2.som @@ -21,7 +23,6 @@ failing_as_unspecified: # I think IEEE allows for infinities here, and we probably want that - Tests/double3.som - - Tests/double4.som - Tests/double5.som - Tests/double6.som - Tests/double7.som @@ -30,16 +31,11 @@ failing_as_unspecified: - Tests/double11.som - Tests/double13.som - # Java seems to do some rounding in the transition, but it's also requiring bigints - - Tests/double_asinteger.som - - - Tests/double_double_div_err.som - Tests/double_double_div_zero_err1.som - Tests/double_double_div_zero_err2.som - Tests/double_double_div_zero_err3.som - Tests/double_double_div_zero_err4.som - - Tests/double_modulus.som - Tests/double_modulus_err.som - Tests/exit_double.som @@ -49,8 +45,6 @@ failing_as_unspecified: - Tests/fromstring_double_err.som - Tests/fromstring_err.som - - Tests/hashcode2.som - - Tests/inst_var_at_bad_idx.som - Tests/inst_var_at_put_bad_idx.som @@ -83,7 +77,6 @@ failing_as_unspecified: - Tests/int_double_div_err.som - Tests/int_double_div_zero_err.som - - Tests/int_modulus.som - Tests/int_modulus_err.som - Tests/load_string.som @@ -100,9 +93,7 @@ failing_as_unspecified: - Tests/perform_witharguments_wrong.som - Tests/remainder_zero.som - - Tests/round.som - - Tests/shift_right.som - Tests/shift_right_too_big.som - Tests/shift_right_type_err.som @@ -116,9 +107,12 @@ failing_as_unspecified: - Tests/test_literals_limit_2.som - Tests/unknown_field_write.som - # This should be specified so that the "set" of fields cannot be changed reflectively - # they obtained array can be changed, but it is expected to have no effect. - - Tests/mutate_fields.som + - Tests/parse_errors/duplicate_name_arg.som + - Tests/parse_errors/duplicate_name_arg_local.som + - Tests/parse_errors/duplicate_name_local.som + - Tests/parse_errors/duplicate_name_method.som + - Tests/parse_errors/instance_fields_overlap2.som + - Tests/unknown_field_write2.som unsupported: [] diff --git a/src/som/primitives/ClassPrimitives.java b/src/som/primitives/ClassPrimitives.java index 1879d6b..5e32d43 100644 --- a/src/som/primitives/ClassPrimitives.java +++ b/src/som/primitives/ClassPrimitives.java @@ -71,7 +71,7 @@ public void invoke(final Frame frame, final Interpreter interpreter) { @Override public void invoke(final Frame frame, final Interpreter interpreter) { SClass self = (SClass) frame.pop(); - frame.push(self.getInstanceFields()); + frame.push(self.getInstanceFields().copy(universe)); } }); diff --git a/src/som/primitives/DoublePrimitives.java b/src/som/primitives/DoublePrimitives.java index 2898e01..57baafb 100644 --- a/src/som/primitives/DoublePrimitives.java +++ b/src/som/primitives/DoublePrimitives.java @@ -133,8 +133,7 @@ public void invoke(final Frame frame, final Interpreter interpreter) { @Override public void invoke(final Frame frame, final Interpreter interpreter) { SDouble rcvr = (SDouble) frame.pop(); - long result = Math.round(rcvr.getEmbeddedDouble()); - frame.push(universe.newInteger(result)); + frame.push(rcvr.primRound(universe)); } }); diff --git a/src/som/primitives/IntegerPrimitives.java b/src/som/primitives/IntegerPrimitives.java index be37d1b..9fca1ca 100644 --- a/src/som/primitives/IntegerPrimitives.java +++ b/src/som/primitives/IntegerPrimitives.java @@ -219,9 +219,8 @@ public void invoke(final Frame frame, final Interpreter interpreter) { @Override public void invoke(final Frame frame, final Interpreter interpreter) { SInteger right = (SInteger) frame.pop(); - SInteger rcvr = (SInteger) frame.pop(); - frame.push( - universe.newInteger(rcvr.getEmbeddedInteger() >>> right.getEmbeddedInteger())); + SNumber rcvr = (SNumber) frame.pop(); + frame.push(rcvr.primShiftRight(right, universe)); } }); diff --git a/src/som/vmobjects/SArray.java b/src/som/vmobjects/SArray.java index bf836c7..92a7e6f 100644 --- a/src/som/vmobjects/SArray.java +++ b/src/som/vmobjects/SArray.java @@ -64,6 +64,12 @@ public SArray copyAndExtendWith(SAbstractObject value, final Universe universe) return result; } + public SArray copy(final Universe universe) { + SArray result = universe.newArray(getNumberOfIndexableFields()); + copyIndexableFieldsTo(result); + return result; + } + protected void copyIndexableFieldsTo(SArray destination) { // Copy all indexable fields from this array to the destination array for (int i = 0; i < getNumberOfIndexableFields(); i++) { diff --git a/src/som/vmobjects/SBigInteger.java b/src/som/vmobjects/SBigInteger.java index 423b8ca..b0ec5f4 100644 --- a/src/som/vmobjects/SBigInteger.java +++ b/src/som/vmobjects/SBigInteger.java @@ -64,14 +64,6 @@ public SNumber primAsDouble(final Universe universe) { return universe.newDouble(embeddedBiginteger.doubleValue()); } - private SNumber asSNumber(final BigInteger result, final Universe universe) { - if (result.bitLength() >= Long.SIZE) { - return universe.newBigInteger(result); - } else { - return universe.newInteger(result.longValue()); - } - } - private BigInteger asBigInteger(final SNumber right) { BigInteger r; if (right instanceof SInteger r1) { @@ -133,6 +125,10 @@ public SNumber primDoubleDivide(final SNumber right, final Universe universe) { @Override public SNumber primIntegerDivide(final SNumber right, final Universe universe) { + if (right instanceof SDouble d) { + return fitIntoInteger( + embeddedBiginteger.doubleValue() / d.getEmbeddedDouble(), universe); + } BigInteger r = asBigInteger(right); BigInteger result = embeddedBiginteger.divide(r); return asSNumber(result, universe); @@ -140,8 +136,11 @@ public SNumber primIntegerDivide(final SNumber right, final Universe universe) { @Override public SNumber primModulo(final SNumber right, final Universe universe) { + if (right instanceof SDouble d) { + return universe.newDouble(embeddedBiginteger.doubleValue() % d.getEmbeddedDouble()); + } BigInteger r = asBigInteger(right); - BigInteger result = embeddedBiginteger.mod(r); + BigInteger result = floorMod(embeddedBiginteger, r); return asSNumber(result, universe); } @@ -194,6 +193,12 @@ public SNumber primLeftShift(final SNumber right, final Universe universe) { return universe.newBigInteger(embeddedBiginteger.shiftLeft(r.intValue())); } + @Override + public SNumber primShiftRight(final SInteger right, final Universe universe) { + return asSNumber(embeddedBiginteger.shiftRight((int) right.getEmbeddedInteger()), + universe); + } + @Override public SNumber primBitXor(final SNumber right, final Universe universe) { BigInteger r = asBigInteger(right); diff --git a/src/som/vmobjects/SDouble.java b/src/som/vmobjects/SDouble.java index aec9044..b652512 100644 --- a/src/som/vmobjects/SDouble.java +++ b/src/som/vmobjects/SDouble.java @@ -26,9 +26,6 @@ import som.vm.Universe; -import java.math.BigDecimal; -import java.math.BigInteger; - public final class SDouble extends SNumber { @@ -43,6 +40,17 @@ public double getEmbeddedDouble() { return embeddedDouble; } + @Override + public int hashCode() { + return Double.hashCode(embeddedDouble); + } + + @Override + public boolean equals(final Object o) { + return o instanceof SDouble d + && Double.compare(embeddedDouble, d.embeddedDouble) == 0; + } + @Override public String toString() { return super.toString() + "(" + embeddedDouble + ")"; @@ -77,11 +85,14 @@ public SDouble primAsDouble(final Universe universe) { } public SNumber primAsInteger(final Universe universe) { - if (embeddedDouble > Long.MAX_VALUE || embeddedDouble < Long.MIN_VALUE) { - BigInteger bigInteger = BigDecimal.valueOf(embeddedDouble).toBigInteger(); - return universe.newBigInteger(bigInteger); + return fitIntoInteger(embeddedDouble, universe); + } + + public SNumber primRound(final Universe universe) { + if (embeddedDouble >= Long.MAX_VALUE || embeddedDouble < Long.MIN_VALUE) { + return fitIntoInteger(embeddedDouble, universe); } - return universe.newInteger((long) embeddedDouble); + return universe.newInteger(Math.round(embeddedDouble)); } @Override @@ -139,6 +150,11 @@ public SNumber primLeftShift(final SNumber right, final Universe universe) { throw new RuntimeException("Not supported for doubles"); } + @Override + public SNumber primShiftRight(final SInteger right, final Universe universe) { + throw new RuntimeException("Not supported for doubles"); + } + @Override public SObject primEqual(final SAbstractObject right, final Universe universe) { if (!(right instanceof SNumber)) { diff --git a/src/som/vmobjects/SInteger.java b/src/som/vmobjects/SInteger.java index 60826b0..b4bb69e 100644 --- a/src/som/vmobjects/SInteger.java +++ b/src/som/vmobjects/SInteger.java @@ -196,13 +196,9 @@ public SNumber primIntegerDivide(final SNumber right, final Universe universe) { @Override public SNumber primModulo(final SNumber right, final Universe universe) { if (right instanceof SBigInteger) { - // Note: modulo semantics of SOM differ from Java, with respect to - // negative operands, but BigInteger doesn't support a negative - // second operand, so, we should get an exception, which we can - // properly handle once an application actually needs it. - BigInteger result = BigInteger.valueOf(embeddedInteger).mod( + BigInteger result = floorMod(BigInteger.valueOf(embeddedInteger), ((SBigInteger) right).getEmbeddedBiginteger()); - return universe.newBigInteger(result); + return asSNumber(result, universe); } else if (right instanceof SDouble) { double result = embeddedInteger % ((SDouble) right).getEmbeddedDouble(); return universe.newDouble(result); @@ -264,6 +260,12 @@ public SNumber primLeftShift(final SNumber right, final Universe universe) { return universe.newInteger(result); } + @Override + public SNumber primShiftRight(final SInteger right, final Universe universe) { + return universe.newInteger( + embeddedInteger >>> right.getEmbeddedInteger()); + } + @Override public SObject primEqual(final SAbstractObject right, final Universe universe) { boolean result; diff --git a/src/som/vmobjects/SNumber.java b/src/som/vmobjects/SNumber.java index ee8084e..6b6f397 100644 --- a/src/som/vmobjects/SNumber.java +++ b/src/som/vmobjects/SNumber.java @@ -1,6 +1,7 @@ package som.vmobjects; import java.math.BigDecimal; +import java.math.BigInteger; import som.vm.Universe; @@ -30,6 +31,8 @@ public abstract class SNumber extends SAbstractObject { public abstract SNumber primLeftShift(SNumber right, Universe universe); + public abstract SNumber primShiftRight(SInteger right, Universe universe); + public abstract SObject primEqual(SAbstractObject right, Universe universe); public abstract SObject primLessThan(SNumber right, Universe universe); @@ -43,6 +46,29 @@ protected final SNumber intOrBigInt(final double value, final Universe universe) } } + protected static SNumber fitIntoInteger(final double value, final Universe universe) { + if (value >= Long.MAX_VALUE || value < Long.MIN_VALUE) { + return universe.newBigInteger(new BigDecimal(value).toBigInteger()); + } + return universe.newInteger((long) value); + } + + public static SNumber asSNumber(final BigInteger result, final Universe universe) { + if (result.bitLength() >= Long.SIZE) { + return universe.newBigInteger(result); + } else { + return universe.newInteger(result.longValue()); + } + } + + protected static BigInteger floorMod(final BigInteger left, final BigInteger right) { + BigInteger result = left.remainder(right); + if (result.signum() != 0 && result.signum() != right.signum()) { + result = result.add(right); + } + return result; + } + protected final SObject asSBoolean(final boolean result, final Universe universe) { if (result) { return universe.trueObject;