Runtime checking of ascribed expression types (#7796)

This commit is contained in:
Jaroslav Tulach 2023-09-14 14:09:41 +02:00 committed by GitHub
parent a5094225cf
commit 30a62b97bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 1852 additions and 370 deletions

View File

@ -947,6 +947,7 @@
projects next to each other][7634]
- [Support runtime checks of intersection types][7769]
- [Merge `Small_Integer` and `Big_Integer` types][7636]
- [Inline type ascriptions][7796]
[3227]: https://github.com/enso-org/enso/pull/3227
[3248]: https://github.com/enso-org/enso/pull/3248
@ -1086,6 +1087,7 @@
[7634]: https://github.com/enso-org/enso/pull/7634
[7769]: https://github.com/enso-org/enso/pull/7769
[7636]: https://github.com/enso-org/enso/pull/7636
[7796]: https://github.com/enso-org/enso/pull/7796
# Enso 2.0.0-alpha.18 (2021-10-12)

View File

@ -87,7 +87,6 @@ working with types. These are listed below.
| `;` | `< :`, `> =` | -2 | Left | Concatenates the left and right operand typesets to create a new typeset. |
| `\|` | `> <:`, `> !`, `> in`, `> :` | 5 | Left | Computes the union of the left and right operand typesets. |
| `&` | `> \|` | 6 | Left | Computes the intersection of the left and right operand typesets. |
| `\` | `> &` | 7 | Left | Computes the subtraction of the right typeset from the left typeset. |
| `:=` | `< :`, `> =`, `> ;` | -1 | Left | Creates a typeset member by assigning a value to a label. |
<!-- prettier-ignore-end -->
@ -108,7 +107,6 @@ bind (`=`) has a relative level of -3 in this ordering.
(declare-fun tsConcat () Int) ; `;`
(declare-fun tsUnion () Int) ; `|`
(declare-fun tsInter () Int) ; `&`
(declare-fun minus () Int) ; `\`
(declare-fun tsMember () Int) ; `:=`
(assert (> ascrip bind))
@ -265,8 +263,6 @@ of typesets. Their syntax is as follows:
arguments.
- **Intersection - `&`:** The resultant typeset may contain values that are
members of _both_ its arguments.
- **Subtraction - `\`:** The resultant typeset may contain values that are in
the first argument's set but not in the second.
> The actionables for this section are:
>

View File

@ -194,10 +194,8 @@ They are as follows:
product types.
- **Union - `|`:** This operator creates a typeset that contains the members in
the union of its operands.
- **Intersection - `|`:** This operator creates a typeset that contains the
- **Intersection - `&`:** This operator creates a typeset that contains the
members in the intersection of its operands.
- **Subtraction - `\`:** This operator creates a typeset that contains all of
the members in the left operand that do not occur in the right operand.
For information on the syntactic usage of these operators, please see the
section on [type operators](#../syntax/types.md#type-operators) in the syntax

View File

@ -99,7 +99,8 @@ public abstract class IndirectInvokeMethodNode extends Node {
@Shared("indirectInvokeFunctionNode") @Cached IndirectInvokeFunctionNode invokeFunctionNode,
@Cached ConditionProfile profile) {
Function function =
methodResolverNode.execute(EnsoContext.get(this).getBuiltins().dataflowError(), symbol);
methodResolverNode.executeResolution(
EnsoContext.get(this).getBuiltins().dataflowError(), symbol);
if (profile.profile(function == null)) {
return self;
} else {

View File

@ -12,6 +12,7 @@ import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.control.TailCallException;
import org.enso.interpreter.runtime.data.ArrayRope;
import org.enso.interpreter.runtime.data.EnsoMultiValue;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.data.text.Text;
import org.enso.interpreter.runtime.error.DataflowError;
@ -152,6 +153,27 @@ public abstract class InvokeConversionNode extends BaseNode {
throw that;
}
@Specialization
Object doMultiValue(
VirtualFrame frame,
State state,
UnresolvedConversion conversion,
Object self,
EnsoMultiValue that,
Object[] arguments) {
var type = extractType(self);
var result = that.castTo(type);
if (result == null) {
throw new PanicException(
EnsoContext.get(this)
.getBuiltins()
.error()
.makeNoSuchConversion(type, self, conversion),
this);
}
return result;
}
@Specialization
Object doWarning(
VirtualFrame frame,

View File

@ -162,7 +162,7 @@ public abstract class InvokeMethodNode extends BaseNode {
Function resolveFunction(
UnresolvedSymbol symbol, Type selfTpe, MethodResolverNode methodResolverNode) {
Function function = methodResolverNode.execute(selfTpe, symbol);
Function function = methodResolverNode.executeResolution(selfTpe, symbol);
if (function == null) {
return null;
}
@ -288,10 +288,11 @@ public abstract class InvokeMethodNode extends BaseNode {
var fnAndType = self.resolveSymbol(methodResolverNode, symbol);
if (fnAndType != null) {
var unwrapSelf = self.castTo(fnAndType.getRight());
assert unwrapSelf != null;
assert arguments[0] == self;
arguments[0] = unwrapSelf;
return execute(frame, state, symbol, unwrapSelf, arguments);
if (unwrapSelf != null) {
assert arguments[0] == self;
arguments[0] = unwrapSelf;
}
return invokeFunctionNode.execute(fnAndType.getLeft(), frame, state, arguments);
}
throw methodNotFound(symbol, self);
}
@ -305,7 +306,7 @@ public abstract class InvokeMethodNode extends BaseNode {
Object[] arguments,
@Shared("methodResolverNode") @Cached MethodResolverNode methodResolverNode) {
Function function =
methodResolverNode.execute(EnsoContext.get(this).getBuiltins().dataflowError(), symbol);
methodResolverNode.executeResolution(EnsoContext.get(this).getBuiltins().dataflowError(), symbol);
if (errorReceiverProfile.profile(function == null)) {
return self;
} else {
@ -352,9 +353,10 @@ public abstract class InvokeMethodNode extends BaseNode {
e);
}
Type typeOfSymbol = symbol.resolveDeclaringType(this, types.getType(selfWithoutWarnings));
Builtins builtins = EnsoContext.get(this).getBuiltins();
if (typeOfSymbol == builtins.any()) {
var selfType = types.getType(selfWithoutWarnings);
var fnAndType = symbol.resolveFor(this, selfType);
var builtins = EnsoContext.get(this).getBuiltins();
if (fnAndType != null && fnAndType.getRight() == builtins.any()) {
return symbol
.getScope()
.lookupMethodDefinition(builtins.warning().getEigentype(), symbol.getName());

View File

@ -9,6 +9,7 @@ import org.enso.compiler.core.ir.Name;
import org.enso.interpreter.EnsoLanguage;
import org.enso.interpreter.node.BaseNode.TailStatus;
import org.enso.interpreter.node.EnsoRootNode;
import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.node.callable.ApplicationNode;
import org.enso.interpreter.node.callable.InvokeCallableNode.DefaultsExecutionMode;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
@ -55,6 +56,13 @@ public abstract class ReadArgumentCheckNode extends Node {
this.name = name;
}
/**
*
*/
public static ExpressionNode wrap(ExpressionNode original, ReadArgumentCheckNode check) {
return new TypeCheckExpressionNode(original, check);
}
/** Executes check or conversion of the value.abstract
* @param frame frame requesting the conversion
* @param value the value to convert
@ -289,16 +297,28 @@ public abstract class ReadArgumentCheckNode extends Node {
ApplicationNode findConversionNode(Type from) {
var convAndType = findConversion(from);
if (convAndType != null && NodeUtil.findParent(this, ReadArgumentNode.class) instanceof ReadArgumentNode ran) {
CompilerAsserts.neverPartOfCompilation();
var convNode = LiteralNode.build(convAndType.getLeft());
var intoNode = LiteralNode.build(convAndType.getRight());
var valueNode = ran.plainRead();
var args = new CallArgument[]{
new CallArgument(null, intoNode),
new CallArgument(null, valueNode)
};
return ApplicationNode.build(convNode, args, DefaultsExecutionMode.EXECUTE);
if (convAndType != null) {
if (NodeUtil.findParent(this, ReadArgumentNode.class) instanceof ReadArgumentNode ran) {
CompilerAsserts.neverPartOfCompilation();
var convNode = LiteralNode.build(convAndType.getLeft());
var intoNode = LiteralNode.build(convAndType.getRight());
var valueNode = ran.plainRead();
var args = new CallArgument[]{
new CallArgument(null, intoNode),
new CallArgument(null, valueNode)
};
return ApplicationNode.build(convNode, args, DefaultsExecutionMode.EXECUTE);
} else if (NodeUtil.findParent(this, TypeCheckExpressionNode.class) instanceof TypeCheckExpressionNode tcen) {
CompilerAsserts.neverPartOfCompilation();
var convNode = LiteralNode.build(convAndType.getLeft());
var intoNode = LiteralNode.build(convAndType.getRight());
var valueNode = tcen.original;
var args = new CallArgument[]{
new CallArgument(null, intoNode),
new CallArgument(null, valueNode)
};
return ApplicationNode.build(convNode, args, DefaultsExecutionMode.EXECUTE);
}
}
return null;
}
@ -378,4 +398,29 @@ public abstract class ReadArgumentCheckNode extends Node {
return result;
}
}
private static final class TypeCheckExpressionNode extends ExpressionNode {
@Child
private ExpressionNode original;
@Child
private ReadArgumentCheckNode check;
TypeCheckExpressionNode(ExpressionNode original, ReadArgumentCheckNode check) {
this.check = check;
this.original = original;
}
@Override
public Object executeGeneric(VirtualFrame frame) {
var value = original.executeGeneric(frame);
var result = check.handleCheckOrConversion(frame, value);
return result;
}
@Override
public boolean isInstrumentable() {
return false;
}
}
}

View File

@ -11,6 +11,7 @@ import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.error.PanicException;
import org.graalvm.collections.Pair;
@GenerateUncached
@ReportPolymorphism
@ -22,15 +23,20 @@ public abstract class MethodResolverNode extends Node {
return EnsoContext.get(this);
}
public abstract Function execute(Type type, UnresolvedSymbol symbol);
public abstract Pair<Function, Type> execute(Type type, UnresolvedSymbol symbol);
public Function expectNonNull(Object self, Type type, UnresolvedSymbol symbol) {
public final Function executeResolution(Type type, UnresolvedSymbol symbol) {
var pair = execute(type, symbol);
return pair == null ? null : pair.getLeft();
}
public final Function expectNonNull(Object self, Type type, UnresolvedSymbol symbol) {
var result = execute(type, symbol);
if (result == null) {
throw new PanicException(
EnsoContext.get(this).getBuiltins().error().makeNoSuchMethod(self, symbol), this);
}
return result;
return result.getLeft();
}
@Specialization(
@ -40,17 +46,17 @@ public abstract class MethodResolverNode extends Node {
"cachedType == type"
},
limit = "CACHE_SIZE")
Function resolveCached(
Pair<Function, Type> resolveCached(
Type type,
UnresolvedSymbol symbol,
@Cached("symbol") UnresolvedSymbol cachedSymbol,
@Cached("type") Type cachedType,
@Cached("resolveUncached(cachedType, cachedSymbol)") Function function) {
@Cached("resolveUncached(cachedType, cachedSymbol)") Pair<Function, Type> function) {
return function;
}
@Specialization(replaces = "resolveCached")
Function resolveUncached(Type self, UnresolvedSymbol symbol) {
Pair<Function, Type> resolveUncached(Type self, UnresolvedSymbol symbol) {
return symbol.resolveFor(this, self);
}
}

View File

@ -1,25 +1,28 @@
package org.enso.interpreter.node.expression.builtin.meta;
import com.ibm.icu.text.Normalizer;
import java.math.BigInteger;
import org.enso.interpreter.dsl.AcceptsError;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.data.EnsoMultiValue;
import org.enso.interpreter.runtime.data.text.Text;
import org.enso.interpreter.runtime.error.WarningsLibrary;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
import org.enso.polyglot.common_utils.Core_Text_Utils;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Shared;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node;
import java.math.BigInteger;
import org.enso.interpreter.dsl.AcceptsError;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.data.text.Text;
import org.enso.interpreter.runtime.error.WarningsLibrary;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
import org.enso.polyglot.common_utils.Core_Text_Utils;
@BuiltinMethod(
type = "Any",
@ -72,6 +75,18 @@ public abstract class EqualsNode extends Node {
return false;
}
@Specialization(guards="interop.isBoolean(other)")
boolean equalsBoolInterop(
boolean self, Object other,
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop
) {
try {
return self == interop.asBoolean(other);
} catch (UnsupportedMessageException ex) {
return false;
}
}
@Specialization
boolean equalsLongLong(long self, long other) {
return self == other;
@ -92,6 +107,18 @@ public abstract class EqualsNode extends Node {
return false;
}
@Specialization(guards="interop.fitsInLong(other)")
boolean equalsLongInterop(
long self, Object other,
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop
) {
try {
return self == interop.asLong(other);
} catch (UnsupportedMessageException ex) {
return false;
}
}
@Specialization
boolean equalsDoubleDouble(double self, double other) {
if (Double.isNaN(self) || Double.isNaN(other)) {
@ -117,6 +144,18 @@ public abstract class EqualsNode extends Node {
return self == other.asDouble();
}
@Specialization(guards="interop.fitsInDouble(other)")
boolean equalsDoubleInterop(
double self, Object other,
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop
) {
try {
return self == interop.asDouble(other);
} catch (UnsupportedMessageException ex) {
return false;
}
}
@Specialization
boolean equalsDoubleText(double self, Text other) {
return false;
@ -154,6 +193,23 @@ public abstract class EqualsNode extends Node {
return false;
}
@TruffleBoundary
@Specialization(guards={
"!isPrimitiveValue(other)",
"interop.fitsInBigInteger(other)"
})
boolean equalsBigIntInterop(
EnsoBigInteger self, Object other,
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop
) {
try {
var otherBigInteger = InteropLibrary.getUncached().asBigInteger(other);
return self.asBigInteger().equals(otherBigInteger);
} catch (UnsupportedMessageException ex) {
return false;
}
}
@Specialization
@TruffleBoundary
boolean equalsLongBigInt(long self, EnsoBigInteger other) {
@ -236,6 +292,43 @@ public abstract class EqualsNode extends Node {
return isSameObjectNode.execute(self, other) || equalsAtomNode.execute(self, other);
}
@Specialization
boolean equalsReverseBoolean(
TruffleObject self, boolean other,
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
@Shared("reverse") @Cached EqualsNode reverse
) {
return reverse.execute(other, self);
}
@Specialization
boolean equalsReverseLong(
TruffleObject self, long other,
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
@Shared("reverse") @Cached EqualsNode reverse
) {
return reverse.execute(other, self);
}
@Specialization
boolean equalsReverseDouble(
TruffleObject self, double other,
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
@Shared("reverse") @Cached EqualsNode reverse
) {
return reverse.execute(other, self);
}
@Specialization
boolean equalsReverseBigInt(
TruffleObject self, EnsoBigInteger other,
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
@Shared("reverse") @Cached EqualsNode reverse
) {
return reverse.execute(other, self);
}
@Specialization(guards = "isNotPrimitive(self, other, interop, warnings)")
boolean equalsComplex(
Object self,
@ -258,6 +351,9 @@ public abstract class EqualsNode extends Node {
if (warnings.hasWarnings(a) || warnings.hasWarnings(b)) {
return true;
}
if (a instanceof EnsoMultiValue || b instanceof EnsoMultiValue) {
return true;
}
return !isPrimitive(a, interop) && !isPrimitive(b, interop);
}
@ -269,11 +365,17 @@ public abstract class EqualsNode extends Node {
* org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode}.
*/
static boolean isPrimitive(Object object, InteropLibrary interop) {
return object instanceof Boolean
|| object instanceof Long
|| object instanceof Double
return isPrimitiveValue(object)
|| object instanceof EnsoBigInteger
|| object instanceof Text
|| interop.isString(object);
|| interop.isString(object)
|| interop.isNumber(object)
|| interop.isBoolean(object);
}
static boolean isPrimitiveValue(Object object) {
return object instanceof Boolean
|| object instanceof Long
|| object instanceof Double;
}
}

View File

@ -46,7 +46,8 @@ public abstract class GetAnnotationNode extends BaseNode {
if (targetTypeResult instanceof Type targetType) {
Function methodFunction;
if (method instanceof UnresolvedSymbol symbol) {
methodFunction = symbol.resolveFor(this, targetType);
var pair = symbol.resolveFor(this, targetType);
methodFunction = pair == null ? null : pair.getLeft();
} else {
CompilerDirectives.transferToInterpreter();
var ctx = EnsoContext.get(this);

View File

@ -1,10 +1,9 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@BuiltinMethod(type = "Decimal", name = "abs", description = "Absolute value of a number.")
public class AbsNode extends Node {
public class AbsNode extends FloatNode {
double execute(double self) {
return Math.abs(self);
}

View File

@ -1,17 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "+", description = "Addition of numbers.")
public abstract class AddNode extends Node {
public abstract class AddNode extends FloatNode {
abstract double execute(double self, Object that);
static AddNode build() {
@ -33,10 +34,18 @@ public abstract class AddNode extends Node {
return self + BigIntegerOps.toDouble(that.getValue());
}
@Specialization(guards = "isForeignNumber(iop, that)")
double doInterop(
double self,
TruffleObject that,
@CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop,
@Cached ToEnsoNumberNode toEnsoNumberNode,
@Cached AddNode delegate) {
return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode));
}
@Fallback
double doOther(double self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
throw panicOtherwise(self, that);
}
}

View File

@ -1,7 +1,6 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.CountingConditionProfile;
import java.math.BigDecimal;
import java.math.BigInteger;
@ -13,7 +12,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
type = "Decimal",
name = "ceil",
description = "Decimal ceiling, converting to a small or big integer depending on size.")
public class CeilNode extends Node {
public class CeilNode extends FloatNode {
private final CountingConditionProfile fitsProfile = CountingConditionProfile.create();
Object execute(double self) {

View File

@ -1,17 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "/", description = "Division of numbers.")
public abstract class DivideNode extends Node {
public abstract class DivideNode extends FloatNode {
abstract double execute(double self, Object that);
static DivideNode build() {
@ -33,10 +34,18 @@ public abstract class DivideNode extends Node {
return self / BigIntegerOps.toDouble(that.getValue());
}
@Specialization(guards = "isForeignNumber(iop, that)")
double doInterop(
double self,
TruffleObject that,
@CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop,
@Cached ToEnsoNumberNode toEnsoNumberNode,
@Cached DivideNode delegate) {
return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode));
}
@Fallback
double doOther(double self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
throw panicOtherwise(self, that);
}
}

View File

@ -0,0 +1,53 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.Node;
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.error.PanicException;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
abstract class FloatNode extends Node {
static final String INTEROP_LIMIT = "3";
final boolean isForeignNumber(InteropLibrary iop, TruffleObject obj) {
if (obj instanceof EnsoBigInteger) {
return false;
}
return iop.isNumber(obj);
}
final Object handleInterop(
boolean incomparableError,
double self,
TruffleObject that,
InteropLibrary iop,
ToEnsoNumberNode toEnsoNumberNode) {
try {
if (iop.fitsInLong(that)) {
return iop.asLong(that);
} else if (iop.fitsInDouble(that)) {
return iop.asDouble(that);
} else if (iop.fitsInBigInteger(that)) {
return toEnsoNumberNode.execute(iop.asBigInteger(that));
}
} catch (UnsupportedMessageException ex) {
}
return incomparableError ? incomparableError(self, that) : panicOtherwise(self, that);
}
final PanicException panicOtherwise(double self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
}
final DataflowError incomparableError(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableErr, this);
}
}

View File

@ -1,7 +1,6 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.CountingConditionProfile;
import java.math.BigDecimal;
import java.math.BigInteger;
@ -13,7 +12,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
type = "Decimal",
name = "floor",
description = "Decimal floor, converting to a small or big integer depending on size.")
public class FloorNode extends Node {
public class FloorNode extends FloatNode {
private final CountingConditionProfile fitsProfile = CountingConditionProfile.create();
Object execute(double self) {

View File

@ -1,16 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.error.DataflowError;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = ">", description = "Comparison of numbers.")
public abstract class GreaterNode extends Node {
public abstract class GreaterNode extends FloatNode {
abstract Object execute(double self, Object that);
@ -45,14 +47,18 @@ public abstract class GreaterNode extends Node {
}
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
double self,
TruffleObject that,
@CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop,
@Cached ToEnsoNumberNode toEnsoNumberNode,
@Cached GreaterNode delegate) {
return delegate.execute(self, handleInterop(true, self, that, iop, toEnsoNumberNode));
}
@Fallback
Object doOther(double self, Object that) {
return incomparableError(self, that);
}
private DataflowError incomparableError(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableErr, this);
}
}

View File

@ -1,16 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.error.DataflowError;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = ">=", description = "Comparison of numbers.")
public abstract class GreaterOrEqualNode extends Node {
public abstract class GreaterOrEqualNode extends FloatNode {
abstract Object execute(double self, Object that);
@ -45,14 +47,18 @@ public abstract class GreaterOrEqualNode extends Node {
}
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
double self,
TruffleObject that,
@CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop,
@Cached ToEnsoNumberNode toEnsoNumberNode,
@Cached GreaterOrEqualNode delegate) {
return delegate.execute(self, handleInterop(true, self, that, iop, toEnsoNumberNode));
}
@Fallback
Object doOther(double self, Object that) {
return incomparableError(self, that);
}
private DataflowError incomparableError(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableErr, this);
}
}

View File

@ -1,16 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.error.DataflowError;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "<", description = "Comparison of numbers.")
public abstract class LessNode extends Node {
public abstract class LessNode extends FloatNode {
abstract Object execute(double self, Object that);
@ -45,14 +47,18 @@ public abstract class LessNode extends Node {
}
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
double self,
TruffleObject that,
@CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop,
@Cached ToEnsoNumberNode toEnsoNumberNode,
@Cached LessNode delegate) {
return delegate.execute(self, handleInterop(true, self, that, iop, toEnsoNumberNode));
}
@Fallback
Object doOther(double self, Object that) {
return incomparableError(self, that);
}
private DataflowError incomparableError(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableErr, this);
}
}

View File

@ -1,16 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.error.DataflowError;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "<=", description = "Comparison of numbers.")
public abstract class LessOrEqualNode extends Node {
public abstract class LessOrEqualNode extends FloatNode {
abstract Object execute(double self, Object that);
@ -45,14 +47,18 @@ public abstract class LessOrEqualNode extends Node {
}
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
double self,
TruffleObject that,
@CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop,
@Cached ToEnsoNumberNode toEnsoNumberNode,
@Cached LessOrEqualNode delegate) {
return delegate.execute(self, handleInterop(true, self, that, iop, toEnsoNumberNode));
}
@Fallback
Object doOther(double self, Object that) {
return incomparableError(self, that);
}
private DataflowError incomparableError(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var incomparableErr = builtins.error().makeIncomparableValues(self, that);
return DataflowError.withoutTrace(incomparableErr, this);
}
}

View File

@ -1,17 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "%", description = "Modulo division of numbers.")
public abstract class ModNode extends Node {
public abstract class ModNode extends FloatNode {
abstract double execute(double self, Object that);
static ModNode build() {
@ -33,10 +34,18 @@ public abstract class ModNode extends Node {
return self % BigIntegerOps.toDouble(that.getValue());
}
@Specialization(guards = "isForeignNumber(iop, that)")
double doInterop(
double self,
TruffleObject that,
@CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop,
@Cached ToEnsoNumberNode toEnsoNumberNode,
@Cached ModNode delegate) {
return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode));
}
@Fallback
double doOther(double self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
throw panicOtherwise(self, that);
}
}

View File

@ -1,17 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "*", description = "Multiplication of numbers.")
public abstract class MultiplyNode extends Node {
public abstract class MultiplyNode extends FloatNode {
abstract double execute(double self, Object that);
static MultiplyNode build() {
@ -33,10 +34,18 @@ public abstract class MultiplyNode extends Node {
return self * BigIntegerOps.toDouble(that.getValue());
}
@Specialization(guards = "isForeignNumber(iop, that)")
double doInterop(
double self,
TruffleObject that,
@CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop,
@Cached ToEnsoNumberNode toEnsoNumberNode,
@Cached MultiplyNode delegate) {
return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode));
}
@Fallback
double doOther(double self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
throw panicOtherwise(self, that);
}
}

View File

@ -1,10 +1,9 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@BuiltinMethod(type = "Decimal", name = "negate", description = "Negation for numbers.")
public class NegateNode extends Node {
public class NegateNode extends FloatNode {
double execute(double self) {
return -self;
}

View File

@ -1,17 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "^", description = "Exponentiation of numbers.")
public abstract class PowNode extends Node {
public abstract class PowNode extends FloatNode {
abstract double execute(double self, Object that);
static PowNode build() {
@ -33,10 +34,18 @@ public abstract class PowNode extends Node {
return Math.pow(self, BigIntegerOps.toDouble(that.getValue()));
}
@Specialization(guards = "isForeignNumber(iop, that)")
double doInterop(
double self,
TruffleObject that,
@CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop,
@Cached ToEnsoNumberNode toEnsoNumberNode,
@Cached PowNode delegate) {
return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode));
}
@Fallback
double doOther(double self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
throw panicOtherwise(self, that);
}
}

View File

@ -1,7 +1,6 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.profiles.CountingConditionProfile;
import com.oracle.truffle.api.profiles.PrimitiveValueProfile;
@ -16,7 +15,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
type = "Decimal",
name = "round",
description = "Decimal ceiling, converting to a small or big integer depending on size.")
public class RoundNode extends Node {
public class RoundNode extends FloatNode {
private final CountingConditionProfile fitsProfile = CountingConditionProfile.create();
private final PrimitiveValueProfile constantPlacesDecimalPlaces = PrimitiveValueProfile.create();

View File

@ -1,17 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "-", description = "Subtraction of numbers.")
public abstract class SubtractNode extends Node {
public abstract class SubtractNode extends FloatNode {
abstract double execute(double self, Object that);
static SubtractNode build() {
@ -33,10 +34,18 @@ public abstract class SubtractNode extends Node {
return self - BigIntegerOps.toDouble(that.getValue());
}
@Specialization(guards = "isForeignNumber(iop, that)")
double doInterop(
double self,
TruffleObject that,
@CachedLibrary(limit = INTEROP_LIMIT) InteropLibrary iop,
@Cached ToEnsoNumberNode toEnsoNumberNode,
@Cached SubtractNode delegate) {
return delegate.execute(self, handleInterop(false, self, that, iop, toEnsoNumberNode));
}
@Fallback
double doOther(double self, Object that) {
Builtins builtins = EnsoContext.get(this).getBuiltins();
var number = builtins.number().getNumber();
throw new PanicException(builtins.error().makeTypeError(number, that, "that"), this);
throw panicOtherwise(self, that);
}
}

View File

@ -1,10 +1,9 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@BuiltinMethod(type = "Decimal", name = "to_decimal", description = "Identity on decimals")
public class ToDecimalNode extends Node {
public class ToDecimalNode extends FloatNode {
double execute(double self) {
return self;
}

View File

@ -1,7 +1,6 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.CountingConditionProfile;
import java.math.BigDecimal;
import java.math.BigInteger;
@ -13,7 +12,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
type = "Decimal",
name = "truncate_builtin",
description = "Truncate a floating-point number to an integer by dropping the fractional part.")
public class TruncateNode extends Node {
public class TruncateNode extends FloatNode {
private final CountingConditionProfile fitsProfile = CountingConditionProfile.create();
Object execute(double self) {

View File

@ -2,15 +2,12 @@ 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 = "Integer", name = "abs", description = "Absolute value of a number")
public abstract class AbsNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract class AbsNode extends IntegerNode {
public static AbsNode build() {
return AbsNodeGen.create();
@ -39,6 +36,6 @@ public abstract class AbsNode extends Node {
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
throw throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -1,17 +1,18 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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 class AddNode extends IntegerNode {
public abstract Object execute(Object self, Object that);
@ -55,8 +56,17 @@ public abstract class AddNode extends Node {
return self.asDouble() + that;
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached AddNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -1,16 +1,17 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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 = "bit_and", description = "Bitwise and.")
public abstract class BitAndNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract class BitAndNode extends IntegerNode {
public abstract Object execute(Object self, Object that);
@ -38,8 +39,17 @@ public abstract class BitAndNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.bitAnd(self.getValue(), that.getValue()));
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached BitAndNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -3,12 +3,11 @@ 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 {
public abstract class BitNotNode extends IntegerNode {
abstract Object execute(Object self);
static BitNotNode build() {
@ -28,6 +27,6 @@ public abstract class BitNotNode extends Node {
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
throw throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -1,16 +1,17 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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 = "bit_or", description = "Bitwise or.")
public abstract class BitOrNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract class BitOrNode extends IntegerNode {
abstract Object execute(Object self, Object that);
@ -38,8 +39,17 @@ public abstract class BitOrNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.bitOr(self.getValue(), that.getValue()));
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached BitOrNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -6,19 +6,20 @@ 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.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@ImportStatic(BigIntegerOps.class)
@BuiltinMethod(type = "Integer", name = "bit_shift", description = "Bitwise shift.")
public abstract class BitShiftNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract class BitShiftNode extends IntegerNode {
private final CountingConditionProfile canShiftLeftInLongProfile =
CountingConditionProfile.create();
private final CountingConditionProfile positiveFitsInInt = CountingConditionProfile.create();
@ -124,9 +125,18 @@ public abstract class BitShiftNode extends Node {
}
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached BitShiftNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
boolean hasFreeBitsLeftShift(long number, long shift) {

View File

@ -4,13 +4,15 @@ 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 com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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 = "bit_shift_r", description = "Bitwise right-shift.")
public abstract class BitShiftRightNode extends Node {
public abstract class BitShiftRightNode extends IntegerNode {
abstract Object execute(Object self, Object that);
static BitShiftRightNode build() {
@ -47,8 +49,17 @@ public abstract class BitShiftRightNode extends Node {
return bitShiftNode.execute(self, new EnsoBigInteger(BigIntegerOps.negate(that.getValue())));
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached BitShiftRightNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -1,16 +1,17 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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 = "bit_xor", description = "Bitwise exclusive or.")
public abstract class BitXorNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract class BitXorNode extends IntegerNode {
abstract Object execute(Object self, Object that);
@ -38,8 +39,17 @@ public abstract class BitXorNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.bitXor(self.getValue(), that.getValue()));
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached BitXorNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -2,12 +2,11 @@ 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 {
public abstract class CeilNode extends IntegerNode {
abstract Object execute(Object self);
public static CeilNode build() {
@ -26,6 +25,6 @@ public abstract class CeilNode extends Node {
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
throw throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -1,19 +1,19 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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 = "div", description = "Division of numbers.")
public abstract class DivNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract class DivNode extends IntegerNode {
abstract Object execute(Object self, Object that);
@ -53,8 +53,17 @@ public abstract class DivNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.divide(self.getValue(), that.getValue()));
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached DivNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -1,15 +1,19 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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 = "/", description = "Division of numbers.")
public abstract class DivideNode extends Node {
abstract double execute(Object self, Object that);
public abstract class DivideNode extends IntegerNode {
@Override
abstract Object execute(Object self, Object that);
static DivideNode build() {
return DivideNodeGen.create();
@ -45,8 +49,17 @@ public abstract class DivideNode extends Node {
return BigIntegerOps.toDouble(self.getValue()) / that;
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached DivideNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
double doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
Object doOther(Object self, Object that) {
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -2,12 +2,11 @@ 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 class FloorNode extends IntegerNode {
public abstract Object execute(Object self);
@ -27,6 +26,6 @@ public abstract class FloorNode extends Node {
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
throw throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -1,8 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.EnsoContext;
@ -10,7 +13,7 @@ import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = ">", description = "Comparison of numbers.")
public abstract class GreaterNode extends Node {
public abstract class GreaterNode extends IntegerNode {
abstract Object execute(Object self, Object that);
@ -48,6 +51,15 @@ public abstract class GreaterNode extends Node {
return BigIntegerOps.compare(self.getValue(), that.getValue()) > 0;
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached GreaterNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();

View File

@ -1,8 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.EnsoContext;
@ -10,7 +13,7 @@ import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = ">=", description = "Comparison of numbers.")
public abstract class GreaterOrEqualNode extends Node {
public abstract class GreaterOrEqualNode extends IntegerNode {
abstract Object execute(Object self, Object that);
@ -48,6 +51,15 @@ public abstract class GreaterOrEqualNode extends Node {
return BigIntegerOps.compare(self.getValue(), that.getValue()) >= 0;
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached GreaterOrEqualNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();

View File

@ -0,0 +1,67 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
abstract class IntegerNode extends Node {
@Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
IntegerNode() {}
@TruffleBoundary
final PanicException throwTypeErrorIfNotInt(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();
var intType = builtins.number().getInteger();
var selfType = TypesLibrary.getUncached().getType(self);
if (selfType != intType) {
return new PanicException(builtins.error().makeTypeError(intType, self, "self"), this);
} else {
return new PanicException(builtins.error().makeTypeError(intType, that, "that"), this);
}
}
@TruffleBoundary
final PanicException throwTypeErrorIfNotInt(Object self) {
var builtins = EnsoContext.get(this).getBuiltins();
var intType = builtins.number().getInteger();
return new PanicException(builtins.error().makeTypeError(intType, self, "self"), this);
}
final boolean isForeignNumber(InteropLibrary iop, TruffleObject obj) {
if (obj instanceof EnsoBigInteger) {
return false;
}
return iop.isNumber(obj);
}
final Object doInterop(
Object self, TruffleObject that, InteropLibrary iop, IntegerNode delegate) {
try {
if (iop.fitsInLong(that)) {
return delegate.execute(self, iop.asLong(that));
} else if (iop.fitsInDouble(that)) {
return delegate.execute(self, iop.asDouble(that));
} else if (iop.fitsInBigInteger(that)) {
return delegate.execute(self, toEnsoNumberNode.execute(iop.asBigInteger(that)));
}
} catch (UnsupportedMessageException ex) {
}
return doOther(self, that);
}
Object execute(Object self, Object that) {
throw new AbstractMethodError();
}
Object doOther(Object self, Object that) {
throw new AbstractMethodError();
}
}

View File

@ -1,30 +0,0 @@
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,8 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.EnsoContext;
@ -10,7 +13,7 @@ import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = "<", description = "Comparison of numbers.")
public abstract class LessNode extends Node {
public abstract class LessNode extends IntegerNode {
abstract Object execute(Object self, Object that);
@ -48,6 +51,15 @@ public abstract class LessNode extends Node {
return BigIntegerOps.compare(self.getValue(), that.getValue()) < 0;
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached LessNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();

View File

@ -1,8 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.EnsoContext;
@ -10,8 +13,9 @@ import org.enso.interpreter.runtime.error.DataflowError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = "<=", description = "Comparison of numbers.")
public abstract class LessOrEqualNode extends Node {
public abstract class LessOrEqualNode extends IntegerNode {
@Override
abstract Object execute(Object self, Object that);
static LessOrEqualNode build() {
@ -48,6 +52,15 @@ public abstract class LessOrEqualNode extends Node {
return BigIntegerOps.compare(self.getValue(), that.getValue()) <= 0;
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached LessOrEqualNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
var builtins = EnsoContext.get(this).getBuiltins();

View File

@ -1,20 +1,21 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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();
public abstract class ModNode extends IntegerNode {
abstract Object execute(Object self, Object that);
@ -78,8 +79,17 @@ public abstract class ModNode extends Node {
}
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached ModNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -1,16 +1,17 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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 = "Multiplication of numbers.")
public abstract class MultiplyNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract class MultiplyNode extends IntegerNode {
abstract Object execute(Object self, Object that);
@ -53,8 +54,17 @@ public abstract class MultiplyNode extends Node {
return BigIntegerOps.toDouble(self.getValue()) * that;
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached MultiplyNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -2,15 +2,12 @@ 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 = "Integer", name = "negate", description = "Negation for numbers.")
public abstract class NegateNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract class NegateNode extends IntegerNode {
static NegateNode build() {
return NegateNodeGen.create();
@ -35,6 +32,6 @@ public abstract class NegateNode extends Node {
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
throw throwTypeErrorIfNotInt(self, this);
}
}

View File

@ -1,9 +1,9 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.Node.Child;
import com.oracle.truffle.api.profiles.BranchProfile;
import java.math.BigInteger;
import org.enso.interpreter.dsl.*;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.data.text.Text;
@ -12,8 +12,8 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = "parse", description = """
Parse integer number""", autoRegister = false)
public final class ParseIntegerNode extends Node {
@Node.Child
public final class ParseIntegerNode extends IntegerNode {
@Child
ToJavaStringNode toJavaString = ToJavaStringNode.build();
private final BranchProfile noEx1 = BranchProfile.create();
private final BranchProfile noEx2 = BranchProfile.create();

View File

@ -1,18 +1,21 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node.Child;
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.number.EnsoBigInteger;
@BuiltinMethod(type = "Integer", name = "^", description = "Exponentiation of numbers.")
public abstract class PowNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract class PowNode extends IntegerNode {
private @Child MultiplyNode multiplyNode = MultiplyNode.build();
abstract Object execute(Object self, Object that);
@ -86,8 +89,17 @@ public abstract class PowNode extends Node {
return new EnsoBigInteger(BigInteger.valueOf(self));
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached PowNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -1,6 +1,5 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.profiles.CountingConditionProfile;
import com.oracle.truffle.api.profiles.PrimitiveValueProfile;
@ -11,7 +10,7 @@ import org.enso.interpreter.node.expression.builtin.number.utils.RoundHelpers;
type = "Integer",
name = "round",
description = "Decimal ceiling, converting to a small or big integer depending on size.")
public class RoundNode extends Node {
public class RoundNode extends IntegerNode {
private final CountingConditionProfile fitsProfile = CountingConditionProfile.create();
private final PrimitiveValueProfile constantPlacesDecimalPlaces = PrimitiveValueProfile.create();

View File

@ -1,16 +1,17 @@
package org.enso.interpreter.node.expression.builtin.number.integer;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.CachedLibrary;
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 = "Subtraction of numbers.")
public abstract class SubtractNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.create();
public abstract class SubtractNode extends IntegerNode {
abstract Object execute(Object self, Object that);
@ -53,8 +54,17 @@ public abstract class SubtractNode extends Node {
return BigIntegerOps.toDouble(self.getValue()) - that;
}
@Specialization(guards = "isForeignNumber(iop, that)")
Object doInterop(
Object self,
TruffleObject that,
@CachedLibrary(limit = "3") InteropLibrary iop,
@Cached SubtractNode delegate) {
return super.doInterop(self, that, iop, delegate);
}
@Fallback
Object doOther(Object self, Object that) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, that, this);
throw throwTypeErrorIfNotInt(self, that);
}
}

View File

@ -2,7 +2,6 @@ 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;
@ -11,7 +10,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
type = "Integer",
name = "to_decimal",
description = "Conversion of integers to decimals.")
public abstract class ToDecimalNode extends Node {
public abstract class ToDecimalNode extends IntegerNode {
public abstract Object execute(Object self);
public static ToDecimalNode build() {
@ -30,6 +29,6 @@ public abstract class ToDecimalNode extends Node {
@Fallback
Object doOther(Object self) {
throw IntegerUtils.throwTypeErrorIfNotInt(self, this);
throw throwTypeErrorIfNotInt(self);
}
}

View File

@ -17,6 +17,7 @@ import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.EnsoObject;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.scope.ModuleScope;
import org.graalvm.collections.Pair;
/** Simple runtime value representing a yet-unresolved by-name symbol. */
@ExportLibrary(InteropLibrary.class)
@ -56,32 +57,16 @@ public final class UnresolvedSymbol implements EnsoObject {
* is returned. This is useful for certain subtyping relations, such as "any constructor is a
* subtype of Any" or "Nat is a subtype of Int, is a subtype of Number".
*
* @param node the node that performs the query
* @param type the type for which this symbol should be resolved
* @return the resolved function definition, or null if not found
* @return the resolved function definition and type it was resolved in, or null if not found
*/
public Function resolveFor(Node node, Type type) {
for (var current : type.allTypes(EnsoContext.get(node))) {
Function candidate = scope.lookupMethodDefinition(current, name);
if (candidate != null) {
return candidate;
}
}
return null;
}
/**
* Resolves the type where the symbol is declared.
*
* @param type the type for which this symbol should be resolved
* @return the resolved function definition, or null if not found
*/
public Type resolveDeclaringType(Node node, Type type) {
var ctx = EnsoContext.get(node);
public Pair<Function, Type> resolveFor(Node node, Type type) {
if (type != null) {
for (var current : type.allTypes(ctx)) {
for (var current : type.allTypes(EnsoContext.get(node))) {
Function candidate = scope.lookupMethodDefinition(current, name);
if (candidate != null) {
return current;
return Pair.create(candidate, current);
}
}
}

View File

@ -2,12 +2,21 @@ package org.enso.interpreter.runtime.data;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached.Shared;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import java.math.BigInteger;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.enso.interpreter.node.callable.resolver.MethodResolverNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
@ -16,6 +25,7 @@ import org.graalvm.collections.Pair;
@ExportLibrary(TypesLibrary.class)
@ExportLibrary(InteropLibrary.class)
public final class EnsoMultiValue implements EnsoObject {
@CompilationFinal(dimensions = 1)
private final Type[] types;
@ -52,6 +62,289 @@ public final class EnsoMultiValue implements EnsoObject {
return toString();
}
@ExportMessage
boolean isBoolean(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.isBoolean(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
boolean asBoolean(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.isBoolean(values[i])) {
return iop.asBoolean(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
boolean isString(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.isString(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
String asString(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (Object value : values) {
if (iop.isString(value)) {
return iop.asString(value);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
boolean isNumber(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.isNumber(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
boolean fitsInByte(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInByte(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
boolean fitsInShort(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInShort(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
boolean fitsInInt(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInShort(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
boolean fitsInLong(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInLong(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
boolean fitsInFloat(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInFloat(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
boolean fitsInDouble(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInDouble(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
byte asByte(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInByte(values[i])) {
return iop.asByte(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
short asShort(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInShort(values[i])) {
return iop.asShort(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
int asInt(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInInt(values[i])) {
return iop.asInt(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
long asLong(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInLong(values[i])) {
return iop.asLong(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
float asFloat(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInFloat(values[i])) {
return iop.asFloat(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
double asDouble(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInDouble(values[i])) {
return iop.asDouble(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
boolean fitsInBigInteger(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInBigInteger(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
BigInteger asBigInteger(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.fitsInBigInteger(values[i])) {
return iop.asBigInteger(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
boolean isTime(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.isTime(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
LocalTime asTime(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.isTime(values[i])) {
return iop.asTime(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
boolean isDate(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.isDate(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
LocalDate asDate(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.isDate(values[i])) {
return iop.asDate(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
boolean isTimeZone(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.isTimeZone(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
ZoneId asTimeZone(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.isTimeZone(values[i])) {
return iop.asTimeZone(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@ExportMessage
boolean isDuration(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop) {
for (var i = 0; i < values.length; i++) {
if (iop.isDuration(values[i])) {
return true;
}
}
return false;
}
@ExportMessage
Duration asDuration(@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary iop)
throws UnsupportedMessageException {
for (var i = 0; i < values.length; i++) {
if (iop.isDuration(values[i])) {
return iop.asDuration(values[i]);
}
}
throw UnsupportedMessageException.create();
}
@TruffleBoundary
@Override
public String toString() {
@ -82,12 +375,17 @@ public final class EnsoMultiValue implements EnsoObject {
*/
public final Pair<Function, Type> resolveSymbol(
MethodResolverNode node, UnresolvedSymbol symbol) {
var ctx = EnsoContext.get(node);
Pair<Function, Type> foundAnyMethod = null;
for (Type t : types) {
var fn = node.execute(t, symbol);
if (fn != null) {
return Pair.create(fn, t);
var fnAndType = node.execute(t, symbol);
if (fnAndType != null) {
if (fnAndType.getRight() != ctx.getBuiltins().any()) {
return Pair.create(fnAndType.getLeft(), t);
}
foundAnyMethod = fnAndType;
}
}
return null;
return foundAnyMethod;
}
}

View File

@ -680,43 +680,46 @@ class IrToTruffle(
// === Utility Functions ====================================================
// ==========================================================================
private def extractAscribedType(
name: Name,
t: Expression
): ReadArgumentCheckNode = t match {
case u: `type`.Set.Union =>
ReadArgumentCheckNode.oneOf(
name,
u.operands.map(extractAscribedType(name, _)).asJava
)
case i: `type`.Set.Intersection =>
ReadArgumentCheckNode.allOf(
name,
extractAscribedType(name, i.left),
extractAscribedType(name, i.right)
)
case p: Application.Prefix => extractAscribedType(name, p.function)
case _: Tpe.Function =>
ReadArgumentCheckNode.build(
name,
context.getTopScope().getBuiltins().function()
)
case t => {
t.getMetadata(TypeNames) match {
case Some(
BindingsMap
.Resolution(BindingsMap.ResolvedType(mod, tpe))
) =>
ReadArgumentCheckNode.build(
name,
mod.unsafeAsModule().getScope.getTypes.get(tpe.name)
)
case _ => null
}
}
}
private def checkRuntimeTypes(
arg: DefinitionArgument
): ReadArgumentCheckNode = {
def extractAscribedType(t: Expression): ReadArgumentCheckNode = t match {
case u: `type`.Set.Union =>
ReadArgumentCheckNode.oneOf(
arg.name,
u.operands.map(extractAscribedType).asJava
)
case i: `type`.Set.Intersection =>
ReadArgumentCheckNode.allOf(
arg.name,
extractAscribedType(i.left),
extractAscribedType(i.right)
)
case p: Application.Prefix => extractAscribedType(p.function)
case _: Tpe.Function =>
ReadArgumentCheckNode.build(
arg.name,
context.getTopScope().getBuiltins().function()
)
case t => {
t.getMetadata(TypeNames) match {
case Some(
BindingsMap
.Resolution(BindingsMap.ResolvedType(mod, tpe))
) =>
ReadArgumentCheckNode.build(
arg.name,
mod.unsafeAsModule().getScope.getTypes.get(tpe.name)
)
case _ => null
}
}
}
arg.ascribedType.map(extractAscribedType).getOrElse(null)
arg.ascribedType.map(extractAscribedType(arg.name, _)).getOrElse(null)
}
/** Checks if the expression has a @Builtin_Method annotation
@ -984,7 +987,7 @@ class IrToTruffle(
binding: Boolean,
subjectToInstrumentation: Boolean
): RuntimeExpression = {
val runtimeExpression = ir match {
var runtimeExpression = ir match {
case block: Expression.Block => processBlock(block)
case literal: Literal => processLiteral(literal)
case app: Application =>
@ -1009,8 +1012,20 @@ class IrToTruffle(
s"Foreign expressions not yet implemented: $ir."
)
}
runtimeExpression.setTailStatus(getTailStatus(ir))
ir match {
case _: Expression.Binding =>
case _ =>
val types = ir.getMetadata(TypeSignatures)
types.foreach { tpe =>
val checkNode = extractAscribedType(null, tpe.signature);
if (checkNode != null) {
runtimeExpression =
ReadArgumentCheckNode.wrap(runtimeExpression, checkNode)
}
}
}
runtimeExpression
}

View File

@ -81,7 +81,16 @@ case object GatherDiagnostics extends IRPass {
})
.getOrElse(Nil)
typeSignatureDiagnostics ++ x.diagnostics.toList
case x => x.diagnostics.toList
case x: Expression =>
val typeSignatureDiagnostics =
x.getMetadata(TypeSignatures)
.map(_.signature.preorder.collect { case err: Diagnostic =>
err
})
.getOrElse(Nil)
typeSignatureDiagnostics ++ x.diagnostics.toList
case x =>
x.diagnostics.toList
}.flatten
DiagnosticsMeta(
diagnostics.distinctBy(d => new DiagnosticKeys(d))

View File

@ -45,9 +45,14 @@ case object TypeNames extends IRPass {
val bindingsMap =
ir.unsafeGetMetadata(BindingAnalysis, "bindings analysis did not run")
ir.copy(bindings = ir.bindings.map { d =>
val mapped = d.mapExpressions(resolveExpression(bindingsMap, _))
val typeParams = d match {
case t: Definition.Type => t.params.map(_.name)
case _ => Nil
}
val mapped =
d.mapExpressions(resolveExpression(typeParams, bindingsMap, _))
doResolveType(
Nil,
typeParams,
bindingsMap,
mapped match {
case typ: Definition.Type =>
@ -64,6 +69,7 @@ case object TypeNames extends IRPass {
}
private def resolveExpression(
typeParams: List[Name],
bindingsMap: BindingsMap,
ir: Expression
): Expression = {
@ -71,11 +77,11 @@ case object TypeNames extends IRPass {
val processedIr = ir match {
case fn: Function.Lambda =>
fn.copy(arguments =
fn.arguments.map(doResolveType(Nil, bindingsMap, _))
fn.arguments.map(doResolveType(typeParams, bindingsMap, _))
)
case x => x
}
doResolveType(Nil, bindingsMap, processedIr.mapExpressions(go))
doResolveType(typeParams, bindingsMap, processedIr.mapExpressions(go))
}
go(ir)
}

View File

@ -0,0 +1,125 @@
package org.enso.interpreter.test;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.Stream;
import org.enso.polyglot.MethodNames;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.PolyglotException;
import org.graalvm.polyglot.Value;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import com.google.common.collect.Streams;
@RunWith(Parameterized.class)
public class BinaryOpFloatTest extends TestBase {
private static final String[] OPERATIONS = {
" +", " -", " ^", " *", " %", " <=", " <", " >=", " >", " /"
};
@Parameterized.Parameters(name="({1}){0} ({2})")
public static Object[][] parameters() {
var r = new Random();
var randomOps = Arrays.asList(OPERATIONS).stream().map(
(op) -> new Object[] { op, r.nextDouble(), switch (op) {
case " ^" -> r.nextDouble(10);
case " *" -> r.nextDouble(Integer.MAX_VALUE);
default -> r.nextDouble();
}}
);
var zeroOps = Arrays.asList(OPERATIONS).stream().map(
(op) -> new Object[] { op, r.nextDouble(), 0.0 }
);
var oneOps = Arrays.asList(OPERATIONS).stream().map(
(op) -> new Object[] { op, r.nextDouble(), 1.0 }
);
var extraOps = Stream.of(
new Object[] { " %", 19.73, 12.10 },
new Object[] { " ^", 10.12, 73.19 }
);
return Streams.concat(
randomOps,
zeroOps,
oneOps,
extraOps
).toArray(Object[][]::new);
}
private static Context ctx;
@BeforeClass
public static void initContext() {
ctx = createDefaultContext();
}
@AfterClass
public static void closeContext() {
ctx.close();
}
private final String operation;
private final double n1;
private final double n2;
public BinaryOpFloatTest(String operation, double n1, double n2) {
this.operation = operation;
this.n1 = n1;
this.n2 = n2;
}
@Test
public void verifyOperationOnForeignObject() {
executeInContext(ctx, () -> {
var code = """
fn a b = a{op} b
""".replace("{op}", operation);
var fn = ctx.eval("enso", code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "fn");
var r1 = execute(fn, n1, n2);
var wrap2 = ctx.asValue(new WrappedPrimitive(n2));
var r2 = execute(fn, n1, wrap2);
assertSameResult(r1, r2);
return null;
});
}
private Value execute(Value fn, Object... args) {
try {
return fn.execute(args);
} catch (PolyglotException ex) {
return ex.getGuestObject();
}
}
private void assertSameResult(Value r1, Value r2) {
assertEquals("r1: " + r1 + " r2: " + r2, r1.isException(), r2.isException());
assertEquals("r1: " + r1 + " r2: " + r2, r1.isBoolean(), r2.isBoolean());
assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInLong(), r2.fitsInLong());
assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInDouble(), r2.fitsInDouble());
assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInBigInteger(), r2.fitsInBigInteger());
if (r1.fitsInLong()) {
assertEquals("Results for " + n1 + operation + " " + n2, r1.asLong(), r2.asLong());
} else if (r1.fitsInDouble()) {
assertEquals("Results for " + n1 + operation + " " + n2, r1.asDouble(), r2.asDouble(), 0.1);
} else if (r1.fitsInBigInteger()) {
assertEquals("Results for " + n1 + operation + " " + n2, r1.asBigInteger(), r2.asBigInteger());
} else if (r1.isBoolean()) {
assertEquals("Results for " + n1 + operation + " " + n2, r1.asBoolean(), r2.asBoolean());
} else if (r1.isException()) {
assertTrue("Both are exceptions for " + n1 + operation + " " + n2, r2.isException());
} else {
fail("Doesn't fit: " + r1);
}
}
}

View File

@ -0,0 +1,117 @@
package org.enso.interpreter.test;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.Stream;
import org.enso.polyglot.MethodNames;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import com.google.common.collect.Streams;
@RunWith(Parameterized.class)
public class BinaryOpIntegerTest extends TestBase {
private static final String[] OPERATIONS = {
" +", " -", " ^", " *", " %", " <=", " <", " >=", " >", " /",
".div", ".bit_xor", ".bit_shift", ".bit_shift_r", ".bit_or", ".bit_and"
};
@Parameterized.Parameters(name="({1}){0} ({2})")
public static Object[][] parameters() {
var r = new Random();
var randomOps = Arrays.asList(OPERATIONS).stream().map(
(op) -> new Object[] { op, r.nextLong(), switch (op) {
case " ^" -> r.nextLong(10);
case " *" -> r.nextLong(Integer.MAX_VALUE);
default -> r.nextLong();
}}
);
var zeroOps = Arrays.asList(OPERATIONS).stream().map(
(op) -> new Object[] { op, r.nextLong(), 0 }
);
var oneOps = Arrays.asList(OPERATIONS).stream().map(
(op) -> new Object[] { op, r.nextLong(), 1 }
);
var extraOps = Stream.of(
new Object[] { " %", 19, 73 },
new Object[] { ".bit_shift", 12, 10 }
);
return Streams.concat(
randomOps,
zeroOps,
oneOps,
extraOps
).toArray(Object[][]::new);
}
private static Context ctx;
@BeforeClass
public static void initContext() {
ctx = createDefaultContext();
}
@AfterClass
public static void closeContext() {
ctx.close();
}
private final String operation;
private final long n1;
private final long n2;
public BinaryOpIntegerTest(String operation, long n1, long n2) {
this.operation = operation;
this.n1 = n1;
this.n2 = n2;
}
@Test
public void verifyOperationOnForeignObject() {
executeInContext(ctx, () -> {
var code = """
fn a b = a{op} b
""".replace("{op}", operation);
var fn = ctx.eval("enso", code).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "fn");
var r1 = fn.execute(n1, n2);
var wrap2 = ctx.asValue(new WrappedPrimitive(n2));
var r2 = fn.execute(n1, wrap2);
assertSameResult(r1, r2);
return null;
});
}
private void assertSameResult(Value r1, Value r2) {
assertEquals("r1: " + r1 + " r2: " + r2, r1.isException(), r2.isException());
assertEquals("r1: " + r1 + " r2: " + r2, r1.isBoolean(), r2.isBoolean());
assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInLong(), r2.fitsInLong());
assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInDouble(), r2.fitsInDouble());
assertEquals("r1: " + r1 + " r2: " + r2, r1.fitsInBigInteger(), r2.fitsInBigInteger());
if (r1.fitsInLong()) {
assertEquals("Results for " + n1 + operation + " " + n2, r1.asLong(), r2.asLong());
} else if (r1.fitsInDouble()) {
assertEquals("Results for " + n1 + operation + " " + n2, r1.asDouble(), r2.asDouble(), 0.1);
} else if (r1.fitsInBigInteger()) {
assertEquals("Results for " + n1 + operation + " " + n2, r1.asBigInteger(), r2.asBigInteger());
} else if (r1.isBoolean()) {
assertEquals("Results for " + n1 + operation + " " + n2, r1.asBoolean(), r2.asBoolean());
} else if (r1.isException()) {
assertTrue("Both are exceptions for " + n1 + operation + " " + n2, r2.isException());
} else {
fail("Doesn't fit: " + r1);
}
}
}

View File

@ -1,20 +1,5 @@
package org.enso.interpreter.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import com.oracle.truffle.api.debug.DebugException;
import com.oracle.truffle.api.debug.DebugScope;
import com.oracle.truffle.api.debug.DebugStackFrame;
import com.oracle.truffle.api.debug.DebugValue;
import com.oracle.truffle.api.debug.Debugger;
import com.oracle.truffle.api.debug.DebuggerSession;
import com.oracle.truffle.api.debug.SuspendedCallback;
import com.oracle.truffle.api.debug.SuspendedEvent;
import com.oracle.truffle.api.nodes.LanguageInfo;
import java.io.OutputStream;
import java.net.URI;
import java.nio.file.Paths;
@ -29,6 +14,7 @@ import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.enso.polyglot.MethodNames.Module;
import org.enso.polyglot.RuntimeOptions;
import org.graalvm.polyglot.Context;
@ -39,9 +25,24 @@ import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.io.IOAccess;
import org.junit.After;
import org.junit.Assert;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import com.oracle.truffle.api.debug.DebugException;
import com.oracle.truffle.api.debug.DebugScope;
import com.oracle.truffle.api.debug.DebugStackFrame;
import com.oracle.truffle.api.debug.DebugValue;
import com.oracle.truffle.api.debug.Debugger;
import com.oracle.truffle.api.debug.DebuggerSession;
import com.oracle.truffle.api.debug.SuspendedCallback;
import com.oracle.truffle.api.debug.SuspendedEvent;
import com.oracle.truffle.api.nodes.LanguageInfo;
public class DebuggingEnsoTest {
private Context context;
private Engine engine;
@ -107,6 +108,8 @@ public class DebuggingEnsoTest {
}
private Value createEnsoMethod(String source, String methodName) {
Value m = context.eval(createEnsoSource("from Standard.Base import all\n\n" + methodName + " = 10"));
m.invokeMember(Module.EVAL_EXPRESSION, methodName);
Value module = context.eval(createEnsoSource(source));
return module.invokeMember(Module.EVAL_EXPRESSION, methodName);
}
@ -118,8 +121,8 @@ public class DebuggingEnsoTest {
@Test
public void recursiveFactorialCall() {
final Value facFn = createEnsoMethod("""
from Standard.Base.Data.Ordering import all
from Standard.Base import all
fac : Number -> Number
fac n =
facacc : Number -> Number -> Number
@ -156,7 +159,7 @@ public class DebuggingEnsoTest {
bar arg_bar =
loc_bar = arg_bar + 1
loc_bar
foo x =
loc_foo = 1
bar loc_foo
@ -195,7 +198,7 @@ public class DebuggingEnsoTest {
Value fooFunc = createEnsoMethod("""
polyglot java import java.nio.file.Path
polyglot java import java.util.ArrayList
foo x =
path = Path.of 'blaaaaa'
list = ArrayList.new
@ -231,7 +234,7 @@ public class DebuggingEnsoTest {
public void testHostValueAsAtomField() {
Value fooFunc = createEnsoMethod("""
from Standard.Base import Vector
foo x =
vec_builder = Vector.new_builder
end = 42
@ -256,7 +259,7 @@ public class DebuggingEnsoTest {
public void testEvaluateExpression() {
Value fooFunc = createEnsoMethod("""
polyglot java import java.nio.file.Path
foo x =
a = 10
b = 20
@ -323,7 +326,7 @@ public class DebuggingEnsoTest {
Value fooFunc = createEnsoMethod("""
bar =
loc_bar = 42
foo x =
a = 10 # Will get modified to 1
b = 20 # Will get modified to 2
@ -480,10 +483,10 @@ public class DebuggingEnsoTest {
public void testSteppingOverUseStdLib() {
Source src = createEnsoSource("""
from Standard.Base import Vector
bar vec num_elems =
vec.slice 0 num_elems
foo x =
vec_builder = Vector.new_builder
vec_builder.append 1

View File

@ -3,6 +3,13 @@ package org.enso.interpreter.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
@ -10,9 +17,11 @@ import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
import org.enso.interpreter.node.expression.builtin.meta.EqualsNode;
import org.enso.interpreter.node.expression.builtin.meta.EqualsNodeGen;
import org.enso.polyglot.MethodNames;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import org.junit.AfterClass;
@ -189,4 +198,91 @@ public class EqualsTest extends TestBase {
return null;
});
}
@Test
public void testTruffleNumberLong() {
var ensoNumber = unwrapValue(context, createValue(context, "1", ""));
var foreignNumber = new WrappedPrimitive(1);
executeInContext(
context,
() -> {
assertTrue(equalsNode.execute(ensoNumber, foreignNumber.asDirect()));
assertTrue(equalsNode.execute(ensoNumber, foreignNumber));
assertTrue(equalsNode.execute(foreignNumber, ensoNumber));
return null;
});
}
@Test
public void testTruffleNumberDouble() {
var ensoNumber = unwrapValue(context, createValue(context, "1.0", ""));
var foreignNumber = new WrappedPrimitive(1.0);
executeInContext(
context,
() -> {
assertTrue(equalsNode.execute(ensoNumber, foreignNumber.asDirect()));
assertTrue(equalsNode.execute(ensoNumber, foreignNumber));
assertTrue(equalsNode.execute(foreignNumber, ensoNumber));
return null;
});
}
@Test
public void testTruffleNumberBigInt() {
var value = new BigInteger("43207431473298432194374819743291479009431478329");
var ensoNumber = unwrapValue(context, createValue(context, value.toString(), ""));
var foreignNumber = new WrappedPrimitive(value);
executeInContext(
context,
() -> {
assertTrue(equalsNode.execute(ensoNumber, foreignNumber));
assertTrue(equalsNode.execute(foreignNumber, ensoNumber));
return null;
});
}
@Test
public void testTruffleBoolean() {
var ensoBoolean =
unwrapValue(context, createValue(context, "True", "from Standard.Base import True"));
var foreignBoolean = new WrappedPrimitive(true);
executeInContext(
context,
() -> {
assertTrue(equalsNode.execute(ensoBoolean, foreignBoolean.asDirect()));
assertTrue(equalsNode.execute(ensoBoolean, foreignBoolean));
assertTrue(equalsNode.execute(foreignBoolean, ensoBoolean));
return null;
});
}
@Test
public void testTruffleString() {
var ensoText = unwrapValue(context, createValue(context, "'Hello'", ""));
var foreignString = new WrappedPrimitive("Hello");
executeInContext(
context,
() -> {
assertTrue(equalsNode.execute(ensoText, foreignString.asDirect()));
assertTrue(equalsNode.execute(ensoText, foreignString));
assertTrue(equalsNode.execute(foreignString, ensoText));
return null;
});
}
@Test
public void testTruffleNumberPlus() {
var plus100 = context.eval("enso", """
plus100 x = 100+x
""").invokeMember(MethodNames.Module.EVAL_EXPRESSION, "plus100");
assertTrue("plus100 can be executed", plus100.canExecute());
var foreignNumber = context.asValue(new WrappedPrimitive(42));
var hundred42 = unwrapValue(context, plus100.execute(foreignNumber));
executeInContext(context,
() -> {
assertTrue(equalsNode.execute(142L, hundred42));
assertTrue(equalsNode.execute(hundred42, 142L));
return null;
});
}
}

View File

@ -49,6 +49,42 @@ public class SignatureTest extends TestBase {
}
}
@Test
public void wrongLiteralSignature() throws Exception {
final URI uri = new URI("memory://literal_signature.enso");
final Source src = Source.newBuilder("enso", """
neg a = 0 - a:Xyz
""",uri.getAuthority())
.uri(uri)
.buildLiteral();
try {
var module = ctx.eval(src);
var neg = module.invokeMember("eval_expression", "neg").execute(-1);
fail("Expecting an exception from compilation, not: " + neg);
} catch (PolyglotException e) {
assertTrue("It is a syntax error exception", e.isSyntaxError());
}
}
@Test
public void wrongExpressionSignature() throws Exception {
final URI uri = new URI("memory://exp_signature.enso");
final Source src = Source.newBuilder("enso", """
neg a = (0 - a):Xyz
""",uri.getAuthority())
.uri(uri)
.buildLiteral();
try {
var module = ctx.eval(src);
var neg = module.invokeMember("eval_expression", "neg").execute(-1);
fail("Expecting an exception from compilation, not: " + neg);
} catch (PolyglotException e) {
assertTrue("It is a syntax error exception", e.isSyntaxError());
}
}
@Test
public void wrongAscribedTypeSignature() throws Exception {
final URI uri = new URI("memory://neg.enso");
@ -621,10 +657,9 @@ public class SignatureTest extends TestBase {
self.dict.mul self.value that.value
compute (a : Plus & Mul) (b : Plus & Mul) =
add (x:Plus) (y:Plus) = x+y
p = add a b
p = a+b
m = a*b
add p m
p:Plus + m:Plus
type BooleanPlus
plus a:Boolean b:Boolean = a || b

View File

@ -0,0 +1,145 @@
package org.enso.interpreter.test;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import java.math.BigInteger;
@ExportLibrary(InteropLibrary.class)
final class WrappedPrimitive implements TruffleObject {
private final Object value;
WrappedPrimitive(long value) {
this.value = value;
}
WrappedPrimitive(boolean value) {
this.value = value;
}
WrappedPrimitive(double value) {
this.value = value;
}
WrappedPrimitive(BigInteger value) {
this.value = value;
}
WrappedPrimitive(String value) {
this.value = value;
}
@ExportMessage
boolean isString() {
return value instanceof String;
}
@ExportMessage
String asString() {
return (String) value;
}
@ExportMessage
boolean isNumber() {
return value instanceof Number;
}
@ExportMessage
boolean isBoolean() {
return value instanceof Boolean;
}
@ExportMessage
boolean asBoolean() {
return (Boolean) value;
}
@ExportMessage
boolean fitsInByte() {
return false;
}
@ExportMessage
boolean fitsInShort() {
return false;
}
@ExportMessage
boolean fitsInInt() {
return false;
}
@ExportMessage
boolean fitsInLong() {
return value instanceof Long;
}
@ExportMessage
boolean fitsInFloat() {
return false;
}
@ExportMessage
boolean fitsInDouble() {
return value instanceof Double;
}
@ExportMessage
byte asByte() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}
@ExportMessage
short asShort() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}
@ExportMessage
int asInt() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}
@ExportMessage
long asLong() throws UnsupportedMessageException {
return (Long) value;
}
@ExportMessage
float asFloat() throws UnsupportedMessageException {
throw UnsupportedMessageException.create();
}
@ExportMessage
double asDouble() throws UnsupportedMessageException {
return (Double) value;
}
@ExportMessage
boolean fitsInBigInteger() {
return value instanceof BigInteger;
}
@ExportMessage
BigInteger asBigInteger() throws UnsupportedMessageException {
return (BigInteger) value;
}
@ExportMessage
String toDisplayString(boolean ignore) {
return toString();
}
Object asDirect() {
return value;
}
@TruffleBoundary
@Override
public String toString() {
return "WrappedPrimitive[" + value + "]";
}
}

View File

@ -246,7 +246,7 @@ object DistributionPackage {
throw new RuntimeException(s"Cannot compile $libMajor.$libName.")
}
} else {
log.info(s"No modified files. Not generating index for ${libName} ")
log.debug(s"No modified files. Not generating index for ${libName}.")
}
}
}

View File

@ -55,6 +55,16 @@ foreign js call_function fn arg_1 = """
Number.foo self = "foo called"
from Standard.Base import all
type Fool
Value fool
to_text : Text
to_text self = "{FOOL " + self.fool.to_text + "}"
Fool.from (that : Any) = Fool.Value that
spec =
Test.group "Conversion" <|
Test.specify "should be able to convert atoms" <|
@ -202,6 +212,145 @@ spec =
to_6 (v : Number & Decimal & Integer) = v
to_6 m . should_equal 1.5
Test.specify "Requesting Integer & Fool" <|
do_number (x : Integer & Fool) =
x.foo . should_equal "foo called"
x.fool . should_equal 42
x==x . should_be_true
(x:Integer)==42 . should_be_true
(x:Fool)==42 . should_be_false
x==42 . should_be_true
42==(x.to Integer) . should_be_true
42==(x.to Fool) . should_be_false
42==x . should_be_true
100+(x:Integer) . should_equal 142
(x:Integer)+100 . should_equal 142
x+100 . should_equal 142
100+x . should_equal 142
x.to_text . should_equal "{FOOL 42}"
(x:Fool).to_text . should_equal "{FOOL 42}"
(x:Integer).to_text . should_equal "42"
do_number 42
Test.specify "Requesting Decimal & Fool" <|
do_number (x : Decimal & Fool) =
x.foo . should_equal "foo called"
x.fool . should_equal 42.3
x==x . should_be_true
(x:Decimal)==42.3 . should_be_true
(x:Fool)==42.3 . should_be_false
x==42.3 . should_be_true
42.3==(x.to Decimal) . should_be_true
42.3==(x.to Fool) . should_be_false
42.3==x . should_be_true
100+(x:Decimal) . should_equal 142.3
(x:Decimal)+100 . should_equal 142.3
x+100 . should_equal 142.3
100+x . should_equal 142.3
x.to_text . should_equal "{FOOL 42.3}"
(x:Fool).to_text . should_equal "{FOOL 42.3}"
(x:Decimal).to_text . should_equal "42.3"
do_number 42.3
Test.specify "Requesting Boolean & Fool" <|
do_boolean (x : Boolean & Fool) =
x.fool . should_equal True
x==x . should_be_true
(x:Boolean) . should_be_true
(x:Fool)==True . should_be_false
x==True . should_be_true
True==(x:Boolean) . should_be_true
True==(x:Fool) . should_be_false
True==x . should_be_true
x.to_text . should_equal "{FOOL True}"
(x:Fool).to_text . should_equal "{FOOL True}"
(x:Boolean).to_text . should_equal "True"
Panic.recover Any (x:Integer).to_text . should_fail_with Type_Error
do_boolean True
Test.specify "Requesting Text & Fool" <|
do_text (x : Text & Fool) =
x.fool . should_equal "Hello"
x==x . should_be_true
(x:Text)=="Hello" . should_be_true
(x:Fool)=="Hello" . should_be_false
x=="Hello" . should_be_true
"Hello"==(x:Text) . should_be_true
"Hello"==(x:Fool) . should_be_false
"Hello"==x . should_be_true
x.to_text . should_equal "Hello"
(x:Fool).to_text . should_equal "{FOOL Hello}"
(x:Text).to_text . should_equal "Hello"
Panic.recover Any (x:Boolean).to_text . should_fail_with Type_Error
do_text "Hello"
Test.specify "Requesting Time_Of_Day & Fool" <|
now = Time_Of_Day.now
do_time (x : Time_Of_Day & Fool) =
x.fool . should_equal now
x==x . should_be_true
(x:Time_Of_Day)==now . should_be_true
(x:Fool)==now . should_be_false
x==now . should_be_true
now==(x:Time_Of_Day) . should_be_true
now==(x:Fool) . should_be_false
now==x . should_be_true
x.to_text . should_equal now.to_text
do_time now
Test.specify "Requesting Date & Fool" <|
now = Date.today
do_date (x : Date & Fool) =
x.fool . should_equal now
x==x . should_be_true
(x:Date)==now . should_be_true
(x:Fool)==now . should_be_false
x==now . should_be_true
now==(x:Date) . should_be_true
now==(x:Fool) . should_be_false
now==x . should_be_true
x.to_text . should_equal "{FOOL "+now.to_text+"}"
do_date now
Test.specify "Requesting Date_Time & Fool" <|
now = Date_Time.now
do_time (x : Date_Time & Fool) =
x.fool . should_equal now
x==x . should_be_true
(x:Date_Time)==now . should_be_true
(x:Fool)==now . should_be_false
x==now . should_be_true
now==(x:Date_Time) . should_be_true
now==(x:Fool) . should_be_false
now==x . should_be_true
x.to_text . should_equal now.to_text
do_time now
Test.specify "Requesting Duration & Fool" <|
now = Duration.new hours=5
do_duration (x : Duration & Fool) =
x.fool . should_equal now
x==x . should_be_true
(x:Duration)==now . should_be_true
(x:Fool)==now . should_be_false
x==now . should_be_true
now==(x:Duration) . should_be_true
now==(x:Fool) . should_be_false
now==x . should_be_true
x.to_text . should_equal "{FOOL "+now.to_text+"}"
do_duration now
Hello.from (that:Foo) suffix=" " = Hello.Say <| (that.foo.to_case Case.Upper) + suffix
Hello.from (that:Bar) suffix="!" = Hello.Say <| (that.bar.to_case Case.Lower) + suffix