Merge Small_Integer and Big_Integer types (#7636)

Merge Small_Integer and Big_Integer types into a single Integer type
This commit is contained in:
Pavel Marek 2023-09-08 16:04:39 +02:00 committed by GitHub
parent 3c00cb400e
commit e0ee8fdda7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
65 changed files with 801 additions and 1215 deletions

View File

@ -945,6 +945,7 @@
- [Use `numpy` & co. from Enso!][7678]
- [Changed layout of local libraries directory, making it easier to reference
projects next to each other][7634]
- [Merge `Small_Integer` and `Big_Integer` types][7636]
[3227]: https://github.com/enso-org/enso/pull/3227
[3248]: https://github.com/enso-org/enso/pull/3248
@ -1082,6 +1083,7 @@
[7613]: https://github.com/enso-org/enso/pull/7613
[7678]: https://github.com/enso-org/enso/pull/7678
[7634]: https://github.com/enso-org/enso/pull/7634
[7636]: https://github.com/enso-org/enso/pull/7636
# Enso 2.0.0-alpha.18 (2021-10-12)

View File

@ -5092,7 +5092,7 @@ class RuntimeServerTest
Api.ExecutionFailed(
contextId,
Api.ExecutionResult.Diagnostic.error(
"Type error: expected `that` to be Number, but got Function.",
"Type error: expected `that` to be Integer, but got Function.",
Some(mainFile),
Some(model.Range(model.Position(11, 8), model.Position(11, 17))),
None,

View File

@ -187,7 +187,15 @@ class RuntimeVisualizationsTest
Api.ExpressionUpdate(
Main.idMainZ,
Some(ConstantsGen.INTEGER),
None,
Some(
Api.MethodCall(
Api.MethodPointer(
"Standard.Base.Data.Numbers",
"Standard.Base.Data.Numbers.Integer",
"+"
)
)
),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache,
typeChanged,
@ -209,7 +217,15 @@ class RuntimeVisualizationsTest
Api.ExpressionUpdate(
Main.idFooY,
Some(ConstantsGen.INTEGER),
None,
Some(
Api.MethodCall(
Api.MethodPointer(
"Standard.Base.Data.Numbers",
"Standard.Base.Data.Numbers.Integer",
"+"
)
)
),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache,
typeChanged,
@ -231,7 +247,15 @@ class RuntimeVisualizationsTest
Api.ExpressionUpdate(
Main.idFooZ,
Some(ConstantsGen.INTEGER),
None,
Some(
Api.MethodCall(
Api.MethodPointer(
"Standard.Base.Data.Numbers",
"Standard.Base.Data.Numbers.Integer",
"*"
)
)
),
Vector(Api.ProfilingInfo.ExecutionTime(0)),
fromCache,
typeChanged,
@ -973,12 +997,30 @@ class RuntimeVisualizationsTest
contextId,
context.Main.idFooY,
ConstantsGen.INTEGER,
methodCall = Some(
Api.MethodCall(
Api.MethodPointer(
"Standard.Base.Data.Numbers",
"Standard.Base.Data.Numbers.Integer",
"+"
)
)
),
typeChanged = false
),
TestMessages.update(
contextId,
context.Main.idFooZ,
ConstantsGen.INTEGER,
methodCall = Some(
Api.MethodCall(
Api.MethodPointer(
"Standard.Base.Data.Numbers",
"Standard.Base.Data.Numbers.Integer",
"*"
)
)
),
typeChanged = false
),
context.executionComplete(contextId)

View File

@ -85,7 +85,7 @@ public abstract class IsValueOfTypeNode extends Node {
@Specialization
boolean doLongCheck(Type expectedType, long payload) {
var numbers = EnsoContext.get(this).getBuiltins().number();
return checkParentTypes(numbers.getSmallInteger(), expectedType);
return checkParentTypes(numbers.getInteger(), expectedType);
}
@Specialization
@ -97,7 +97,7 @@ public abstract class IsValueOfTypeNode extends Node {
@Specialization
boolean doBigIntegerCheck(Type expectedType, EnsoBigInteger value) {
var numbers = EnsoContext.get(this).getBuiltins().number();
return checkParentTypes(numbers.getBigInteger(), expectedType);
return checkParentTypes(numbers.getInteger(), expectedType);
}
@Specialization

View File

@ -1,12 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number;
import org.enso.interpreter.dsl.BuiltinType;
import org.enso.interpreter.node.expression.builtin.Builtin;
@BuiltinType
public class BigInteger extends Builtin {
@Override
protected Class<? extends Builtin> getSuperType() {
return Integer.class;
}
}

View File

@ -1,12 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number;
import org.enso.interpreter.dsl.BuiltinType;
import org.enso.interpreter.node.expression.builtin.Builtin;
@BuiltinType
public class SmallInteger extends Builtin {
@Override
protected Class<? extends Builtin> getSuperType() {
return Integer.class;
}
}

View File

@ -1,16 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "abs", description = "Big integer absolute value.")
public class AbsNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
Object execute(EnsoBigInteger self) {
return toEnsoNumberNode.execute(BigIntegerOps.abs(self.getValue()));
}
}

View File

@ -1,45 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "+", description = "Big integer addition.")
public abstract class AddNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(EnsoBigInteger self, Object that);
static AddNode build() {
return AddNodeGen.create();
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.add(self.getValue(), that));
}
@Specialization
Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.add(self.getValue(), that.getValue()));
}
@Specialization
double doDouble(EnsoBigInteger self, double that) {
return BigIntegerOps.toDouble(self.getValue()) + that;
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
}
}

View File

@ -1,33 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "bit_not", description = "Bitwise negation.")
public abstract class BitNotNode extends Node {
abstract Object execute(Object self);
static BitNotNode build() {
return BitNotNodeGen.create();
}
@Specialization
@CompilerDirectives.TruffleBoundary
EnsoBigInteger doBigInteger(EnsoBigInteger self) {
return new EnsoBigInteger(self.getValue().not());
}
@Fallback
Object doOther(Object self) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, self, "this"), this);
}
}

View File

@ -1,80 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NeverDefault;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.CountingConditionProfile;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@ImportStatic(BigIntegerOps.class)
@BuiltinMethod(type = "Big_Integer", name = "bit_shift", description = "Bitwise shift.")
public abstract class BitShiftNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
private final CountingConditionProfile fitsInIntProfileLeftShift =
CountingConditionProfile.create();
private final CountingConditionProfile fitsInIntProfileRightShift =
CountingConditionProfile.create();
abstract Object execute(Object self, Object that);
@NeverDefault
static BitShiftNode build() {
return BitShiftNodeGen.create();
}
@Specialization(guards = {"that >= 0", "fitsInInt(that)"})
EnsoBigInteger doBigIntShiftLeft(EnsoBigInteger self, long that) {
return new EnsoBigInteger(BigIntegerOps.bitShiftLeft(self.getValue(), (int) that));
}
@Specialization(guards = "that >= 0", replaces = "doBigIntShiftLeft")
Object doBigIntShiftLeftExplicit(EnsoBigInteger self, long that) {
if (fitsInIntProfileLeftShift.profile(BigIntegerOps.fitsInInt(that))) {
return doBigIntShiftLeft(self, that);
} else {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getShiftAmountTooLargeError(), this);
}
}
@Specialization(guards = {"that < 0", "fitsInInt(that)"})
Object doBigIntShiftRight(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitShiftRight(self.getValue(), (int) -that));
}
@Specialization(guards = "that < 0", replaces = "doBigIntShiftRight")
Object doBigIntShiftRightExplicit(EnsoBigInteger self, long that) {
if (fitsInIntProfileRightShift.profile(BigIntegerOps.fitsInInt(that))) {
return doBigIntShiftRight(self, -that);
} else {
return BigIntegerOps.nonNegative(self.getValue()) ? 0L : -1L;
}
}
@Specialization
Object doBigIntThat(EnsoBigInteger self, EnsoBigInteger that) {
if (!BigIntegerOps.nonNegative(that.getValue())) {
return BigIntegerOps.nonNegative(self.getValue()) ? 0L : -1L;
} else {
// Note [Well-Formed BigIntegers]
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getShiftAmountTooLargeError(), this);
}
}
@Fallback
Object doOther(Object self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
}
}

View File

@ -1,12 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "ceil", description = "Big integer ceiling.")
public class CeilNode extends Node {
Object execute(EnsoBigInteger self) {
return self;
}
}

View File

@ -1,12 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "floor", description = "Big integer floor.")
public class FloorNode extends Node {
Object execute(EnsoBigInteger self) {
return self;
}
}

View File

@ -1,54 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "%", description = "Big integer modulo division.")
public abstract class ModNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(EnsoBigInteger self, Object that);
static ModNode build() {
return ModNodeGen.create();
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
try {
return toEnsoNumberNode.execute(BigIntegerOps.modulo(self.getValue(), that));
} catch (ArithmeticException e) {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getDivideByZeroError(), this);
}
}
@Specialization
double doDouble(EnsoBigInteger self, double that) {
// No need to trap, as floating-point modulo returns NaN for division by zero instead of
// throwing.
return BigIntegerOps.toDouble(self.getValue()) % that;
}
@Specialization
Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) {
// No need to trap, as 0 is never represented as an EnsoBigInteger.
return toEnsoNumberNode.execute(BigIntegerOps.modulo(self.getValue(), that.getValue()));
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
}
}

View File

@ -1,45 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "*", description = "Big integer multiplication.")
public abstract class MultiplyNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract Object execute(EnsoBigInteger self, Object that);
public static MultiplyNode build() {
return MultiplyNodeGen.create();
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.multiply(self.getValue(), that));
}
@Specialization
Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.multiply(self.getValue(), that.getValue()));
}
@Specialization
double doDouble(EnsoBigInteger self, double that) {
return BigIntegerOps.toDouble(self.getValue()) * that;
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
}
}

View File

@ -1,16 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "negate", description = "Big integer negation.")
public class NegateNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
Object execute(EnsoBigInteger self) {
return toEnsoNumberNode.execute(BigIntegerOps.negate(self.getValue()));
}
}

View File

@ -1,45 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "-", description = "Big integer subtraction.")
public abstract class SubtractNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(EnsoBigInteger self, Object that);
static SubtractNode build() {
return SubtractNodeGen.create();
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.subtract(self.getValue(), that));
}
@Specialization
Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.subtract(self.getValue(), that.getValue()));
}
@Specialization
double doDouble(EnsoBigInteger self, double that) {
return BigIntegerOps.toDouble(self.getValue()) - that;
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
}
}

View File

@ -1,16 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(
type = "Big_Integer",
name = "to_decimal",
description = "Conversion of integers to decimals")
public class ToDecimalNode extends Node {
double execute(EnsoBigInteger self) {
return BigIntegerOps.toDouble(self.getValue());
}
}

View File

@ -1,23 +1,25 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "abs", description = "Absolute value of a number")
@BuiltinMethod(type = "Integer", name = "abs", description = "Absolute value of a number")
public abstract class AbsNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
static AbsNode build() {
public static AbsNode build() {
return AbsNodeGen.create();
}
abstract Object execute(long self);
public abstract Object execute(Object self);
@Specialization(rewriteOn = ArithmeticException.class)
long doNormal(long self) {
long doLong(long self) {
if (self < 0) {
return Math.negateExact(self);
} else {
@ -25,8 +27,18 @@ public abstract class AbsNode extends Node {
}
}
@Specialization
Object doOverflow(long self) {
@Specialization(replaces = "doLong")
Object doLongOverflow(long self) {
return toEnsoNumberNode.execute(BigIntegerOps.abs(self));
}
@Specialization
Object doBigInt(EnsoBigInteger self) {
return toEnsoNumberNode.execute(BigIntegerOps.abs(self.getValue()));
}
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -0,0 +1,62 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = "+", description = "Addition of numbers.")
public abstract class AddNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract Object execute(Object self, Object that);
public static AddNode build() {
return AddNodeGen.create();
}
@Specialization(rewriteOn = ArithmeticException.class)
long doLong(long self, long that) {
return Math.addExact(self, that);
}
@Specialization(replaces = "doLong")
Object doOverflow(long self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.add(self, that));
}
@Specialization
Object doDouble(long self, double that) {
return self + that;
}
@TruffleBoundary
@Specialization
Object doBigIntegers(EnsoBigInteger self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(self.asBigInteger().add(that.asBigInteger()));
}
@Specialization
Object doLongBigInteger(long self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.add(that.getValue(), self));
}
@Specialization
Object doBigIntegerLong(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.add(self.getValue(), that));
}
@Specialization
double doBigIntDouble(EnsoBigInteger self, double that) {
return self.asDouble() + that;
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@ -6,35 +6,40 @@ import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "bit_and", description = "Bitwise and.")
@BuiltinMethod(type = "Integer", name = "bit_and", description = "Bitwise and.")
public abstract class BitAndNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(Object self, Object that);
public abstract Object execute(Object self, Object that);
static BitAndNode build() {
public static BitAndNode build() {
return BitAndNodeGen.create();
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
long doLongLong(long self, long that) {
return self & that;
}
@Specialization
Object doLongBigInt(long self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitAnd(self, that.getValue()));
}
@Specialization
Object doBigIntLong(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitAnd(self.getValue(), that));
}
@Specialization
Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) {
Object doBigIntBigInt(EnsoBigInteger self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitAnd(self.getValue(), that.getValue()));
}
@Fallback
Object doOther(Object self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -0,0 +1,33 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = "bit_not", description = "Bitwise negation.")
public abstract class BitNotNode extends Node {
abstract Object execute(Object self);
static BitNotNode build() {
return BitNotNodeGen.create();
}
@Specialization
long doLong(long self) {
return ~self;
}
@Specialization
@TruffleBoundary
EnsoBigInteger doBigInteger(EnsoBigInteger self) {
return new EnsoBigInteger(self.getValue().not());
}
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@ -6,12 +6,9 @@ import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "bit_or", description = "Bitwise or.")
@BuiltinMethod(type = "Integer", name = "bit_or", description = "Bitwise or.")
public abstract class BitOrNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
@ -21,6 +18,16 @@ public abstract class BitOrNode extends Node {
return BitOrNodeGen.create();
}
@Specialization
long doLong(long self, long that) {
return self | that;
}
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitOr(self, that.getValue()));
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitOr(self.getValue(), that));
@ -33,8 +40,6 @@ public abstract class BitOrNode extends Node {
@Fallback
Object doOther(Object self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -1,5 +1,7 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Exclusive;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NeverDefault;
@ -10,13 +12,11 @@ import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@ImportStatic(BigIntegerOps.class)
@BuiltinMethod(type = "Small_Integer", name = "bit_shift", description = "Bitwise shift.")
@BuiltinMethod(type = "Integer", name = "bit_shift", description = "Bitwise shift.")
public abstract class BitShiftNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
private final CountingConditionProfile canShiftLeftInLongProfile =
@ -26,7 +26,7 @@ public abstract class BitShiftNode extends Node {
private final CountingConditionProfile rightShiftExceedsLongWidth =
CountingConditionProfile.create();
abstract Object execute(long self, Object that);
abstract Object execute(Object self, Object that);
@NeverDefault
static BitShiftNode build() {
@ -79,11 +79,54 @@ public abstract class BitShiftNode extends Node {
}
}
@Specialization(guards = {"that >= 0", "fitsInInt(that)"})
EnsoBigInteger doBigIntShiftLeft(EnsoBigInteger self, long that) {
return new EnsoBigInteger(BigIntegerOps.bitShiftLeft(self.getValue(), (int) that));
}
@Specialization(guards = "that >= 0", replaces = "doBigIntShiftLeft")
Object doBigIntShiftLeftExplicit(
EnsoBigInteger self,
long that,
@Exclusive @Cached CountingConditionProfile fitsInIntProfileLeftShift) {
if (fitsInIntProfileLeftShift.profile(BigIntegerOps.fitsInInt(that))) {
return doBigIntShiftLeft(self, that);
} else {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getShiftAmountTooLargeError(), this);
}
}
@Specialization(guards = {"that < 0", "fitsInInt(that)"})
Object doBigIntShiftRight(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitShiftRight(self.getValue(), (int) -that));
}
@Specialization(guards = "that < 0", replaces = "doBigIntShiftRight")
Object doBigIntShiftRightExplicit(
EnsoBigInteger self,
long that,
@Exclusive @Cached CountingConditionProfile fitsInIntProfileRightShift) {
if (fitsInIntProfileRightShift.profile(BigIntegerOps.fitsInInt(that))) {
return doBigIntShiftRight(self, -that);
} else {
return BigIntegerOps.nonNegative(self.getValue()) ? 0L : -1L;
}
}
@Specialization
Object doBigIntThat(EnsoBigInteger self, EnsoBigInteger that) {
if (!BigIntegerOps.nonNegative(that.getValue())) {
return BigIntegerOps.nonNegative(self.getValue()) ? 0L : -1L;
} else {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getShiftAmountTooLargeError(), this);
}
}
@Fallback
Object doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
boolean hasFreeBitsLeftShift(long number, long shift) {

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Shared;
@ -7,19 +7,30 @@ import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "bit_shift_r", description = "Bitwise right-shift.")
@BuiltinMethod(type = "Integer", name = "bit_shift_r", description = "Bitwise right-shift.")
public abstract class BitShiftRightNode extends Node {
abstract Object execute(EnsoBigInteger self, Object that);
abstract Object execute(Object self, Object that);
static BitShiftRightNode build() {
return BitShiftRightNodeGen.create();
}
@Specialization
Object doBigInteger(
long self, long that, @Shared("bitShiftNode") @Cached("build()") BitShiftNode bitShiftNode) {
return bitShiftNode.execute(self, -1L * that);
}
@Specialization
Object doBigInteger(
long self,
EnsoBigInteger that,
@Shared("bitShiftNode") @Cached("build()") BitShiftNode bitShiftNode) {
return bitShiftNode.execute(self, new EnsoBigInteger(BigIntegerOps.negate(that.getValue())));
}
@Specialization
Object doBigInteger(
EnsoBigInteger self,
@ -37,9 +48,7 @@ public abstract class BitShiftRightNode extends Node {
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@ -6,21 +6,28 @@ import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "bit_xor", description = "Bitwise exclusive or.")
@BuiltinMethod(type = "Integer", name = "bit_xor", description = "Bitwise exclusive or.")
public abstract class BitXorNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(EnsoBigInteger self, Object that);
abstract Object execute(Object self, Object that);
static BitXorNode build() {
return BitXorNodeGen.create();
}
@Specialization
long doLong(long self, long that) {
return self ^ that;
}
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitXor(self, that.getValue()));
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitXor(self.getValue(), that));
@ -32,9 +39,7 @@ public abstract class BitXorNode extends Node {
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -0,0 +1,31 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = "ceil", description = "Small integer ceiling.")
public abstract class CeilNode extends Node {
abstract Object execute(Object self);
public static CeilNode build() {
return CeilNodeGen.create();
}
@Specialization
long doLong(long self) {
return self;
}
@Specialization
EnsoBigInteger doBigInt(EnsoBigInteger self) {
return self;
}
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@ -7,21 +7,36 @@ import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "div", description = "Big integer integral division.")
@BuiltinMethod(type = "Integer", name = "div", description = "Division of numbers.")
public abstract class DivNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(EnsoBigInteger self, Object that);
abstract Object execute(Object self, Object that);
static DivNode build() {
return DivNodeGen.create();
}
@Specialization
Object doLong(long self, long that) {
try {
return self / that;
} catch (ArithmeticException e) {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getDivideByZeroError(), this);
}
}
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
// No need to trap, as 0 is never represented as an EnsoBigInteger.
return 0L;
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
try {
@ -39,9 +54,7 @@ public abstract class DivNode extends Node {
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -1,23 +1,35 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "/", description = "Big integer division.")
@BuiltinMethod(type = "Integer", name = "/", description = "Division of numbers.")
public abstract class DivideNode extends Node {
abstract double execute(EnsoBigInteger self, Object that);
abstract double execute(Object self, Object that);
static DivideNode build() {
return DivideNodeGen.create();
}
@Specialization
double doLong(long self, long that) {
return ((double) self) / ((double) that);
}
@Specialization
double doDouble(long self, double that) {
return self / that;
}
@Specialization
double doBigInteger(long self, EnsoBigInteger that) {
return ((double) self) / BigIntegerOps.toDouble(that.getValue());
}
@Specialization
double doBigInteger(EnsoBigInteger self, EnsoBigInteger that) {
return BigIntegerOps.toDouble(self.getValue()) / BigIntegerOps.toDouble(that.getValue());
@ -34,9 +46,7 @@ public abstract class DivideNode extends Node {
}
@Fallback
double doOther(EnsoBigInteger self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
double doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -0,0 +1,32 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = "floor", description = "Small integer floor.")
public abstract class FloorNode extends Node {
public abstract Object execute(Object self);
public static FloorNode build() {
return FloorNodeGen.create();
}
@Specialization
long doLong(long self) {
return self;
}
@Specialization
EnsoBigInteger doBigInt(EnsoBigInteger self) {
return self;
}
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@ -9,15 +9,30 @@ import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = ">", description = "Comparison of numbers.")
@BuiltinMethod(type = "Integer", name = ">", description = "Comparison of numbers.")
public abstract class GreaterNode extends Node {
abstract Object execute(EnsoBigInteger self, Object that);
abstract Object execute(Object self, Object that);
static GreaterNode build() {
return GreaterNodeGen.create();
}
@Specialization
boolean doLong(long self, long that) {
return self > that;
}
@Specialization
boolean doDouble(long self, double that) {
return (double) self > that;
}
@Specialization
boolean doBigInteger(long self, EnsoBigInteger that) {
return that.getValue().signum() < 0;
}
@Specialization
boolean doDouble(EnsoBigInteger self, double that) {
return BigIntegerOps.toDouble(self.getValue()) > that;
@ -34,7 +49,7 @@ public abstract class GreaterNode extends Node {
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Object doOther(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableValsErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableValsErr, this);

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@ -9,15 +9,30 @@ import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = ">=", description = "Comparison of numbers.")
@BuiltinMethod(type = "Integer", name = ">=", description = "Comparison of numbers.")
public abstract class GreaterOrEqualNode extends Node {
abstract Object execute(EnsoBigInteger self, Object that);
abstract Object execute(Object self, Object that);
static GreaterOrEqualNode build() {
return GreaterOrEqualNodeGen.create();
}
@Specialization
boolean doLong(long self, long that) {
return self >= that;
}
@Specialization
boolean doDouble(long self, double that) {
return (double) self >= that;
}
@Specialization
boolean doBigInteger(long self, EnsoBigInteger that) {
return that.getValue().signum() < 0;
}
@Specialization
boolean doDouble(EnsoBigInteger self, double that) {
return BigIntegerOps.toDouble(self.getValue()) >= that;
@ -34,7 +49,7 @@ public abstract class GreaterOrEqualNode extends Node {
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Object doOther(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableValsErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableValsErr, this);

View File

@ -0,0 +1,30 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
public final class IntegerUtils {
private IntegerUtils() {}
@TruffleBoundary
static PanicException throwTypeErrorIfNotInt(Object self, Object that, Node node) {
var builtins = EnsoContext.get(node).getBuiltins();
var intType = builtins.number().getInteger();
var selfType = TypesLibrary.getUncached().getType(self);
if (selfType != intType) {
return new PanicException(builtins.error().makeTypeError(intType, self, "self"), node);
} else {
return new PanicException(builtins.error().makeTypeError(intType, that, "that"), node);
}
}
@TruffleBoundary
static PanicException throwTypeErrorIfNotInt(Object self, Node node) {
var builtins = EnsoContext.get(node).getBuiltins();
var intType = builtins.number().getInteger();
return new PanicException(builtins.error().makeTypeError(intType, self, "self"), node);
}
}

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@ -9,15 +9,30 @@ import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "<", description = "Comparison of numbers.")
@BuiltinMethod(type = "Integer", name = "<", description = "Comparison of numbers.")
public abstract class LessNode extends Node {
abstract Object execute(EnsoBigInteger self, Object that);
abstract Object execute(Object self, Object that);
static LessNode build() {
return LessNodeGen.create();
}
@Specialization
boolean doLong(long self, long that) {
return self < that;
}
@Specialization
boolean doDouble(long self, double that) {
return (double) self < that;
}
@Specialization
boolean doBigInteger(long self, EnsoBigInteger that) {
return that.getValue().signum() > 0;
}
@Specialization
boolean doDouble(EnsoBigInteger self, double that) {
return BigIntegerOps.toDouble(self.getValue()) < that;
@ -34,7 +49,7 @@ public abstract class LessNode extends Node {
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Object doOther(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableValsErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableValsErr, this);

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@ -9,15 +9,30 @@ import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "<=", description = "Comparison of numbers.")
@BuiltinMethod(type = "Integer", name = "<=", description = "Comparison of numbers.")
public abstract class LessOrEqualNode extends Node {
abstract Object execute(EnsoBigInteger self, Object that);
abstract Object execute(Object self, Object that);
static LessOrEqualNode build() {
return LessOrEqualNodeGen.create();
}
@Specialization
boolean doLong(long self, long that) {
return self <= that;
}
@Specialization
boolean doDouble(long self, double that) {
return (double) self <= that;
}
@Specialization
boolean doBigInteger(long self, EnsoBigInteger that) {
return that.getValue().signum() > 0;
}
@Specialization
boolean doDouble(EnsoBigInteger self, double that) {
return BigIntegerOps.toDouble(self.getValue()) <= that;
@ -34,7 +49,7 @@ public abstract class LessOrEqualNode extends Node {
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Object doOther(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableValsErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableValsErr, this);

View File

@ -0,0 +1,85 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import java.math.BigInteger;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = "%", description = "Modulo division of numbers.")
public abstract class ModNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(Object self, Object that);
static ModNode build() {
return ModNodeGen.create();
}
@Specialization
Object doLong(long self, long that) {
try {
return self % that;
} catch (ArithmeticException e) {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getDivideByZeroError(), this);
}
}
@Specialization
double doDouble(long self, double that) {
// No need to try-catch, as floating-point modulo returns NaN for division by zero instead of
// throwing.
return self % that;
}
@TruffleBoundary
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
var selfBigInt = BigInteger.valueOf(self);
try {
return toEnsoNumberNode.execute(BigIntegerOps.modulo(selfBigInt, that.getValue()));
} catch (ArithmeticException e) {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getDivideByZeroError(), this);
}
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
try {
return toEnsoNumberNode.execute(BigIntegerOps.modulo(self.getValue(), that));
} catch (ArithmeticException e) {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getDivideByZeroError(), this);
}
}
@Specialization
double doDouble(EnsoBigInteger self, double that) {
// No need to trap, as floating-point modulo returns NaN for division by zero instead of
// throwing.
return BigIntegerOps.toDouble(self.getValue()) % that;
}
@Specialization
Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) {
try {
return toEnsoNumberNode.execute(BigIntegerOps.modulo(self.getValue(), that.getValue()));
} catch (ArithmeticException e) {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getDivideByZeroError(), this);
}
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@ -6,16 +6,13 @@ import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "*", description = "Multiplication of numbers.")
@BuiltinMethod(type = "Integer", name = "*", description = "Multiplication of numbers.")
public abstract class MultiplyNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(long self, Object that);
abstract Object execute(Object self, Object that);
static MultiplyNode build() {
return MultiplyNodeGen.create();
@ -41,10 +38,23 @@ public abstract class MultiplyNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.multiply(that.getValue(), self));
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.multiply(self.getValue(), that));
}
@Specialization
Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.multiply(self.getValue(), that.getValue()));
}
@Specialization
double doDouble(EnsoBigInteger self, double that) {
return BigIntegerOps.toDouble(self.getValue()) * that;
}
@Fallback
Object doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -1,12 +1,14 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "negate", description = "Negation for numbers.")
@BuiltinMethod(type = "Integer", name = "negate", description = "Negation for numbers.")
public abstract class NegateNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
@ -14,15 +16,25 @@ public abstract class NegateNode extends Node {
return NegateNodeGen.create();
}
abstract Object execute(long self);
abstract Object execute(Object self);
@Specialization(rewriteOn = ArithmeticException.class)
long doNormal(long self) {
return Math.negateExact(self);
}
@Specialization
Object doBigInt(EnsoBigInteger self) {
return toEnsoNumberNode.execute(BigIntegerOps.negate(self.getValue()));
}
@Specialization
Object doOverflow(long self) {
return toEnsoNumberNode.execute(BigIntegerOps.negate(self));
}
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -1,26 +1,58 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import java.math.BigInteger;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "^", description = "Big integer exponentiation.")
@BuiltinMethod(type = "Integer", name = "^", description = "Exponentiation of numbers.")
public abstract class PowNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
private @Child MultiplyNode multiplyNode = MultiplyNode.build();
public abstract Object execute(EnsoBigInteger self, Object that);
abstract Object execute(Object self, Object that);
public static PowNode build() {
static PowNode build() {
return PowNodeGen.create();
}
@Specialization
Object doLong(long self, long that) {
if (that < 0) {
return Math.pow(self, that);
} else if (that == 0) {
return 1L;
} else {
Object res = 1L;
Object base = self;
while (that > 0) {
if (that % 2 == 0) {
base = multiplyNode.execute(base, base);
that /= 2;
} else {
res = multiplyNode.execute(res, base);
that--;
}
}
return res;
}
}
@Specialization
double doDouble(long self, double that) {
return Math.pow(self, that);
}
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
return doBigInteger(toBigInteger(self), that);
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
if (that == 0) {
@ -49,10 +81,13 @@ public abstract class PowNode extends Node {
return Math.pow(BigIntegerOps.toDouble(self.getValue()), that);
}
@CompilerDirectives.TruffleBoundary
private static EnsoBigInteger toBigInteger(long self) {
return new EnsoBigInteger(BigInteger.valueOf(self));
}
@Fallback
Object doOther(EnsoBigInteger self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;

View File

@ -1,4 +1,4 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@ -6,16 +6,13 @@ import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "-", description = "Subtraction of numbers.")
@BuiltinMethod(type = "Integer", name = "-", description = "Subtraction of numbers.")
public abstract class SubtractNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(long self, Object that);
abstract Object execute(Object self, Object that);
static SubtractNode build() {
return SubtractNodeGen.create();
@ -41,10 +38,23 @@ public abstract class SubtractNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.subtract(self, that.getValue()));
}
@Specialization
Object doLong(EnsoBigInteger self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.subtract(self.getValue(), that));
}
@Specialization
Object doBigInteger(EnsoBigInteger self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.subtract(self.getValue(), that.getValue()));
}
@Specialization
double doDouble(EnsoBigInteger self, double that) {
return BigIntegerOps.toDouble(self.getValue()) - that;
}
@Fallback
Object doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
}
}

View File

@ -0,0 +1,35 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(
type = "Integer",
name = "to_decimal",
description = "Conversion of integers to decimals.")
public abstract class ToDecimalNode extends Node {
public abstract Object execute(Object self);
public static ToDecimalNode build() {
return ToDecimalNodeGen.create();
}
@Specialization
double doLong(long self) {
return self;
}
@Specialization
double doBigInt(EnsoBigInteger self) {
return BigIntegerOps.toDouble(self.getValue());
}
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -1,50 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "+", description = "Addition of numbers.")
public abstract class AddNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(long self, Object that);
static AddNode build() {
return AddNodeGen.create();
}
@Specialization(rewriteOn = ArithmeticException.class)
long doLong(long self, long that) {
return Math.addExact(self, that);
}
@Specialization
Object doOverflow(long self, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.add(self, that));
}
@Specialization
double doDouble(long self, double that) {
return self + that;
}
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.add(that.getValue(), self));
}
@Fallback
Object doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
}
}

View File

@ -1,40 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "bit_and", description = "Bitwise and.")
public abstract class BitAndNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(Object self, Object that);
static BitAndNode build() {
return BitAndNodeGen.create();
}
@Specialization
long doLong(long self, long that) {
return self & that;
}
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitAnd(self, that.getValue()));
}
@Fallback
Object doOther(Object self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
}
}

View File

@ -1,30 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
@BuiltinMethod(type = "Small_Integer", name = "bit_not", description = "Bitwise negation.")
public abstract class BitNotNode extends Node {
abstract Object execute(Object self);
static BitNotNode build() {
return BitNotNodeGen.create();
}
@Specialization
long doLong(long self) {
return ~self;
}
@Fallback
Object doOther(Object self) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, self, "this"), this);
}
}

View File

@ -1,40 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "bit_or", description = "Bitwise or.")
public abstract class BitOrNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(long self, Object that);
static BitOrNode build() {
return BitOrNodeGen.create();
}
@Specialization
long doLong(long self, long that) {
return self | that;
}
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitOr(self, that.getValue()));
}
@Fallback
Object doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
}
}

View File

@ -1,43 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Shared;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "bit_shift_r", description = "Bitwise right-shift.")
public abstract class BitShiftRightNode extends Node {
abstract Object execute(long self, Object that);
static BitShiftRightNode build() {
return BitShiftRightNodeGen.create();
}
@Specialization
Object doBigInteger(
long self, long that, @Shared("bitShiftNode") @Cached("build()") BitShiftNode bitShiftNode) {
return bitShiftNode.execute(self, -1L * that);
}
@Specialization
Object doBigInteger(
long self,
EnsoBigInteger that,
@Shared("bitShiftNode") @Cached("build()") BitShiftNode bitShiftNode) {
return bitShiftNode.execute(self, new EnsoBigInteger(BigIntegerOps.negate(that.getValue())));
}
@Fallback
Object doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
}
}

View File

@ -1,40 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "bit_xor", description = "Bitwise exclusive or.")
public abstract class BitXorNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
abstract Object execute(long self, Object that);
static BitXorNode build() {
return BitXorNodeGen.create();
}
@Specialization
long doLong(long self, long that) {
return self ^ that;
}
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.bitXor(self, that.getValue()));
}
@Fallback
Object doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
}
}

View File

@ -1,11 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@BuiltinMethod(type = "Small_Integer", name = "ceil", description = "Small integer ceiling.")
public class CeilNode extends Node {
long execute(long self) {
return self;
}
}

View File

@ -1,43 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "div", description = "Division of numbers.")
public abstract class DivNode extends Node {
abstract Object execute(long self, Object that);
static DivNode build() {
return DivNodeGen.create();
}
@Specialization
Object doLong(long self, long that) {
try {
return self / that;
} catch (ArithmeticException e) {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getDivideByZeroError(), this);
}
}
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
// No need to trap, as 0 is never represented as an EnsoBigInteger.
return 0L;
}
@Fallback
Object doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var integer = builtins.number().getInteger();
throw new PanicException(builtins.error().makeTypeError(integer, that, "that"), this);
}
}

View File

@ -1,42 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "/", description = "Division of numbers.")
public abstract class DivideNode extends Node {
abstract double execute(long self, Object that);
static DivideNode build() {
return DivideNodeGen.create();
}
@Specialization
double doLong(long self, long that) {
return ((double) self) / ((double) that);
}
@Specialization
double doDouble(long self, double that) {
return self / that;
}
@Specialization
double doBigInteger(long self, EnsoBigInteger that) {
return ((double) self) / BigIntegerOps.toDouble(that.getValue());
}
@Fallback
double doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
}
}

View File

@ -1,11 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@BuiltinMethod(type = "Small_Integer", name = "floor", description = "Small integer floor.")
public class FloorNode extends Node {
long execute(long self) {
return self;
}
}

View File

@ -1,41 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = ">", description = "Comparison of numbers.")
public abstract class GreaterNode extends Node {
abstract Object execute(long self, Object that);
static GreaterNode build() {
return GreaterNodeGen.create();
}
@Specialization
boolean doLong(long self, long that) {
return self > that;
}
@Specialization
boolean doDouble(long self, double that) {
return (double) self > that;
}
@Specialization
boolean doBigInteger(long self, EnsoBigInteger that) {
return that.getValue().signum() < 0;
}
@Fallback
Object doOther(long self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableValsErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableValsErr, this);
}
}

View File

@ -1,41 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = ">=", description = "Comparison of numbers.")
public abstract class GreaterOrEqualNode extends Node {
abstract Object execute(long self, Object that);
static GreaterOrEqualNode build() {
return GreaterOrEqualNodeGen.create();
}
@Specialization
boolean doLong(long self, long that) {
return self >= that;
}
@Specialization
boolean doDouble(long self, double that) {
return (double) self >= that;
}
@Specialization
boolean doBigInteger(long self, EnsoBigInteger that) {
return that.getValue().signum() < 0;
}
@Fallback
Object doOther(long self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableValsErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableValsErr, this);
}
}

View File

@ -1,41 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "<", description = "Comparison of numbers.")
public abstract class LessNode extends Node {
abstract Object execute(long self, Object that);
static LessNode build() {
return LessNodeGen.create();
}
@Specialization
boolean doLong(long self, long that) {
return self < that;
}
@Specialization
boolean doDouble(long self, double that) {
return (double) self < that;
}
@Specialization
boolean doBigInteger(long self, EnsoBigInteger that) {
return that.getValue().signum() > 0;
}
@Fallback
Object doOther(long self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableValsErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableValsErr, this);
}
}

View File

@ -1,41 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "<=", description = "Comparison of numbers.")
public abstract class LessOrEqualNode extends Node {
abstract Object execute(long self, Object that);
static LessOrEqualNode build() {
return LessOrEqualNodeGen.create();
}
@Specialization
boolean doLong(long self, long that) {
return self <= that;
}
@Specialization
boolean doDouble(long self, double that) {
return (double) self <= that;
}
@Specialization
boolean doBigInteger(long self, EnsoBigInteger that) {
return that.getValue().signum() > 0;
}
@Fallback
Object doOther(long self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableValsErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableValsErr, this);
}
}

View File

@ -1,50 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "%", description = "Modulo division of numbers.")
public abstract class ModNode extends Node {
abstract Object execute(long self, Object that);
static ModNode build() {
return ModNodeGen.create();
}
@Specialization
Object doLong(long self, long that) {
try {
return self % that;
} catch (ArithmeticException e) {
return DataflowError.withoutTrace(
EnsoContext.get(this).getBuiltins().error().getDivideByZeroError(), this);
}
}
@Specialization
double doDouble(long self, double that) {
// No need to trap, as floating-point modulo returns NaN for division by zero instead of
// throwing.
return self % that;
}
@Specialization
long doBigInteger(long self, EnsoBigInteger that) {
// No need to trap, as 0 is never represented as an EnsoBigInteger.
return self;
}
@Fallback
Object doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
}
}

View File

@ -1,85 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import java.math.BigInteger;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "^", description = "Exponentiation of numbers.")
public abstract class PowNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
private @Child org.enso.interpreter.node.expression.builtin.number.smallInteger.MultiplyNode
longMultiplyNode =
org.enso.interpreter.node.expression.builtin.number.smallInteger.MultiplyNode.build();
private @Child org.enso.interpreter.node.expression.builtin.number.bigInteger.MultiplyNode
bigIntMultiplyNode =
org.enso.interpreter.node.expression.builtin.number.bigInteger.MultiplyNode.build();
private @Child org.enso.interpreter.node.expression.builtin.number.bigInteger.PowNode
bigIntPowNode =
org.enso.interpreter.node.expression.builtin.number.bigInteger.PowNode.build();
abstract Object execute(long self, Object that);
static PowNode build() {
return PowNodeGen.create();
}
@Specialization
Object doLong(long self, long that) {
if (that < 0) {
return Math.pow(self, that);
} else if (that == 0) {
return 1L;
} else {
Object res = 1L;
Object base = self;
while (that > 0) {
if (that % 2 == 0) {
if (base instanceof Long) {
base = longMultiplyNode.execute((long) base, base);
} else {
base = bigIntMultiplyNode.execute((EnsoBigInteger) base, base);
}
that /= 2;
} else {
if (res instanceof Long) {
res = longMultiplyNode.execute((long) res, base);
} else {
res = bigIntMultiplyNode.execute((EnsoBigInteger) res, base);
}
that--;
}
}
return res;
}
}
@Specialization
double doDouble(long self, double that) {
return Math.pow(self, that);
}
@Specialization
Object doBigInteger(long self, EnsoBigInteger that) {
return bigIntPowNode.execute(toBigInteger(self), that);
}
@CompilerDirectives.TruffleBoundary
private static EnsoBigInteger toBigInteger(long self) {
return new EnsoBigInteger(BigInteger.valueOf(self));
}
@Fallback
Object doOther(long self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
}
}

View File

@ -1,14 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number.smallInteger;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@BuiltinMethod(
type = "Small_Integer",
name = "to_decimal",
description = "Conversion of integers to decimals.")
public class ToDecimalNode extends Node {
double execute(long self) {
return self;
}
}

View File

@ -1,40 +1,24 @@
package org.enso.interpreter.runtime.builtin;
import org.enso.interpreter.node.expression.builtin.Builtin;
import org.enso.interpreter.node.expression.builtin.number.BigInteger;
import org.enso.interpreter.node.expression.builtin.number.Decimal;
import org.enso.interpreter.node.expression.builtin.number.Integer;
import org.enso.interpreter.node.expression.builtin.number.SmallInteger;
import org.enso.interpreter.runtime.data.Type;
/** A container for all number-related builtins. */
public class Number {
private final Builtin smallInteger;
private final Builtin bigInteger;
private final Builtin integer;
private final Builtin number;
private final Builtin decimal;
/** Creates builders for number Atom Constructors. */
public Number(Builtins builtins) {
smallInteger = builtins.getBuiltinType(SmallInteger.class);
bigInteger = builtins.getBuiltinType(BigInteger.class);
integer = builtins.getBuiltinType(Integer.class);
number =
builtins.getBuiltinType(org.enso.interpreter.node.expression.builtin.number.Number.class);
decimal = builtins.getBuiltinType(Decimal.class);
}
/** @return the Int64 atom constructor. */
public Type getSmallInteger() {
return smallInteger.getType();
}
/** @return the Big_Integer atom constructor. */
public Type getBigInteger() {
return bigInteger.getType();
}
/** @return the Integer atom constructor */
public Type getInteger() {
return integer.getType();

View File

@ -17,6 +17,6 @@ public class DefaultLongExports {
@ExportMessage
static Type getType(
Long receiver, @CachedLibrary("receiver") TypesLibrary thisLib, @Cached("1") int ignore) {
return EnsoContext.get(thisLib).getBuiltins().number().getSmallInteger();
return EnsoContext.get(thisLib).getBuiltins().number().getInteger();
}
}

View File

@ -131,7 +131,7 @@ public final class EnsoBigInteger implements EnsoObject {
@ExportMessage
Type getMetaObject(@CachedLibrary("this") InteropLibrary thisLib) {
return EnsoContext.get(thisLib).getBuiltins().number().getBigInteger();
return EnsoContext.get(thisLib).getBuiltins().number().getInteger();
}
@ExportMessage
@ -146,7 +146,7 @@ public final class EnsoBigInteger implements EnsoObject {
@ExportMessage
Type getType(@CachedLibrary("this") TypesLibrary thisLib, @Cached("1") int ignore) {
return EnsoContext.get(thisLib).getBuiltins().number().getBigInteger();
return EnsoContext.get(thisLib).getBuiltins().number().getInteger();
}
@Override

View File

@ -0,0 +1,71 @@
package org.enso.interpreter.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import java.math.BigInteger;
import org.enso.interpreter.node.expression.builtin.number.integer.AbsNode;
import org.enso.interpreter.node.expression.builtin.number.integer.AddNode;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
import org.graalvm.polyglot.Context;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.theories.Theories;
import org.junit.runner.RunWith;
/** Tests Truffle nodes for integer operations. */
@RunWith(Theories.class)
public class IntegerTest extends TestBase {
private static AbsNode absNode;
private static AddNode addNode;
private static Context ctx;
@BeforeClass
public static void setup() {
ctx = createDefaultContext();
executeInContext(
ctx,
() -> {
absNode = AbsNode.build();
addNode = AddNode.build();
return null;
});
}
private static final EnsoBigInteger bigInt =
new EnsoBigInteger(new BigInteger("1000000000000000000000000000000000000"));
private static final EnsoBigInteger bigIntNegative =
new EnsoBigInteger(new BigInteger("-1000000000000000000000000000000000000"));
@Test
public void testAbs() {
executeInContext(
ctx,
() -> {
assertEquals(23L, absNode.execute(23L));
assertEquals(23L, absNode.execute(-23L));
assertTrue(absNode.execute(Long.MIN_VALUE) instanceof EnsoBigInteger);
assertEquals(bigInt, absNode.execute(bigInt));
assertEquals(bigInt, absNode.execute(bigIntNegative));
assertThrows(
"Decimals are not supported", PanicException.class, () -> absNode.execute(23.0));
assertThrows(
"Java int is not supported", PanicException.class, () -> absNode.execute(23));
return null;
});
}
@Test
public void testAdd() {
executeInContext(
ctx,
() -> {
assertEquals(23L, addNode.execute(22L, 1L));
assertThrows(PanicException.class, () -> addNode.execute(23L, "Hello"));
return null;
});
}
}

View File

@ -133,7 +133,7 @@ class TextTest extends InterpreterTest {
"Compile error: error :(.",
"Inexhaustive pattern match: no branch matches 32.",
"Arithmetic error: cannot frobnicate quaternions.",
"Type error: expected `that` to be Number, but got Text.",
"Type error: expected `that` to be Integer, but got Text.",
"Type error: expected a function, but got 7.",
"Wrong number of arguments. Expected 10, but got 20."
)

View File

@ -225,6 +225,13 @@ spec =
Integer.parse "-101021010" 2 . should_fail_with Number_Parse_Error
Integer.parse "123" 128 . should_fail_with Number_Parse_Error
Test.specify "should be able to invoke methods on Integer via static method call" <|
Integer.+ 1 2 . should_equal 3
Integer.+ 1 2.5 . should_equal 3.5
Test.expect_panic_with (Integer.+ 1.5 1) Type_Error
Test.expect_panic_with (Integer.+ 1.5 2.5) Type_Error
Test.expect_panic_with (Integer.+ 1 "hello") Type_Error
Test.group "Decimals" <|
Test.specify "should exist and expose basic arithmetic operations" <|
@ -297,6 +304,10 @@ spec =
1/0 . is_infinite . should_be_true
-1/0 . is_infinite . should_be_true
hundred_factorial%0 . should_fail_with Arithmetic_Error
hundred_factorial%hundred_factorial . should_equal 0
10%hundred_factorial . should_equal 10
Test.specify "should support less than operator" <|
(1 < 2).should_be_true
(1 < 1).should_be_false

View File

@ -258,10 +258,10 @@ spec =
methods.sort . should_equal ['Value', 'create', 'factory', 'first_method', 'my_method', 'other_method', 'second_method']
Test.specify "methods of Integer" <|
Meta.meta Integer . methods . sort . should_equal ['bit_shift_l', 'round', 'truncate']
Meta.meta Integer . methods . sort . should_equal ['%', '*', '+', '-', '/', '<', '<=', '>', '>=', '^', 'abs', 'bit_and', 'bit_not', 'bit_or', 'bit_shift', 'bit_shift_l', 'bit_shift_r', 'bit_xor', 'ceil', 'div', 'floor', 'negate', 'round', 'to_decimal', 'truncate']
Test.specify "static methods of Integer" <|
Meta.meta (Meta.type_of Integer) . methods . sort . should_equal ['bit_shift_l', 'parse', 'parse_builtin', 'round', 'round_integer_builtin', 'truncate']
Meta.meta (Meta.type_of Integer) . methods . sort . should_equal ['%', '*', '+', '-', '/', '<', '<=', '>', '>=', '^', 'abs', 'bit_and', 'bit_not', 'bit_or', 'bit_shift', 'bit_shift_l', 'bit_shift_r', 'bit_xor', 'ceil', 'div', 'floor', 'negate', 'parse', 'parse_builtin', 'round', 'round_integer_builtin', 'to_decimal', 'truncate']
Test.specify "methods of Any" <|
Meta.meta Any . methods . should_contain "to_text"