Decimal Numbers (#1146)

This commit is contained in:
Marcin Kostrzewa 2020-09-15 15:05:21 +02:00 committed by GitHub
parent 9666d9065e
commit e38d1ab521
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 1682 additions and 51 deletions

View File

@ -26,11 +26,6 @@ Number.times = act ->
res = here.reverse_list (go Nil this) res = here.reverse_list (go Nil this)
res res
zeropad number =
txt = number.to_text
if number % 10 == number then "00" + txt else
if number % 100 == number then "0" + txt else txt
measure = ~act -> label -> iter_size -> num_iters -> measure = ~act -> label -> iter_size -> num_iters ->
single_call = _ -> single_call = _ ->
x1 = System.nano_time x1 = System.nano_time
@ -41,6 +36,6 @@ measure = ~act -> label -> iter_size -> num_iters ->
act_it_num = num_iters - it_num act_it_num = num_iters - it_num
res = iter_size.times single_call res = iter_size.times single_call
avg = here.avg_list res avg = here.avg_list res
fmt = (avg / 1000000).to_text + "." + here.zeropad ((avg / 1000) % 1000) fmt = (avg / 1000000).format "%.2f"
IO.println (label + "/iteration:" + act_it_num.to_text + ": " + fmt + "ms") IO.println (label + "/iteration:" + act_it_num.to_text + ": " + fmt + "ms")
num_iters.times iteration num_iters.times iteration

View File

@ -1,11 +1,13 @@
import Base.List import Base.List
import Base.Vector import Base.Vector
from Builtins import Number, Unit import Base.Number.Extensions
from Builtins import Unit, Number, Integer
from Builtins export all from Builtins export all
from Base.List export Nil, Cons from Base.List export Nil, Cons
from Base.Vector export Vector from Base.Vector export Vector
from Base.Number.Extensions export all hiding Math
## Represents a right-exclusive range of integer values. ## Represents a right-exclusive range of integer values.
type Range type Range
@ -42,5 +44,9 @@ type Range
res = it initial this.start this.end res = it initial this.start this.end
res res
## Creates a new right-exclusive range of integers from `this` to `n`. type Math
Number.upto n = Range this n
## The mathematical constant pi, equal to the ratio of a circle circumference
to its diameter.
Math.pi : Decimal
Math.pi = 3.141592653589793

View File

@ -0,0 +1,85 @@
from Base import all
polyglot java import java.lang.Math
polyglot java import java.lang.String
## Computes the inverse of the sine function
Selects a value in the -pi/2 through pi/2 range.
Number.asin : Decimal
Number.asin = Math.asin [this.to_decimal]
## Computes the inverse of the cosine function.
Selects a value in the -pi/2 through pi/2 range.
Number.acos : Decimal
Number.acos = Math.acos [this.to_decimal]
## Computes the inverse of the tangent function.
Selects a value in the -pi/2 through pi/2 range.
Number.atan : Decimal
Number.atan = Math.atan [this.to_decimal]
## Computes the argument (angle) in the conversion from cartesian
to polar coordinates.
The returned angle is in the -pi through pi range.
Number.atan_2 : Number -> Decimal
Number.atan_2 y = Math.atan2 [this.to_decimal, y.to_decimal]
## Computes the sine function.
Number.sin : Decimal
Number.sin = Math.sin [this.to_decimal]
## Computes the cosine function.
Number.cos : Decimal
Number.cos = Math.cos [this.to_decimal]
## Computes the tangent function.
Number.tan : Decimal
Number.tan = Math.tan [this.to_decimal]
## Computes the hyperbolic sine function.
Number.sinh : Decimal
Number.sinh = Math.sinh [this.to_decimal]
## Computes the hyperbolic cosine function.
Number.cosh : Decimal
Number.cosh = Math.cosh [this.to_decimal]
## Computes the hyperbolic tangent function.
Number.tanh : Decimal
Number.tanh = Math.tanh [this.to_decimal]
## Computes the exponential function.
Number.exp : Decimal
Number.exp = Math.exp [this.to_decimal]
## Computes the natural logarithm function.
Number.ln : Decimal
Number.ln = Math.log [this.to_decimal]
## Computes the square root of `this`.
Number.sqrt : Decimal
Number.sqrt = Math.sqrt [this.to_decimal]
## Computes the `base`-log of `this`.
Number.log : Number -> Decimal
Number.log base = this.ln / base.ln
## Converts a decimal value to a string, using the Java string formatting
syntax.
TODO this should expose a more-user friendly API in the future.
Decimal.format : Text -> Text
Decimal.format fmt = String.format [fmt, this]
## Creates a new right-exclusive range of integers from `this` to `n`.
Integer.upto : Integer -> Range
Integer.upto n = Range this n
## Checks equality of numbers, using an `epsilon` value.
Returns `True` when `this` and `that` are at most `epsilon` apart.
Number.equals : Number -> Number -> Boolean
Number.equals that epsilon = (this - that).abs <= epsilon

View File

@ -1,5 +1,4 @@
import Base.List from Base import all
from Builtins import all
## The top-level entry point for a test suite. ## The top-level entry point for a test suite.
type Suite specs type Suite specs
@ -38,6 +37,13 @@ Any.should_equal that = case this == that of
msg = this.to_text + " did not equal " + that.to_text + "." msg = this.to_text + " did not equal " + that.to_text + "."
Panic.throw (Failure msg) Panic.throw (Failure msg)
## Asserts that `this` is within `epsilon` from `that`.
Decimal.should_equal that (epsilon = 0) = case this.equals that epsilon of
True -> Success
False ->
msg = this.to_text + " did not equal " + that.to_text + "."
Panic.throw (Failure msg)
## Asserts that the given `Boolean` is `True` ## Asserts that the given `Boolean` is `True`
Boolean.should_be_true = case this of Boolean.should_be_true = case this of
True -> Success True -> Success

66
docs/semantics/numbers.md Normal file
View File

@ -0,0 +1,66 @@
---
layout: developer-doc
title: Numbers
category: semantics
tags: [semantics, runtime, number]
order: 8
---
# Numbers
In order to enhance the user experience, Enso provides a number hierarchy,
encompassing both integers of unbound size and floating-point decimals.
<!-- MarkdownTOC levels="2,3" autolink="true" -->
- [Number Types](#number-types)
- [Internal Representation](#internal-representation)
- [Type Conversions](#type-conversions)
<!-- /MarkdownTOC -->
## Number Types
The base number type in Enso is `Number`. It includes both integers and
floating-point numbers and is the basic type that should be used whenever
numerical computations are performed. Any method defined on the type `Number` is
automatically available on all types of numeric values.
The hierarchy is further split into the `Integer` and `Decimal` types. `Integer`
is capable of representing values of unbound length. `Decimal` is capable of
representing IEEE 64-bit (double precision) floating numbers.
Any method defined on `Integer` is available for all integers, while any method
defined on `Decimal` is available on all floating-point numbers. Methods defined
on `Integer` or `Decimal` take precedence over methods defined on `Number`, when
name resolution is performed.
## Internal Representation
Integers that can be represented in a 64-bit integer type are represented as
such. When a 64-bit representation would overflow (either by the result of
creating a large number literal or an arithmetic operation), it is represented
in a Java `BigInteger` type, thus becoming significantly slower than the 64-bit
representation.
Decimals are represented using the Java `double` type.
## Type Conversions
Number literals that do not contain a decimal point, are treated as integers.
Other literals are interpreted as decimals (even if the fractional part is 0).
Any arithmetic operation where at least one of the operands is a decimal will
result in a decimal result.
Moreover, the default division operator `/` is implemented as floating-point
division and always returns a decimal. If the desired behavior is integral
division instead, the `Integer.div` method implements it.
Another operator worth noting is the exponentiation operator (`^`). It will
always result in a decimal whenever either operand is decimal or the exponent is
negative. It will also return a float result when the exponent is outside the
64-bit integer range.
There is a `Number.to_decimal` method, that allows converting any number to a
decimal. This is useful in certain high-performance and polyglot applications.

View File

@ -97,6 +97,16 @@ public abstract class MethodResolverNode extends Node {
return function; return function;
} }
@Specialization(guards = "cachedSymbol == symbol")
Function resolveDouble(
UnresolvedSymbol symbol,
double self,
@Cached(value = "symbol", allowUncached = true) UnresolvedSymbol cachedSymbol,
@Cached(value = "resolveMethodOnDouble(cachedSymbol)", allowUncached = true)
Function function) {
return function;
}
@Specialization(guards = {"cachedSymbol == symbol", "function != null"}) @Specialization(guards = {"cachedSymbol == symbol", "function != null"})
Function resolveBoolean( Function resolveBoolean(
UnresolvedSymbol symbol, UnresolvedSymbol symbol,
@ -220,6 +230,14 @@ public abstract class MethodResolverNode extends Node {
symbol); symbol);
} }
Function resolveMethodOnDouble(UnresolvedSymbol symbol) {
Number number = getBuiltins().number();
return ensureMethodExists(
symbol.resolveFor(number.getDecimal(), number.getNumber(), getBuiltins().any()),
"Decimal",
symbol);
}
@CompilerDirectives.TruffleBoundary @CompilerDirectives.TruffleBoundary
Function resolveMethodOnPrimBoolean(UnresolvedSymbol symbol, Context context) { Function resolveMethodOnPrimBoolean(UnresolvedSymbol symbol, Context context) {
Bool bool = context.getBuiltins().bool(); Bool bool = context.getBuiltins().bool();

View File

@ -0,0 +1,55 @@
package org.enso.interpreter.node.expression.builtin.interop.syntax;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.ReportPolymorphism;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
/**
* Converts a value returned by a polyglot call back to a value that can be further used within Enso
* programs.
*/
@ReportPolymorphism
public abstract class HostValueToEnsoNode extends Node {
public static HostValueToEnsoNode build() {
return HostValueToEnsoNodeGen.create();
}
/**
* Converts an arbitrary value to a value usable within Enso code.
*
* @param o the value to convert.
* @return the Enso counterpart of the value.
*/
public abstract Object execute(Object o);
@Specialization
double doFloat(float f) {
return f;
}
@Specialization
long doInt(int i) {
return i;
}
@Specialization
long doShort(short i) {
return i;
}
@Specialization
long doByte(byte i) {
return i;
}
@Specialization
long doChar(char i) {
return i;
}
@Fallback
Object doOther(Object o) {
return o;
}
}

View File

@ -1,9 +1,6 @@
package org.enso.interpreter.node.expression.builtin.interop.syntax; package org.enso.interpreter.node.expression.builtin.interop.syntax;
import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.ReportPolymorphism;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.*; import com.oracle.truffle.api.interop.*;
import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.NodeInfo;
@ -17,6 +14,7 @@ import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo; import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.error.PanicException; import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.scope.ModuleScope;
import org.enso.interpreter.runtime.state.Stateful; import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen; import org.enso.interpreter.runtime.type.TypesGen;
@ -29,6 +27,7 @@ public abstract class MethodDispatchNode extends BuiltinRootNode {
private @Child InteropLibrary library = private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private @Child HostValueToEnsoNode hostValueToEnsoNode = HostValueToEnsoNode.build();
private final BranchProfile err = BranchProfile.create(); private final BranchProfile err = BranchProfile.create();
private @Child InvokeCallableNode invokeCallableNode = private @Child InvokeCallableNode invokeCallableNode =
@ -53,12 +52,12 @@ public abstract class MethodDispatchNode extends BuiltinRootNode {
* @param frame current execution frame. * @param frame current execution frame.
* @return the result of converting input into a string. * @return the result of converting input into a string.
*/ */
@Specialization(guards = "symbol == cachedSymbol") @Specialization(guards = "symbol.getScope() == cachedScope")
public Stateful run( public Stateful run(
VirtualFrame frame, VirtualFrame frame,
@Bind("getSymbol(frame)") UnresolvedSymbol symbol, @Bind("getSymbol(frame)") UnresolvedSymbol symbol,
@Cached("symbol") UnresolvedSymbol cachedSymbol, @Cached("symbol.getScope()") ModuleScope cachedScope,
@Cached("buildToArray(cachedSymbol)") UnresolvedSymbol toArray) { @Cached("buildToArray(cachedScope)") UnresolvedSymbol toArray) {
Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments()); Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object callable = args[0]; Object callable = args[0];
Object state = Function.ArgumentsHelper.getState(frame.getArguments()); Object state = Function.ArgumentsHelper.getState(frame.getArguments());
@ -66,7 +65,8 @@ public abstract class MethodDispatchNode extends BuiltinRootNode {
Stateful casted = invokeCallableNode.execute(toArray, frame, state, new Object[] {arguments}); Stateful casted = invokeCallableNode.execute(toArray, frame, state, new Object[] {arguments});
try { try {
Object[] castedArgs = TypesGen.expectArray(casted.getValue()).getItems(); Object[] castedArgs = TypesGen.expectArray(casted.getValue()).getItems();
Object res = library.invokeMember(callable, symbol.getName(), castedArgs); Object res =
hostValueToEnsoNode.execute(library.invokeMember(callable, symbol.getName(), castedArgs));
return new Stateful(casted.getState(), res); return new Stateful(casted.getState(), res);
} catch (UnsupportedMessageException } catch (UnsupportedMessageException
| ArityException | ArityException
@ -78,8 +78,14 @@ public abstract class MethodDispatchNode extends BuiltinRootNode {
} }
} }
UnresolvedSymbol buildToArray(UnresolvedSymbol originalSymbol) { @Specialization
return UnresolvedSymbol.build("to_array", originalSymbol.getScope()); public Stateful runUncached(VirtualFrame frame) {
UnresolvedSymbol sym = getSymbol(frame);
return run(frame, sym, sym.getScope(), buildToArray(sym.getScope()));
}
UnresolvedSymbol buildToArray(ModuleScope scope) {
return UnresolvedSymbol.build("to_array", scope);
} }
UnresolvedSymbol getSymbol(VirtualFrame frame) { UnresolvedSymbol getSymbol(VirtualFrame frame) {

View File

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

View File

@ -29,6 +29,11 @@ public abstract class AddNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.add(_this.getValue(), that.getValue())); return toEnsoNumberNode.execute(BigIntegerOps.add(_this.getValue(), that.getValue()));
} }
@Specialization
double doDouble(EnsoBigInteger _this, double that) {
return BigIntegerOps.toDouble(_this.getValue()) + that;
}
@Fallback @Fallback
Object doOther(EnsoBigInteger _this, Object that) { Object doOther(EnsoBigInteger _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.+", this); throw new TypeError("Unexpected type provided for argument `that` in Integer.+", this);

View File

@ -0,0 +1,36 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "div", description = "Big integer integral division.")
public abstract class DivNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build();
abstract Object execute(EnsoBigInteger _this, Object that);
static DivNode build() {
return DivNodeGen.create();
}
@Specialization
Object doLong(EnsoBigInteger _this, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.divide(_this.getValue(), that));
}
@Specialization
Object doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.divide(_this.getValue(), that.getValue()));
}
@Fallback
Object doOther(EnsoBigInteger _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.div", this);
}
}

View File

@ -5,32 +5,34 @@ import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod; 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.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger; import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "/", description = "Big integer division.") @BuiltinMethod(type = "Big_Integer", name = "/", description = "Big integer division.")
public abstract class DivideNode extends Node { public abstract class DivideNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); abstract double execute(EnsoBigInteger _this, Object that);
abstract Object execute(EnsoBigInteger _this, Object that);
static DivideNode build() { static DivideNode build() {
return DivideNodeGen.create(); return DivideNodeGen.create();
} }
@Specialization @Specialization
Object doLong(EnsoBigInteger _this, long that) { double doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.divide(_this.getValue(), that)); return BigIntegerOps.toDouble(_this.getValue()) / BigIntegerOps.toDouble(that.getValue());
} }
@Specialization @Specialization
Object doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) { double doLong(EnsoBigInteger _this, long that) {
return toEnsoNumberNode.execute(BigIntegerOps.divide(_this.getValue(), that.getValue())); return BigIntegerOps.toDouble(_this.getValue()) / that;
}
@Specialization
double doDouble(EnsoBigInteger _this, double that) {
return BigIntegerOps.toDouble(_this.getValue()) / that;
} }
@Fallback @Fallback
Object doOther(EnsoBigInteger _this, Object that) { double doOther(EnsoBigInteger _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer./", this); throw new TypeError("Unexpected type provided for argument `that` in Integer./", this);
} }
} }

View File

@ -21,6 +21,11 @@ public abstract class EqualsNode extends Node {
return BigIntegerOps.equals(_this.getValue(), that.getValue()); return BigIntegerOps.equals(_this.getValue(), that.getValue());
} }
@Specialization
boolean doDouble(EnsoBigInteger _this, double that) {
return BigIntegerOps.toDouble(_this.getValue()) == that;
}
@Fallback @Fallback
boolean doOther(EnsoBigInteger _this, Object that) { boolean doOther(EnsoBigInteger _this, Object that) {
return false; return false;

View File

@ -0,0 +1,39 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = ">", description = "Comparison of numbers.")
public abstract class GreaterNode extends Node {
abstract boolean execute(EnsoBigInteger _this, Object that);
static GreaterNode build() {
return GreaterNodeGen.create();
}
@Specialization
boolean doDouble(EnsoBigInteger _this, double that) {
return BigIntegerOps.toDouble(_this.getValue()) > that;
}
@Specialization
boolean doLong(EnsoBigInteger _this, long that) {
return _this.getValue().signum() > 0;
}
@Specialization
boolean doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) {
return BigIntegerOps.compare(_this.getValue(), that.getValue()) > 0;
}
@Fallback
boolean doOther(EnsoBigInteger _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.>", this);
}
}

View File

@ -0,0 +1,39 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = ">=", description = "Comparison of numbers.")
public abstract class GreaterOrEqualNode extends Node {
abstract boolean execute(EnsoBigInteger _this, Object that);
static GreaterOrEqualNode build() {
return GreaterOrEqualNodeGen.create();
}
@Specialization
boolean doDouble(EnsoBigInteger _this, double that) {
return BigIntegerOps.toDouble(_this.getValue()) >= that;
}
@Specialization
boolean doLong(EnsoBigInteger _this, long that) {
return _this.getValue().signum() > 0;
}
@Specialization
boolean doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) {
return BigIntegerOps.compare(_this.getValue(), that.getValue()) >= 0;
}
@Fallback
boolean doOther(EnsoBigInteger _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.>=", this);
}
}

View File

@ -0,0 +1,39 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "<", description = "Comparison of numbers.")
public abstract class LessNode extends Node {
abstract boolean execute(EnsoBigInteger _this, Object that);
static LessNode build() {
return LessNodeGen.create();
}
@Specialization
boolean doDouble(EnsoBigInteger _this, double that) {
return BigIntegerOps.toDouble(_this.getValue()) < that;
}
@Specialization
boolean doLong(EnsoBigInteger _this, long that) {
return _this.getValue().signum() < 0;
}
@Specialization
boolean doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) {
return BigIntegerOps.compare(_this.getValue(), that.getValue()) < 0;
}
@Fallback
boolean doOther(EnsoBigInteger _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.<", this);
}
}

View File

@ -0,0 +1,39 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "<=", description = "Comparison of numbers.")
public abstract class LessOrEqualNode extends Node {
abstract boolean execute(EnsoBigInteger _this, Object that);
static LessOrEqualNode build() {
return LessOrEqualNodeGen.create();
}
@Specialization
boolean doDouble(EnsoBigInteger _this, double that) {
return BigIntegerOps.toDouble(_this.getValue()) <= that;
}
@Specialization
boolean doLong(EnsoBigInteger _this, long that) {
return _this.getValue().signum() < 0;
}
@Specialization
boolean doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) {
return BigIntegerOps.compare(_this.getValue(), that.getValue()) <= 0;
}
@Fallback
boolean doOther(EnsoBigInteger _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.<=", this);
}
}

View File

@ -13,9 +13,9 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
public abstract class MultiplyNode extends Node { public abstract class MultiplyNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build();
abstract Object execute(EnsoBigInteger _this, Object that); public abstract Object execute(EnsoBigInteger _this, Object that);
static MultiplyNode build() { public static MultiplyNode build() {
return MultiplyNodeGen.create(); return MultiplyNodeGen.create();
} }
@ -29,6 +29,11 @@ public abstract class MultiplyNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.multiply(_this.getValue(), that.getValue())); return toEnsoNumberNode.execute(BigIntegerOps.multiply(_this.getValue(), that.getValue()));
} }
@Specialization
double doDouble(EnsoBigInteger _this, double that) {
return BigIntegerOps.toDouble(_this.getValue()) * that;
}
@Fallback @Fallback
Object doOther(EnsoBigInteger _this, Object that) { Object doOther(EnsoBigInteger _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.*", this); throw new TypeError("Unexpected type provided for argument `that` in Integer.*", this);

View File

@ -0,0 +1,54 @@
package org.enso.interpreter.node.expression.builtin.number.bigInteger;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Big_Integer", name = "^", description = "Big integer exponentiation.")
public abstract class PowNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build();
public abstract Object execute(EnsoBigInteger _this, Object that);
public static PowNode build() {
return PowNodeGen.create();
}
@Specialization
Object doLong(EnsoBigInteger _this, long that) {
if (that == 0) {
return 1L;
} else if (that > 0) {
return toEnsoNumberNode.execute(BigIntegerOps.pow(_this.getValue(), that));
} else {
return Math.pow(BigIntegerOps.toDouble(_this.getValue()), that);
}
}
@Specialization
Object doBigInteger(EnsoBigInteger _this, EnsoBigInteger that) {
if (that.getValue().signum() > 0) {
return Math.pow(
BigIntegerOps.toDouble(_this.getValue()), BigIntegerOps.toDouble(that.getValue()));
} else if (that.getValue().signum() == 0) {
return 1.0D;
} else {
return 0.0D;
}
}
@Specialization
double doDouble(EnsoBigInteger _this, double that) {
return Math.pow(BigIntegerOps.toDouble(_this.getValue()), that);
}
@Fallback
Object doOther(EnsoBigInteger _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.^", this);
}
}

View File

@ -29,6 +29,11 @@ public abstract class SubtractNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.subtract(_this.getValue(), that.getValue())); return toEnsoNumberNode.execute(BigIntegerOps.subtract(_this.getValue(), that.getValue()));
} }
@Specialization
double doDouble(EnsoBigInteger _this, double that) {
return BigIntegerOps.toDouble(_this.getValue()) - that;
}
@Fallback @Fallback
Object doOther(EnsoBigInteger _this, Object that) { Object doOther(EnsoBigInteger _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.-", this); throw new TypeError("Unexpected type provided for argument `that` in Integer.-", this);

View File

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

View File

@ -0,0 +1,11 @@
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 {
double execute(double _this) {
return Math.abs(_this);
}
}

View File

@ -0,0 +1,38 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "+", description = "Addition of numbers.")
public abstract class AddNode extends Node {
abstract double execute(double _this, Object that);
static AddNode build() {
return AddNodeGen.create();
}
@Specialization
double doDouble(double _this, double that) {
return _this + that;
}
@Specialization
double doLong(double _this, long that) {
return _this + that;
}
@Specialization
double doBigInteger(double _this, EnsoBigInteger that) {
return _this + BigIntegerOps.toDouble(that.getValue());
}
@Fallback
double doOther(double _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Decimal.+", this);
}
}

View File

@ -0,0 +1,38 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "/", description = "Division of numbers.")
public abstract class DivideNode extends Node {
abstract double execute(double _this, Object that);
static DivideNode build() {
return DivideNodeGen.create();
}
@Specialization
double doDouble(double _this, double that) {
return _this / that;
}
@Specialization
double doLong(double _this, long that) {
return _this / that;
}
@Specialization
double doBigInteger(double _this, EnsoBigInteger that) {
return _this / BigIntegerOps.toDouble(that.getValue());
}
@Fallback
double doOther(double _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Decimal./", this);
}
}

View File

@ -0,0 +1,38 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "==", description = "Equality on numbers.")
public abstract class EqualsNode extends Node {
abstract boolean execute(double _this, Object that);
static EqualsNode build() {
return EqualsNodeGen.create();
}
@Specialization
boolean doDouble(double _this, double that) {
return _this == that;
}
@Specialization
boolean doLong(double _this, long that) {
return _this == (double) that;
}
@Specialization
boolean doBigInteger(double _this, EnsoBigInteger that) {
return _this == BigIntegerOps.toDouble(that.getValue());
}
@Fallback
boolean doOther(double _this, Object that) {
return false;
}
}

View File

@ -0,0 +1,40 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = ">", description = "Comparison of numbers.")
public abstract class GreaterNode extends Node {
abstract boolean execute(double _this, Object that);
static GreaterNode build() {
return GreaterNodeGen.create();
}
@Specialization
boolean doDouble(double _this, double that) {
return _this > that;
}
@Specialization
boolean doLong(double _this, long that) {
return _this > (double) that;
}
@Specialization
boolean doBigInteger(double _this, EnsoBigInteger that) {
return _this > BigIntegerOps.toDouble(that.getValue());
}
@Fallback
boolean doOther(double _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Decimal.>", this);
}
}

View File

@ -0,0 +1,39 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = ">=", description = "Comparison of numbers.")
public abstract class GreaterOrEqualNode extends Node {
abstract boolean execute(double _this, Object that);
static GreaterOrEqualNode build() {
return GreaterOrEqualNodeGen.create();
}
@Specialization
boolean doDouble(double _this, double that) {
return _this >= that;
}
@Specialization
boolean doLong(double _this, long that) {
return _this >= (double) that;
}
@Specialization
boolean doBigInteger(double _this, EnsoBigInteger that) {
return _this >= BigIntegerOps.toDouble(that.getValue());
}
@Fallback
boolean doOther(double _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Decimal.>=", this);
}
}

View File

@ -0,0 +1,39 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "<", description = "Comparison of numbers.")
public abstract class LessNode extends Node {
abstract boolean execute(double _this, Object that);
static LessNode build() {
return LessNodeGen.create();
}
@Specialization
boolean doDouble(double _this, double that) {
return _this < that;
}
@Specialization
boolean doLong(double _this, long that) {
return _this < (double) that;
}
@Specialization
boolean doBigInteger(double _this, EnsoBigInteger that) {
return _this < BigIntegerOps.toDouble(that.getValue());
}
@Fallback
boolean doOther(double _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Decimal.<", this);
}
}

View File

@ -0,0 +1,39 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "<=", description = "Comparison of numbers.")
public abstract class LessOrEqualNode extends Node {
abstract boolean execute(double _this, Object that);
static LessOrEqualNode build() {
return LessOrEqualNodeGen.create();
}
@Specialization
boolean doDouble(double _this, double that) {
return _this <= that;
}
@Specialization
boolean doLong(double _this, long that) {
return _this <= (double) that;
}
@Specialization
boolean doBigInteger(double _this, EnsoBigInteger that) {
return _this <= BigIntegerOps.toDouble(that.getValue());
}
@Fallback
boolean doOther(double _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Decimal.<=", this);
}
}

View File

@ -0,0 +1,36 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "*", description = "Multiplication of numbers.")
public abstract class MultiplyNode extends Node {
abstract double execute(double _this, Object that);
static MultiplyNode build() {
return MultiplyNodeGen.create();
}
@Specialization
double doDouble(double _this, double that) { return _this * that;}
@Specialization
double doLong(double _this, long that) {
return _this * that;
}
@Specialization
double doBigInteger(double _this, EnsoBigInteger that) {
return _this * BigIntegerOps.toDouble(that.getValue());
}
@Fallback
double doOther(double _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Decimal.*", this);
}
}

View File

@ -0,0 +1,11 @@
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 {
double execute(double _this) {
return -_this;
}
}

View File

@ -0,0 +1,38 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "^", description = "Exponentiation of numbers.")
public abstract class PowNode extends Node {
abstract double execute(double _this, Object that);
static PowNode build() {
return PowNodeGen.create();
}
@Specialization
double doDouble(double _this, double that) {
return Math.pow(_this, that);
}
@Specialization
double doLong(double _this, long that) {
return Math.pow(_this, that);
}
@Specialization
double doBigInteger(double _this, EnsoBigInteger that) {
return Math.pow(_this, BigIntegerOps.toDouble(that.getValue()));
}
@Fallback
double doOther(double _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Decimal.^", this);
}
}

View File

@ -0,0 +1,38 @@
package org.enso.interpreter.node.expression.builtin.number.decimal;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Decimal", name = "-", description = "Subtraction of numbers.")
public abstract class SubtractNode extends Node {
abstract double execute(double _this, Object that);
static SubtractNode build() {
return SubtractNodeGen.create();
}
@Specialization
double doDouble(double _this, double that) {
return _this - that;
}
@Specialization
double doLong(double _this, long that) {
return _this - that;
}
@Specialization
double doBigInteger(double _this, EnsoBigInteger that) {
return _this - BigIntegerOps.toDouble(that.getValue());
}
@Fallback
double doOther(double _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Decimal.-", this);
}
}

View File

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

View File

@ -0,0 +1,32 @@
package org.enso.interpreter.node.expression.builtin.number.int64;
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;
@BuiltinMethod(type = "Small_Integer", name = "negate", description = "Negation for numbers.")
public abstract class AbsNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build();
static AbsNode build() {
return AbsNodeGen.create();
}
abstract Object execute(long _this);
@Specialization(rewriteOn = ArithmeticException.class)
long doNormal(long _this) {
if (_this < 0) {
return Math.negateExact(_this);
} else {
return _this;
}
}
@Specialization
Object doOverflow(long _this) {
return toEnsoNumberNode.execute(BigIntegerOps.abs(_this));
}
}

View File

@ -9,7 +9,7 @@ import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNod
import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger; import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Int_64", name = "+", description = "Addition of numbers.") @BuiltinMethod(type = "Small_Integer", name = "+", description = "Addition of numbers.")
public abstract class AddNode extends Node { public abstract class AddNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build();
@ -29,6 +29,11 @@ public abstract class AddNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.add(_this, that)); return toEnsoNumberNode.execute(BigIntegerOps.add(_this, that));
} }
@Specialization
double doDouble(long _this, double that) {
return _this + that;
}
@Specialization @Specialization
Object doBigInteger(long _this, EnsoBigInteger that) { Object doBigInteger(long _this, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.add(that.getValue(), _this)); return toEnsoNumberNode.execute(BigIntegerOps.add(that.getValue(), _this));

View File

@ -0,0 +1,32 @@
package org.enso.interpreter.node.expression.builtin.number.int64;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "div", description = "Division of numbers.")
public abstract class DivNode extends Node {
abstract Object execute(long _this, Object that);
static DivNode build() {
return DivNodeGen.create();
}
@Specialization
long doLong(long _this, long that) {
return _this / that;
}
@Specialization
long doBigInteger(long _this, EnsoBigInteger that) {
return 0L;
}
@Fallback
Object doOther(long _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.div", this);
}
}

View File

@ -4,29 +4,35 @@ import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger; import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Int_64", name = "/", description = "Division of numbers.") @BuiltinMethod(type = "Small_Integer", name = "/", description = "Division of numbers.")
public abstract class DivideNode extends Node { public abstract class DivideNode extends Node {
abstract Object execute(long _this, Object that); abstract double execute(long _this, Object that);
static DivideNode build() { static DivideNode build() {
return DivideNodeGen.create(); return DivideNodeGen.create();
} }
@Specialization @Specialization
long doLong(long _this, long that) { double doLong(long _this, long that) {
return ((double) _this) / ((double) that);
}
@Specialization
double doDouble(long _this, double that) {
return _this / that; return _this / that;
} }
@Specialization @Specialization
long doBigInteger(long _this, EnsoBigInteger that) { double doBigInteger(long _this, EnsoBigInteger that) {
return 0L; return ((double) _this) / BigIntegerOps.toDouble(that.getValue());
} }
@Fallback @Fallback
Object doOther(long _this, Object that) { double doOther(long _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer./", this); throw new TypeError("Unexpected type provided for argument `that` in Integer./", this);
} }
} }

View File

@ -5,7 +5,7 @@ import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.dsl.BuiltinMethod;
@BuiltinMethod(type = "Int_64", name = "==", description = "Equality on numbers.") @BuiltinMethod(type = "Small_Integer", name = "==", description = "Equality on numbers.")
public abstract class EqualsNode extends Node { public abstract class EqualsNode extends Node {
abstract boolean execute(long _this, Object that); abstract boolean execute(long _this, Object that);
@ -19,6 +19,11 @@ public abstract class EqualsNode extends Node {
return _this == that; return _this == that;
} }
@Specialization
boolean doDouble(long _this, double that) {
return (double) _this == that;
}
@Fallback @Fallback
boolean doOther(long _this, Object that) { boolean doOther(long _this, Object that) {
return false; return false;

View File

@ -0,0 +1,38 @@
package org.enso.interpreter.node.expression.builtin.number.int64;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = ">", description = "Comparison of numbers.")
public abstract class GreaterNode extends Node {
abstract boolean execute(long _this, Object that);
static GreaterNode build() {
return GreaterNodeGen.create();
}
@Specialization
boolean doLong(long _this, long that) {
return _this > that;
}
@Specialization
boolean doDouble(long _this, double that) {
return (double) _this > that;
}
@Specialization
boolean doBigInteger(long _this, EnsoBigInteger that) {
return that.getValue().signum() < 0;
}
@Fallback
boolean doOther(long _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.>", this);
}
}

View File

@ -0,0 +1,38 @@
package org.enso.interpreter.node.expression.builtin.number.int64;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = ">=", description = "Comparison of numbers.")
public abstract class GreaterOrEqualNode extends Node {
abstract boolean execute(long _this, Object that);
static GreaterOrEqualNode build() {
return GreaterOrEqualNodeGen.create();
}
@Specialization
boolean doLong(long _this, long that) {
return _this >= that;
}
@Specialization
boolean doDouble(long _this, double that) {
return (double) _this >= that;
}
@Specialization
boolean doBigInteger(long _this, EnsoBigInteger that) {
return that.getValue().signum() < 0;
}
@Fallback
boolean doOther(long _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.>=", this);
}
}

View File

@ -0,0 +1,38 @@
package org.enso.interpreter.node.expression.builtin.number.int64;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "<", description = "Comparison of numbers.")
public abstract class LessNode extends Node {
abstract boolean execute(long _this, Object that);
static LessNode build() {
return LessNodeGen.create();
}
@Specialization
boolean doLong(long _this, long that) {
return _this < that;
}
@Specialization
boolean doDouble(long _this, double that) {
return (double) _this < that;
}
@Specialization
boolean doBigInteger(long _this, EnsoBigInteger that) {
return that.getValue().signum() > 0;
}
@Fallback
boolean doOther(long _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.<", this);
}
}

View File

@ -0,0 +1,38 @@
package org.enso.interpreter.node.expression.builtin.number.int64;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Small_Integer", name = "<=", description = "Comparison of numbers.")
public abstract class LessOrEqualNode extends Node {
abstract boolean execute(long _this, Object that);
static LessOrEqualNode build() {
return LessOrEqualNodeGen.create();
}
@Specialization
boolean doLong(long _this, long that) {
return _this <= that;
}
@Specialization
boolean doDouble(long _this, double that) {
return (double) _this <= that;
}
@Specialization
boolean doBigInteger(long _this, EnsoBigInteger that) {
return that.getValue().signum() > 0;
}
@Fallback
boolean doOther(long _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.<=", this);
}
}

View File

@ -7,7 +7,7 @@ import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger; import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Int_64", name = "%", description = "Modulo division of numbers.") @BuiltinMethod(type = "Small_Integer", name = "%", description = "Modulo division of numbers.")
public abstract class ModNode extends Node { public abstract class ModNode extends Node {
abstract Object execute(long _this, Object that); abstract Object execute(long _this, Object that);

View File

@ -9,7 +9,7 @@ import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNod
import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger; import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Int_64", name = "*", description = "Multiplication of numbers.") @BuiltinMethod(type = "Small_Integer", name = "*", description = "Multiplication of numbers.")
public abstract class MultiplyNode extends Node { public abstract class MultiplyNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build();
@ -29,6 +29,11 @@ public abstract class MultiplyNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.multiply(_this, that)); return toEnsoNumberNode.execute(BigIntegerOps.multiply(_this, that));
} }
@Specialization
double doDouble(long _this, double that) {
return ((double) _this) * that;
}
@Specialization @Specialization
Object doBigInteger(long _this, EnsoBigInteger that) { Object doBigInteger(long _this, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.multiply(that.getValue(), _this)); return toEnsoNumberNode.execute(BigIntegerOps.multiply(that.getValue(), _this));

View File

@ -6,7 +6,7 @@ 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.BigIntegerOps;
import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode; import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNode;
@BuiltinMethod(type = "Int_64", name = "negate", description = "Negation for numbers.") @BuiltinMethod(type = "Small_Integer", name = "negate", description = "Negation for numbers.")
public abstract class NegateNode extends Node { public abstract class NegateNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build();

View File

@ -0,0 +1,78 @@
package org.enso.interpreter.node.expression.builtin.number.int64;
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.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger;
import org.enso.interpreter.runtime.type.TypesGen;
import java.math.BigInteger;
@BuiltinMethod(type = "Small_Integer", name = "^", description = "Exponentation of numbers.")
public abstract class PowNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build();
private @Child org.enso.interpreter.node.expression.builtin.number.int64.MultiplyNode
longMultiplyNode =
org.enso.interpreter.node.expression.builtin.number.int64.MultiplyNode.build();
private @Child org.enso.interpreter.node.expression.builtin.number.bigInteger.MultiplyNode
bigIntMultiplyNode =
org.enso.interpreter.node.expression.builtin.number.bigInteger.MultiplyNode.build();
private @Child org.enso.interpreter.node.expression.builtin.number.bigInteger.PowNode
bigIntPowNode =
org.enso.interpreter.node.expression.builtin.number.bigInteger.PowNode.build();
abstract Object execute(long _this, Object that);
static PowNode build() {
return PowNodeGen.create();
}
@Specialization
Object doLong(long _this, long that) {
if (that < 0) {
return Math.pow(_this, that);
} else if (that == 0) {
return 1L;
} else {
Object res = 1L;
Object base = _this;
while (that > 0) {
if (that % 2 == 0) {
if (base instanceof Long) {
base = longMultiplyNode.execute((long) base, base);
} else {
base = bigIntMultiplyNode.execute((EnsoBigInteger) base, base);
}
that /= 2;
} else {
if (res instanceof Long) {
res = longMultiplyNode.execute((long) res, base);
} else {
res = bigIntMultiplyNode.execute((EnsoBigInteger) res, base);
}
that--;
}
}
return res;
}
}
@Specialization
double doDouble(long _this, double that) {
return Math.pow(_this, that);
}
@Specialization
Object doBigInteger(long _this, EnsoBigInteger that) {
return bigIntPowNode.execute(new EnsoBigInteger(BigInteger.valueOf(_this)), that);
}
@Fallback
Object doOther(long _this, Object that) {
throw new TypeError("Unexpected type provided for argument `that` in Integer.^", this);
}
}

View File

@ -9,7 +9,7 @@ import org.enso.interpreter.node.expression.builtin.number.utils.ToEnsoNumberNod
import org.enso.interpreter.runtime.error.TypeError; import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.number.EnsoBigInteger; import org.enso.interpreter.runtime.number.EnsoBigInteger;
@BuiltinMethod(type = "Int_64", name = "-", description = "Subtraction of numbers.") @BuiltinMethod(type = "Small_Integer", name = "-", description = "Subtraction of numbers.")
public abstract class SubtractNode extends Node { public abstract class SubtractNode extends Node {
private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build(); private @Child ToEnsoNumberNode toEnsoNumberNode = ToEnsoNumberNode.build();
@ -29,6 +29,11 @@ public abstract class SubtractNode extends Node {
return toEnsoNumberNode.execute(BigIntegerOps.subtract(_this, that)); return toEnsoNumberNode.execute(BigIntegerOps.subtract(_this, that));
} }
@Specialization
double doDouble(long _this, double that) {
return _this - that;
}
@Specialization @Specialization
Object doBigInteger(long _this, EnsoBigInteger that) { Object doBigInteger(long _this, EnsoBigInteger that) {
return toEnsoNumberNode.execute(BigIntegerOps.subtract(_this, that.getValue())); return toEnsoNumberNode.execute(BigIntegerOps.subtract(_this, that.getValue()));

View File

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

View File

@ -86,8 +86,43 @@ public class BigIntegerOps {
return BigInteger.valueOf(a).negate(); return BigInteger.valueOf(a).negate();
} }
@CompilerDirectives.TruffleBoundary
public static BigInteger abs(BigInteger a) {
return a.abs();
}
@CompilerDirectives.TruffleBoundary
public static BigInteger abs(long a) {
return BigInteger.valueOf(a).abs();
}
@CompilerDirectives.TruffleBoundary @CompilerDirectives.TruffleBoundary
public static boolean equals(BigInteger a, BigInteger b) { public static boolean equals(BigInteger a, BigInteger b) {
return a.equals(b); return a.equals(b);
} }
@CompilerDirectives.TruffleBoundary
public static double toDouble(BigInteger a) {
return a.doubleValue();
}
@CompilerDirectives.TruffleBoundary
public static int compare(BigInteger a, BigInteger b) {
return a.compareTo(b);
}
@CompilerDirectives.TruffleBoundary
public static BigInteger pow(BigInteger a, long b) {
BigInteger res = BigInteger.valueOf(1);
while (b > 0) {
if (b % 2 == 0) {
a = a.pow(2);
b /= 2;
} else {
res = res.multiply(a);
b--;
}
}
return res;
}
} }

View File

@ -0,0 +1,36 @@
package org.enso.interpreter.node.expression.literal;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.node.ExpressionNode;
/** A representation of decimal literals in Enso. */
@NodeInfo(description = "A decimal literal.")
public final class DecimalLiteralNode extends ExpressionNode {
private final double value;
private DecimalLiteralNode(double value) {
this.value = value;
}
/**
* Creates an instance of this node.
*
* @param value the value for the node to represent
* @return a node representing the literal given by {@code value}
*/
public static DecimalLiteralNode build(double value) {
return new DecimalLiteralNode(value);
}
/**
* Gets the value of the literal.
*
* @param frame the stack frame for execution
* @return the value of the integer literal
*/
@Override
public Object executeGeneric(VirtualFrame frame) {
return this.value;
}
}

View File

@ -10,6 +10,7 @@ public class Number {
private final AtomConstructor bigInteger; private final AtomConstructor bigInteger;
private final AtomConstructor integer; private final AtomConstructor integer;
private final AtomConstructor number; private final AtomConstructor number;
private final AtomConstructor decimal;
/** /**
* Creates and registers number builtins. * Creates and registers number builtins.
@ -22,14 +23,17 @@ public class Number {
smallInteger = new AtomConstructor("Small_Integer", scope).initializeFields(); smallInteger = new AtomConstructor("Small_Integer", scope).initializeFields();
integer = new AtomConstructor("Integer", scope).initializeFields(); integer = new AtomConstructor("Integer", scope).initializeFields();
bigInteger = new AtomConstructor("Big_Integer", scope).initializeFields(); bigInteger = new AtomConstructor("Big_Integer", scope).initializeFields();
decimal = new AtomConstructor("Decimal", scope).initializeFields();
registerInt64Methods(language, scope); registerInt64Methods(language, scope);
registerBigIntegerMethods(language, scope); registerBigIntegerMethods(language, scope);
registerDecimalMethods(language, scope);
scope.registerConstructor(number); scope.registerConstructor(number);
scope.registerConstructor(smallInteger); scope.registerConstructor(smallInteger);
scope.registerConstructor(integer); scope.registerConstructor(integer);
scope.registerConstructor(bigInteger); scope.registerConstructor(bigInteger);
scope.registerConstructor(decimal);
} }
private void registerInt64Methods(Language language, ModuleScope scope) { private void registerInt64Methods(Language language, ModuleScope scope) {
@ -48,11 +52,21 @@ public class Number {
"*", "*",
org.enso.interpreter.node.expression.builtin.number.int64.MultiplyMethodGen.makeFunction( org.enso.interpreter.node.expression.builtin.number.int64.MultiplyMethodGen.makeFunction(
language)); language));
scope.registerMethod(
smallInteger,
"^",
org.enso.interpreter.node.expression.builtin.number.int64.PowMethodGen.makeFunction(
language));
scope.registerMethod( scope.registerMethod(
smallInteger, smallInteger,
"/", "/",
org.enso.interpreter.node.expression.builtin.number.int64.DivideMethodGen.makeFunction( org.enso.interpreter.node.expression.builtin.number.int64.DivideMethodGen.makeFunction(
language)); language));
scope.registerMethod(
smallInteger,
"div",
org.enso.interpreter.node.expression.builtin.number.int64.DivMethodGen.makeFunction(
language));
scope.registerMethod( scope.registerMethod(
smallInteger, smallInteger,
"%", "%",
@ -63,11 +77,41 @@ public class Number {
"negate", "negate",
org.enso.interpreter.node.expression.builtin.number.int64.NegateMethodGen.makeFunction( org.enso.interpreter.node.expression.builtin.number.int64.NegateMethodGen.makeFunction(
language)); language));
scope.registerMethod(
smallInteger,
"abs",
org.enso.interpreter.node.expression.builtin.number.int64.AbsMethodGen.makeFunction(
language));
scope.registerMethod( scope.registerMethod(
smallInteger, smallInteger,
"==", "==",
org.enso.interpreter.node.expression.builtin.number.int64.EqualsMethodGen.makeFunction( org.enso.interpreter.node.expression.builtin.number.int64.EqualsMethodGen.makeFunction(
language)); language));
scope.registerMethod(
smallInteger,
">",
org.enso.interpreter.node.expression.builtin.number.int64.GreaterMethodGen.makeFunction(
language));
scope.registerMethod(
smallInteger,
">=",
org.enso.interpreter.node.expression.builtin.number.int64.GreaterOrEqualMethodGen
.makeFunction(language));
scope.registerMethod(
smallInteger,
"<",
org.enso.interpreter.node.expression.builtin.number.int64.LessMethodGen.makeFunction(
language));
scope.registerMethod(
smallInteger,
"<=",
org.enso.interpreter.node.expression.builtin.number.int64.LessOrEqualMethodGen.makeFunction(
language));
scope.registerMethod(
smallInteger,
"to_decimal",
org.enso.interpreter.node.expression.builtin.number.int64.ToDecimalMethodGen.makeFunction(
language));
} }
private void registerBigIntegerMethods(Language language, ModuleScope scope) { private void registerBigIntegerMethods(Language language, ModuleScope scope) {
@ -87,11 +131,21 @@ public class Number {
"*", "*",
org.enso.interpreter.node.expression.builtin.number.bigInteger.MultiplyMethodGen org.enso.interpreter.node.expression.builtin.number.bigInteger.MultiplyMethodGen
.makeFunction(language)); .makeFunction(language));
scope.registerMethod(
bigInteger,
"^",
org.enso.interpreter.node.expression.builtin.number.bigInteger.PowMethodGen.makeFunction(
language));
scope.registerMethod( scope.registerMethod(
bigInteger, bigInteger,
"/", "/",
org.enso.interpreter.node.expression.builtin.number.bigInteger.DivideMethodGen.makeFunction( org.enso.interpreter.node.expression.builtin.number.bigInteger.DivideMethodGen.makeFunction(
language)); language));
scope.registerMethod(
bigInteger,
"div",
org.enso.interpreter.node.expression.builtin.number.bigInteger.DivMethodGen.makeFunction(
language));
scope.registerMethod( scope.registerMethod(
bigInteger, bigInteger,
"%", "%",
@ -102,11 +156,110 @@ public class Number {
"negate", "negate",
org.enso.interpreter.node.expression.builtin.number.bigInteger.NegateMethodGen.makeFunction( org.enso.interpreter.node.expression.builtin.number.bigInteger.NegateMethodGen.makeFunction(
language)); language));
scope.registerMethod(
bigInteger,
"abs",
org.enso.interpreter.node.expression.builtin.number.bigInteger.AbsMethodGen.makeFunction(
language));
scope.registerMethod( scope.registerMethod(
bigInteger, bigInteger,
"==", "==",
org.enso.interpreter.node.expression.builtin.number.bigInteger.EqualsMethodGen.makeFunction( org.enso.interpreter.node.expression.builtin.number.bigInteger.EqualsMethodGen.makeFunction(
language)); language));
scope.registerMethod(
bigInteger,
">",
org.enso.interpreter.node.expression.builtin.number.bigInteger.GreaterMethodGen
.makeFunction(language));
scope.registerMethod(
bigInteger,
">=",
org.enso.interpreter.node.expression.builtin.number.bigInteger.GreaterOrEqualMethodGen
.makeFunction(language));
scope.registerMethod(
bigInteger,
"<",
org.enso.interpreter.node.expression.builtin.number.bigInteger.LessMethodGen.makeFunction(
language));
scope.registerMethod(
bigInteger,
"<=",
org.enso.interpreter.node.expression.builtin.number.bigInteger.LessOrEqualMethodGen
.makeFunction(language));
scope.registerMethod(
bigInteger,
"to_decimal",
org.enso.interpreter.node.expression.builtin.number.bigInteger.ToDecimalMethodGen
.makeFunction(language));
}
private void registerDecimalMethods(Language language, ModuleScope scope) {
scope.registerMethod(
decimal,
"+",
org.enso.interpreter.node.expression.builtin.number.decimal.AddMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
"-",
org.enso.interpreter.node.expression.builtin.number.decimal.SubtractMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
"*",
org.enso.interpreter.node.expression.builtin.number.decimal.MultiplyMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
"^",
org.enso.interpreter.node.expression.builtin.number.decimal.PowMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
"/",
org.enso.interpreter.node.expression.builtin.number.decimal.DivideMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
"negate",
org.enso.interpreter.node.expression.builtin.number.decimal.NegateMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
"abs",
org.enso.interpreter.node.expression.builtin.number.decimal.AbsMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
"==",
org.enso.interpreter.node.expression.builtin.number.decimal.EqualsMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
">",
org.enso.interpreter.node.expression.builtin.number.decimal.GreaterMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
">=",
org.enso.interpreter.node.expression.builtin.number.decimal.GreaterOrEqualMethodGen
.makeFunction(language));
scope.registerMethod(
decimal,
"<",
org.enso.interpreter.node.expression.builtin.number.decimal.LessMethodGen.makeFunction(
language));
scope.registerMethod(
decimal,
"<=",
org.enso.interpreter.node.expression.builtin.number.decimal.LessOrEqualMethodGen
.makeFunction(language));
scope.registerMethod(
decimal,
"to_decimal",
org.enso.interpreter.node.expression.builtin.number.decimal.ToDecimalMethodGen.makeFunction(
language));
} }
/** @return the Int64 atom constructor. */ /** @return the Int64 atom constructor. */
@ -128,4 +281,9 @@ public class Number {
public AtomConstructor getNumber() { public AtomConstructor getNumber() {
return number; return number;
} }
/** @return the Decimal atom constructor */
public AtomConstructor getDecimal() {
return decimal;
}
} }

View File

@ -1,5 +1,7 @@
package org.enso.interpreter.runtime.number; package org.enso.interpreter.runtime.number;
import com.oracle.truffle.api.CompilerDirectives;
import java.math.BigInteger; import java.math.BigInteger;
/** Internal wrapper for a {@link BigInteger}. */ /** Internal wrapper for a {@link BigInteger}. */
@ -19,4 +21,10 @@ public class EnsoBigInteger {
public BigInteger getValue() { public BigInteger getValue() {
return value; return value;
} }
@Override
@CompilerDirectives.TruffleBoundary
public String toString() {
return value.toString();
}
} }

View File

@ -27,6 +27,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
@TypeSystem({ @TypeSystem({
long.class, long.class,
boolean.class, boolean.class,
double.class,
String.class, String.class,
Function.class, Function.class,
Atom.class, Atom.class,

View File

@ -377,6 +377,8 @@ object AstToIr {
allBranches, allBranches,
getIdentifiedLocation(inputAst) getIdentifiedLocation(inputAst)
) )
case AstView.DecimalLiteral(intPart, fracPart) =>
translateDecimalLiteral(inputAst, intPart, fracPart)
case AST.App.any(inputAST) => translateApplicationLike(inputAST) case AST.App.any(inputAST) => translateApplicationLike(inputAST)
case AST.Mixfix.any(inputAST) => translateApplicationLike(inputAST) case AST.Mixfix.any(inputAST) => translateApplicationLike(inputAST)
case AST.Literal.any(inputAST) => translateLiteral(inputAST) case AST.Literal.any(inputAST) => translateLiteral(inputAST)
@ -421,6 +423,26 @@ object AstToIr {
* argument and cannot be performed any other way. * argument and cannot be performed any other way.
*/ */
def translateDecimalLiteral(
ast: AST,
int: AST.Literal.Number,
frac: AST.Literal.Number
): Expression = {
if (int.base.isDefined && int.base.get != "10") {
Error.Syntax(
int,
Error.Syntax.UnsupportedSyntax("non-base-10 number literals")
)
} else if (frac.base.isDefined && frac.base.get != "10") {
Error.Syntax(frac, Error.Syntax.InvalidBaseInDecimalLiteral)
} else {
Literal.Number(
s"${int.shape.int}.${frac.shape.int}",
getIdentifiedLocation(ast)
)
}
}
/** Translates a program literal from its [[AST]] representation into /** Translates a program literal from its [[AST]] representation into
* [[IR]]. * [[IR]].
* *

View File

@ -842,6 +842,19 @@ object AstView {
} }
} }
object DecimalLiteral {
def unapply(ast: AST): Option[(AST.Literal.Number, AST.Literal.Number)] =
ast match {
case AST.App.Infix(
AST.Literal.Number.any(int),
AST.Ident.Opr("."),
AST.Literal.Number.any(frac)
) =>
Some((int, frac))
case _ => None
}
}
object UnaryMinus { object UnaryMinus {
def minusSymbol: String = "-" def minusSymbol: String = "-"

View File

@ -44,6 +44,7 @@ import org.enso.interpreter.node.expression.constant.{
} }
import org.enso.interpreter.node.expression.literal.{ import org.enso.interpreter.node.expression.literal.{
BigIntegerLiteralNode, BigIntegerLiteralNode,
DecimalLiteralNode,
IntegerLiteralNode, IntegerLiteralNode,
TextLiteralNode TextLiteralNode
} }
@ -859,10 +860,14 @@ class IrToTruffle(
*/ */
def processLiteral(literal: IR.Literal): RuntimeExpression = def processLiteral(literal: IR.Literal): RuntimeExpression =
literal match { literal match {
case IR.Literal.Number(value, location, _, _) => case lit @ IR.Literal.Number(value, location, _, _) =>
val node = value.toLongOption val node = if (lit.isFractional) {
.map(IntegerLiteralNode.build) DecimalLiteralNode.build(value.toDouble)
.getOrElse(BigIntegerLiteralNode.build(new BigInteger(value))) } else {
value.toLongOption
.map(IntegerLiteralNode.build)
.getOrElse(BigIntegerLiteralNode.build(new BigInteger(value)))
}
setLocation(node, location) setLocation(node, location)
case IR.Literal.Text(text, location, _, _) => case IR.Literal.Text(text, location, _, _) =>
setLocation(TextLiteralNode.build(text), location) setLocation(TextLiteralNode.build(text), location)

View File

@ -1581,6 +1581,13 @@ object IR {
override def children: List[IR] = List() override def children: List[IR] = List()
override def showCode(indent: Int): String = value override def showCode(indent: Int): String = value
/**
* Checks whether the literal represents a fractional value.
*
* @return `true` if the value is fractional, `false` otherwise.
*/
def isFractional: Boolean = value.contains(".")
} }
/** A textual Enso literal. /** A textual Enso literal.
@ -5563,6 +5570,11 @@ object IR {
def explanation: String def explanation: String
} }
case object InvalidBaseInDecimalLiteral extends Reason {
override def explanation: String =
"Cannot change base of the fractional part of a number literal."
}
case class UnsupportedSyntax(syntaxName: String) extends Reason { case class UnsupportedSyntax(syntaxName: String) extends Reason {
override def explanation: String = override def explanation: String =
s"Syntax is not supported yet: $syntaxName." s"Syntax is not supported yet: $syntaxName."

View File

@ -15,5 +15,7 @@ main =
mil = 1000000 mil = 1000000
list = here.gen_list mil list = here.gen_list mil
vec = Vector.new mil (ix -> ix + 1) vec = Vector.new mil (ix -> ix + 1)
vec_decimal = Vector.new mil (ix -> ix + 0.0)
Bench_Utils.measure (vec.fold 0 (+)) "vector fold" 1000 10 Bench_Utils.measure (vec.fold 0 (+)) "vector fold" 1000 10
Bench_Utils.measure (list.fold 0 (+)) "list fold" 1000 10 Bench_Utils.measure (list.fold 0 (+)) "list fold" 1000 10
Bench_Utils.measure (vec_decimal.fold 0 (+)) "vector decimal fold" 1000 10

View File

@ -12,6 +12,14 @@ sum_tco = sum_to ->
res = summator 0 sum_to res = summator 0 sum_to
res res
sum_tco_decimal = sum_to ->
s = sum_to.to_decimal
summator = acc -> current ->
if current >= s then acc else summator acc+current current+1.0
res = summator 0.0 0.0
res
sum_tco_java = sum_to -> sum_tco_java = sum_to ->
summator = acc -> current -> summator = acc -> current ->
if current == 0 then acc else summator (Long.sum [acc, current]) (current - 1) if current == 0 then acc else summator (Long.sum [acc, current]) (current - 1)
@ -40,8 +48,10 @@ sum_state = sum_to ->
main = main =
hundred_mil = 100000000 hundred_mil = 100000000
IO.println "Measuring Sum TCO Decimal"
Bench_Utils.measure (here.sum_tco_decimal hundred_mil) "sum_tco" 100 10
IO.println "Measuring SumTCO" IO.println "Measuring SumTCO"
Bench_Utils.measure (here.sum_tco hundred_mil) "sum_tco" 500 10 Bench_Utils.measure (here.sum_tco hundred_mil) "sum_tco" 100 10
IO.println "Measuring SumTCO Java" IO.println "Measuring SumTCO Java"
Bench_Utils.measure (here.sum_tco_java hundred_mil) "sum_tco" 100 10 Bench_Utils.measure (here.sum_tco_java hundred_mil) "sum_tco" 100 10
IO.println "Measuring State" IO.println "Measuring State"

View File

@ -2,7 +2,13 @@ from Base import all
import Base.Test import Base.Test
polyglot java import java.lang.Long polyglot java import java.lang.Long
polyglot java import java.lang.Integer
polyglot java import java.lang.Float
spec = describe "Java FFI" <| spec = describe "Java FFI" <|
it "should call methods imported from Java" <| it "should call methods imported from Java" <|
Long.sum [1, 2] . should_equal 3 Long.sum [1, 2] . should_equal 3
it "should auto-convert numeric types across the polyglot boundary" <|
(Float.valueOf ["123.3"] + 5).should_equal 128.3 epsilon=0.0001
(Integer.sum [1, 2] + 3) . should_equal 6

View File

@ -3,8 +3,10 @@ from Base import all
import Base.Test import Base.Test
Integer.is_even = this % 2 == 0 Integer.is_even = this % 2 == 0
Decimal.get_fun_factor = "Wow, " + this.to_text + " is such a fun number!"
spec = spec =
eps = 0.000001
almost_max_long = 9223372036854775806 almost_max_long = 9223372036854775806
almost_max_long_times_three = 27670116110564327418 almost_max_long_times_three = 27670116110564327418
hundred_factorial = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 hundred_factorial = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
@ -17,7 +19,7 @@ spec =
(0 - almost_max_long - almost_max_long - almost_max_long).should_equal almost_max_long_times_three.negate (0 - almost_max_long - almost_max_long - almost_max_long).should_equal almost_max_long_times_three.negate
it "should be of unbound size when dividing" <| it "should be of unbound size when dividing" <|
expected = 3372816184472482867110284450043137767873196479305249187406461598235841786750685581361224832688174410089430537516012695688121622150430744676 expected = 3372816184472482867110284450043137767873196479305249187406461598235841786750685581361224832688174410089430537516012695688121622150430744676
((1.upto 101 . fold 1 (*)) / 3*almost_max_long).should_equal expected ((1.upto 101 . fold 1 (*)).div 3*almost_max_long).should_equal expected
it "should be of unbound size when taking remainder" <| it "should be of unbound size when taking remainder" <|
expected = 3191479909175673432 expected = 3191479909175673432
((1.upto 101 . fold 1 (*)) % 3*almost_max_long).should_equal expected ((1.upto 101 . fold 1 (*)) % 3*almost_max_long).should_equal expected
@ -34,4 +36,33 @@ spec =
(hundred_factorial == 1).should_be_false (hundred_factorial == 1).should_be_false
it "should properly handle going to big numbers and back" <| it "should properly handle going to big numbers and back" <|
((almost_max_long * 3) / 3) . should_equal almost_max_long ((almost_max_long * 3) / 3) . should_equal almost_max_long
it "should use floating point arithmetic for division" <|
(3 / 4) . should_equal 0.75 epsilon=eps
(almost_max_long * 2 / almost_max_long_times_three) . should_equal 0.6666666 epsilon=eps
describe "Decimals" <|
it "should exist and expose basic arithmetic operations" <|
((1.5 + 1.5)*1.3 / 2 - 3) . should_equal -1.05 epsilon=eps
it "should allow defining extension methods through the Decimal type" <|
32.5.get_fun_factor.should_equal "Wow, 32.5 is such a fun number!"
describe "Numbers" <|
it "should expose comparison operators" <|
(3 < hundred_factorial).should_be_true
(hundred_factorial < 3).should_be_false
(3.0 < hundred_factorial).should_be_true
(3.0 <= 3.4).should_be_true
(3.0 >= 2).should_be_true
(-hundred_factorial > 0).should_be_false
it "should expose exponentiation operations" <|
(3.14 ^ 2.71).should_equal 22.216689546 epsilon=eps
(3.14 ^ 14).should_equal 9057640.36635 epsilon=eps
a = almost_max_long
(a ^ 4).should_equal (a * a * a * a)
(2 ^ 10).should_equal 1024
(2 ^ 0.5).should_equal 1.41421356237 epsilon=eps
(a^2)^0.5 . should_equal a epsilon=eps
it "should expose more involved mathematical functions" <|
Math.Pi.sin.should_equal 0 epsilon=eps
(Math.Pi / 4).sin.should_equal (2 ^ 0.5)/2 epsilon=eps
(Math.Pi / 6).cos.should_equal (3.sqrt / 2) epsilon=eps
(17 ^ 0.13).log base=17 . should_equal 0.13 epsilon=eps
0.exp.should_equal 1