mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 21:41:34 +03:00
Autoscoped constructors (#9190)
Fixes #8645 by recognizing `~` prefix to constructor names.
This commit is contained in:
parent
3be5e585f2
commit
5676618bad
@ -1059,6 +1059,7 @@
|
||||
- [Add run_google_report method][8907]
|
||||
- [Execute and debug individual Enso files in VSCode extension][8923]
|
||||
- [Check type of `self` when calling a method using the static syntax][8867]
|
||||
- [Autoscoped constructors][9190]
|
||||
|
||||
[3227]: https://github.com/enso-org/enso/pull/3227
|
||||
[3248]: https://github.com/enso-org/enso/pull/3248
|
||||
@ -1217,6 +1218,7 @@
|
||||
[8907]: https://github.com/enso-org/enso/pull/8907
|
||||
[8923]: https://github.com/enso-org/enso/pull/8923
|
||||
[8867]: https://github.com/enso-org/enso/pull/8867
|
||||
[9190]: https://github.com/enso-org/enso/pull/9190
|
||||
|
||||
# Enso 2.0.0-alpha.18 (2021-10-12)
|
||||
|
||||
|
@ -79,7 +79,15 @@ type Type_Error
|
||||
_ -> ". Try to apply " + (missing_args.join ", ") + " arguments"
|
||||
_ -> tpe.to_text
|
||||
|
||||
"Type error: expected "+self.comment+" to be "+self.expected.to_display_text+", but got "+(if type_of_actual.is_a Text then type_of_actual else "<ERR>")+"."
|
||||
got = if type_of_actual.is_a Text then type_of_actual else "<ERR>"
|
||||
exp = self.expected.to_display_text
|
||||
msg = self.comment
|
||||
. replace "{exp}" exp
|
||||
. replace "{got}" got
|
||||
"Type error: "+msg+"."
|
||||
|
||||
to_text : Text
|
||||
to_text self = self.to_display_text
|
||||
|
||||
@Builtin_Type
|
||||
type Compile_Error
|
||||
|
@ -14,20 +14,11 @@ priority, but the dependencies between tasks are described.
|
||||
|
||||
## Technology Choices
|
||||
|
||||
With the advent of Java 17 and its ergonomic improvements (read:
|
||||
pattern-matching), it makes little sense to retain the usage of Scala throughout
|
||||
the compiler. The language was originally introduced due to the capabilities of
|
||||
its type system in comparison to Java's, but very little of this functionality
|
||||
has been used in the end.
|
||||
|
||||
We recommend moving everything to Java as part of this work, as you will end up
|
||||
with better tooling support. Scala has been a problem child.
|
||||
|
||||
Enso originally started working with Java 8, and was transitioned (painfully,
|
||||
due to the JPMS) to Java 11. Java 8 was EOL'd by the graal team after a couple
|
||||
of years. It seems likely that Java 11 will suffer a similar fate, though the
|
||||
transition from 11 to 17 will be far less painful as it doesn't introduce any
|
||||
breaking language-level changes.
|
||||
Enso interpreter is written in a mixture of Scala and Java. Scala was originally
|
||||
used due to the capabilities of its type system in comparison to Java's. Modern
|
||||
Java (as provided by JDK 21 or [Frgaal compiler](http://frgaal.org)) meets most
|
||||
of the needs too. The ultimate goal is to write everything in Java and also keep
|
||||
up with most recent long term supported JDK/GraalVM releases.
|
||||
|
||||
## Static Analysis
|
||||
|
||||
@ -49,7 +40,8 @@ Currently, the IR is:
|
||||
- Very verbose and difficult to add a new node to. Adding a new node requires
|
||||
adding ~100 lines of code that could likely be automated away. Lots of
|
||||
boilerplate.
|
||||
- Of unknown performance.
|
||||
- Of poor performance as witnessed by
|
||||
[static compiler benchmarks](https://github.com/enso-org/enso/pull/9158)
|
||||
- Partially mutable, making it confusing as to which things are shared.
|
||||
|
||||
A new IR for Enso would have to:
|
||||
@ -252,25 +244,6 @@ To rectify this situation, we recommend implementing a system we have termed
|
||||
With this done, it may still be necessary to create a Java DSL for implementing
|
||||
built-in methods and types, but that is unclear at this point.
|
||||
|
||||
### Static Methods on Types
|
||||
|
||||
Currently, Enso allows calling methods on _modules_, _constructors_, and
|
||||
_instances_. This does not conform to the language specification because it
|
||||
allows constructors and instances to be treated the same at runtime. This leads
|
||||
to odd results (see the ticket below).
|
||||
|
||||
The end result should be compliant with the design described
|
||||
[here](https://github.com/enso-org/enso/issues/1851), and needs to be taken into
|
||||
account when defining builtins.
|
||||
|
||||
### Better Safepointing
|
||||
|
||||
Enso currently uses a hand-rolled safepointing system for interrupting threads
|
||||
and handling resource finalisation. With 21.1, Truffle landed its own system for
|
||||
doing this. Enso should be updated to use
|
||||
[the new system](https://github.com/oracle/graal/blob/master/truffle/docs/Safepoints.md),
|
||||
instead, as it will provide better performance and more robust operation.
|
||||
|
||||
## Runtime Performance
|
||||
|
||||
While Enso is performant when it gets JITted by GraalVM, the performance when
|
||||
@ -290,29 +263,6 @@ This can be greatly improved.
|
||||
be improved.
|
||||
- Many of the above-listed static optimisations will greatly help here.
|
||||
|
||||
### Unboxed Atoms
|
||||
|
||||
Currently every atom in Enso is stored boxed. In limited circumstances it may be
|
||||
possible to unbox these and hence remove the indirection cost when accessing
|
||||
their data.
|
||||
|
||||
- Read the details of Truffle's
|
||||
[`DynamicObject`](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/object/DynamicObject.html),
|
||||
and the sources.
|
||||
- Use this system to inform the design for a system that reduces the overhead of
|
||||
dynamic field names and arities when accessing data on Atoms.
|
||||
|
||||
### Unboxed Vectors
|
||||
|
||||
Enso currently doesn't have support for unboxed arrays (and hence vectors). This
|
||||
means that it incurs a significant performance cost when working with pure
|
||||
numerical arrays. This can be improved.
|
||||
|
||||
- Read the truffle documentation on
|
||||
[truffle libraries](https://github.com/oracle/graal/blob/master/truffle/docs/TruffleLibraries.md).
|
||||
- Based on this, define a system that seamlessly specializes and deoptimises
|
||||
between boxed and unboxed arrays as necessary.
|
||||
|
||||
## IDE
|
||||
|
||||
As Enso's primary mode of use is in the IDE, there are a number of important
|
||||
@ -362,7 +312,3 @@ preprocessors.
|
||||
- Implement caching support for the visualization expression processing.
|
||||
- This cache should, much like the IDE's introspection cache, track and save the
|
||||
values of all top-level bindings in the visualization preprocessor.
|
||||
|
||||
## Parser
|
||||
|
||||
Parser
|
||||
|
@ -87,7 +87,7 @@ binds the function name. This means that:
|
||||
user-defined type for the function.
|
||||
|
||||
```ruby
|
||||
sum : (a: Monoid) -> a -> a
|
||||
sum : (a:Monoid) -> a -> a
|
||||
sum : x -> y -> x + y
|
||||
sum x y = x + y
|
||||
```
|
||||
@ -113,11 +113,11 @@ Methods can be defined in Enso in two ways:
|
||||
```ruby
|
||||
type Maybe a
|
||||
Nothing
|
||||
type Just (value : a)
|
||||
Just (value : a)
|
||||
|
||||
isJust = case this of
|
||||
Nothing -> False
|
||||
Just _ -> True
|
||||
is_just self = case self of
|
||||
Maybe.Nothing -> False
|
||||
Maybe.Just _ -> True
|
||||
```
|
||||
|
||||
2. **As an Extension Method:** A function defined _explicitly_ on an atom counts
|
||||
@ -125,7 +125,7 @@ type Maybe a
|
||||
to all the atoms within that typeset.
|
||||
|
||||
```ruby
|
||||
Number.floor = case this of
|
||||
Number.floor self = case self of
|
||||
Integer -> ...
|
||||
...
|
||||
```
|
||||
|
@ -276,32 +276,48 @@ context-dependent manner that is discussed properly in the
|
||||
[type system design document](../types/README.md), but is summarised briefly
|
||||
below.
|
||||
|
||||
- **Name and Fields:** When you provide the keyword with only a name and some
|
||||
field names, this creates an atom.
|
||||
|
||||
```ruby
|
||||
type Just value
|
||||
```
|
||||
|
||||
- **Body with Atom Definitions:** If you provide a body with atom definitions,
|
||||
this defines a smart constructor that defines the atoms and related functions
|
||||
by returning a typeset.
|
||||
|
||||
```ruby
|
||||
type Maybe a
|
||||
type Maybe
|
||||
Nothing
|
||||
type Just (value : a)
|
||||
Just (value : Integer)
|
||||
|
||||
isJust = case this of
|
||||
Nothing -> False
|
||||
Just _ -> True
|
||||
is_just self = case self of
|
||||
Maybe.Nothing -> False
|
||||
Maybe.Just _ -> True
|
||||
|
||||
nothing = not isJust
|
||||
nothing self = self.is_just.not
|
||||
```
|
||||
|
||||
Please note that the `type Foo (a : t)` is syntax only allowable inside a type
|
||||
definition. It defines an atom `Foo`, but constrains the type variable of the
|
||||
atom _in this usage_.
|
||||
To reference atoms use type name followed by the name of the atom. E.g.
|
||||
`Maybe.Nothing` or `Maybe.Just 2`. Atom constructors act like functions and
|
||||
fully support currying - e.g. one can create `fn = Maybe.Just` and later apply
|
||||
two to it (`fn 2`) to obtain new atom.
|
||||
|
||||
- **Autoscoped Constructors:** Referencing constructors via their type name may
|
||||
lead to long and boilerplate code. To simplify referencing constructors when
|
||||
the _context is known_ a special `~` syntax is supported. Should there be a
|
||||
method `describe`:
|
||||
|
||||
```ruby
|
||||
describe (m : Maybe) -> Text = if m.is_just then m.value.to_text else "Empty"
|
||||
```
|
||||
|
||||
one may invoke it as `describe (Maybe.Just 5)` - e.g. the regular way. Or one
|
||||
may use _autoscoped constructors_ and call
|
||||
|
||||
```ruby
|
||||
describe (~Just 5)
|
||||
```
|
||||
|
||||
the argument `(~Just 5)` is _recorded but not executed_ until it is send to
|
||||
the `describe` method. The argument of the `describe` method is known to be of
|
||||
type `Maybe` and have `Just` constructor. The _scope_ is now known and the so
|
||||
far deferred `~` value gets evaluated. `Maybe.Just 5` atom is constructed and
|
||||
execution of `describe` method continues with such atom.
|
||||
|
||||
- **Body Without Atom Definitions:** If you provide a body and do not define any
|
||||
atoms within it, this creates an interface that asserts no atoms as part of
|
||||
|
@ -1,15 +1,18 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Engine;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.BenchmarkParams;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
@ -33,16 +36,7 @@ public class ArrayProxyBenchmarks {
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmark(BenchmarkParams params) throws Exception {
|
||||
Engine eng =
|
||||
Engine.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.option(
|
||||
"enso.languageHomeOverride",
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
var ctx = Context.newBuilder().engine(eng).allowIO(IOAccess.ALL).allowAllAccess(true).build();
|
||||
var ctx = SrcUtil.newContextBuilder().build();
|
||||
var code =
|
||||
"""
|
||||
import Standard.Base.Data.Vector.Vector
|
||||
|
@ -1,13 +1,9 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.interpreter.bench.Utils;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
@ -59,9 +55,28 @@ public class AtomBenchmarks {
|
||||
import Standard.Base.Data.Numbers
|
||||
|
||||
main = length ->
|
||||
generator = acc -> i -> if i == 0 then acc else @Tail_Call generator (List.Cons i acc) (i - 1)
|
||||
qualified_generator = acc -> i -> if i == 0 then acc else
|
||||
@Tail_Call qualified_generator (List.Cons i acc) (i - 1)
|
||||
|
||||
res = generator List.Nil length
|
||||
res = qualified_generator List.Nil length
|
||||
res
|
||||
""";
|
||||
|
||||
private static final String GENERATE_LIST_AUTOSCOPING_CODE =
|
||||
"""
|
||||
import Standard.Base.Data.List.List
|
||||
import Standard.Base.Data.Numbers
|
||||
import Standard.Base.Data.Numbers.Integer
|
||||
|
||||
main = length ->
|
||||
autoscoped_generator x i:Integer =
|
||||
acc = x:List
|
||||
if i == 0 then acc else
|
||||
c = ~Cons i acc
|
||||
i1 = i - 1
|
||||
@Tail_Call autoscoped_generator c i1
|
||||
|
||||
res = autoscoped_generator ~Nil length
|
||||
res
|
||||
""";
|
||||
private static final String REVERSE_LIST_CODE =
|
||||
@ -174,6 +189,7 @@ public class AtomBenchmarks {
|
||||
private Value millionElementsList;
|
||||
private Value generateList;
|
||||
private Value generateListQualified;
|
||||
private Value generateListAutoscoping;
|
||||
private Value reverseList;
|
||||
private Value reverseListMethods;
|
||||
private Value sumList;
|
||||
@ -184,31 +200,54 @@ public class AtomBenchmarks {
|
||||
private Value mapReverseListCurry;
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmarks(BenchmarkParams params) {
|
||||
this.context =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(
|
||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
public void initializeBenchmarks(BenchmarkParams params) throws IOException {
|
||||
this.context = SrcUtil.newContextBuilder().build();
|
||||
|
||||
var millionElemListMethod = Utils.getMainMethod(context, MILLION_ELEMENT_LIST);
|
||||
var millionElemListMethod = mainMethod(context, "millionElementList", MILLION_ELEMENT_LIST);
|
||||
this.millionElementsList = millionElemListMethod.execute();
|
||||
this.generateList = Utils.getMainMethod(context, GENERATE_LIST_CODE);
|
||||
this.generateListQualified = Utils.getMainMethod(context, GENERATE_LIST_QUALIFIED_CODE);
|
||||
this.reverseList = Utils.getMainMethod(context, REVERSE_LIST_CODE);
|
||||
this.reverseListMethods = Utils.getMainMethod(context, REVERSE_LIST_METHODS_CODE);
|
||||
this.sumList = Utils.getMainMethod(context, SUM_LIST_CODE);
|
||||
this.sumListLeftFold = Utils.getMainMethod(context, SUM_LIST_LEFT_FOLD_CODE);
|
||||
this.sumListFallback = Utils.getMainMethod(context, SUM_LIST_FALLBACK_CODE);
|
||||
this.sumListMethods = Utils.getMainMethod(context, SUM_LIST_METHODS_CODE);
|
||||
this.mapReverseList = Utils.getMainMethod(context, MAP_REVERSE_LIST_CODE);
|
||||
this.mapReverseListCurry = Utils.getMainMethod(context, MAP_REVERSE_LIST_CURRY_CODE);
|
||||
|
||||
var lastDot = params.getBenchmark().lastIndexOf('.');
|
||||
var name = params.getBenchmark().substring(lastDot + 1);
|
||||
switch (name) {
|
||||
case "benchGenerateList" -> {
|
||||
this.generateList = mainMethod(context, name, GENERATE_LIST_CODE);
|
||||
}
|
||||
case "benchGenerateListQualified" -> {
|
||||
this.generateListQualified = mainMethod(context, name, GENERATE_LIST_QUALIFIED_CODE);
|
||||
}
|
||||
case "benchGenerateListAutoscoping" -> {
|
||||
this.generateListAutoscoping = mainMethod(context, name, GENERATE_LIST_AUTOSCOPING_CODE);
|
||||
}
|
||||
case "benchReverseList" -> {
|
||||
this.reverseList = mainMethod(context, name, REVERSE_LIST_CODE);
|
||||
}
|
||||
case "benchReverseListMethods" -> {
|
||||
this.reverseListMethods = mainMethod(context, name, REVERSE_LIST_METHODS_CODE);
|
||||
}
|
||||
case "benchSumList" -> {
|
||||
this.sumList = mainMethod(context, name, SUM_LIST_CODE);
|
||||
}
|
||||
case "benchSumListLeftFold" -> {
|
||||
this.sumListLeftFold = mainMethod(context, name, SUM_LIST_LEFT_FOLD_CODE);
|
||||
}
|
||||
case "benchSumListFallback" -> {
|
||||
this.sumListFallback = mainMethod(context, name, SUM_LIST_FALLBACK_CODE);
|
||||
}
|
||||
case "benchSumListMethods" -> {
|
||||
this.sumListMethods = mainMethod(context, name, SUM_LIST_METHODS_CODE);
|
||||
}
|
||||
case "benchMapReverseList" -> {
|
||||
this.mapReverseList = mainMethod(context, name, MAP_REVERSE_LIST_CODE);
|
||||
}
|
||||
case "benchMapReverseListCurry" -> {
|
||||
this.mapReverseListCurry = mainMethod(context, name, MAP_REVERSE_LIST_CURRY_CODE);
|
||||
}
|
||||
default -> throw new IllegalArgumentException(name);
|
||||
}
|
||||
}
|
||||
|
||||
private static Value mainMethod(Context context, String name, String code) throws IOException {
|
||||
return SrcUtil.getMainMethod(context, name, code);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@ -223,6 +262,12 @@ public class AtomBenchmarks {
|
||||
bh.consume(res);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void benchGenerateListAutoscoping(Blackhole bh) {
|
||||
var res = generateListAutoscoping.execute(MILLION);
|
||||
bh.consume(res);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void benchReverseList(Blackhole bh) {
|
||||
var reversedList = reverseList.execute(millionElementsList);
|
||||
@ -245,7 +290,7 @@ public class AtomBenchmarks {
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void sumListLeftFold(Blackhole bh) {
|
||||
public void benchSumListLeftFold(Blackhole bh) {
|
||||
var res = sumListLeftFold.execute(millionElementsList);
|
||||
if (!res.fitsInLong()) {
|
||||
throw new AssertionError("Should return a number");
|
||||
@ -278,7 +323,7 @@ public class AtomBenchmarks {
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void benchMapReverseCurryList(Blackhole bh) {
|
||||
public void benchMapReverseListCurry(Blackhole bh) {
|
||||
var res = mapReverseListCurry.execute(millionElementsList);
|
||||
bh.consume(res);
|
||||
}
|
||||
|
@ -1,13 +1,9 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.interpreter.bench.Utils;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
@ -81,17 +77,7 @@ main = sumTo ->
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmarks(BenchmarkParams params) {
|
||||
this.context =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(
|
||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
this.context = SrcUtil.newContextBuilder().build();
|
||||
|
||||
this.sumTCOfromCall = Utils.getMainMethod(context, SUM_TCO_FROM_CALL_CODE);
|
||||
this.sumTCOmethodCall = Utils.getMainMethod(context, SUM_TCO_METHOD_CALL_CODE);
|
||||
|
@ -1,6 +1,5 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -8,12 +7,8 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.polyglot.MethodNames.Module;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
@ -58,17 +53,7 @@ public class EqualsBenchmarks {
|
||||
public void initializeBenchmark(BenchmarkParams params) throws Exception {
|
||||
var random = new Random(42);
|
||||
|
||||
var ctx =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(
|
||||
"enso.languageHomeOverride",
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
var ctx = SrcUtil.newContextBuilder().build();
|
||||
|
||||
var benchmarkName = SrcUtil.findName(params);
|
||||
var codeBuilder =
|
||||
|
@ -3,17 +3,13 @@ package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.polyglot.MethodNames.Module;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
@ -47,21 +43,7 @@ public class IfVsCaseBenchmarks {
|
||||
@Setup
|
||||
public void initializeBench(BenchmarkParams params) throws IOException {
|
||||
OutputStream out = new ByteArrayOutputStream();
|
||||
ctx =
|
||||
Context.newBuilder("enso")
|
||||
.allowAllAccess(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.out(out)
|
||||
.err(out)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowExperimentalOptions(true)
|
||||
.option(
|
||||
"enso.languageHomeOverride",
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.option("engine.MultiTier", "true")
|
||||
.option("engine.BackgroundCompilation", "true")
|
||||
.build();
|
||||
ctx = SrcUtil.newContextBuilder().out(out).err(out).build();
|
||||
|
||||
var code =
|
||||
"""
|
||||
|
@ -1,13 +1,8 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
@ -38,17 +33,7 @@ public class ListBenchmarks {
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmark(BenchmarkParams params) throws Exception {
|
||||
var ctx =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.option(
|
||||
"enso.languageHomeOverride",
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
var ctx = SrcUtil.newContextBuilder().build();
|
||||
|
||||
var benchmarkName = SrcUtil.findName(params);
|
||||
var code =
|
||||
|
@ -1,13 +1,9 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.interpreter.bench.Utils;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
@ -57,18 +53,7 @@ main = sumTo ->
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmarks(BenchmarkParams params) {
|
||||
this.context =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(
|
||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
|
||||
this.context = SrcUtil.newContextBuilder().build();
|
||||
this.sumTCOWithNamedArguments = Utils.getMainMethod(context, SUM_TCO_WITH_NAMED_ARGUMENTS_CODE);
|
||||
this.sumTCOWithDefaultedArguments =
|
||||
Utils.getMainMethod(context, SUM_TCO_WITH_DEFAULTED_ARGUMENTS_CODE);
|
||||
|
@ -1,14 +1,10 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
@ -36,18 +32,7 @@ public class NestedPatternCompilationBenchmarks {
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmark(BenchmarkParams params) throws Exception {
|
||||
ctx =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.option(
|
||||
"enso.languageHomeOverride",
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
|
||||
ctx = SrcUtil.newContextBuilder().build();
|
||||
benchmarkName = SrcUtil.findName(params);
|
||||
code =
|
||||
"""
|
||||
|
@ -1,14 +1,19 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.interpreter.bench.Utils;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.BenchmarkParams;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
@ -114,17 +119,7 @@ main = n ->
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmarks(BenchmarkParams params) {
|
||||
this.context =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(
|
||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
this.context = SrcUtil.newContextBuilder().build();
|
||||
|
||||
this.sumTCO = Utils.getMainMethod(context, SUM_TCO_CODE);
|
||||
this.sumTCOWithEval = Utils.getMainMethod(context, SUM_TCO_WITH_EVAL_CODE);
|
||||
|
@ -3,8 +3,15 @@ package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.polyglot.MethodNames.Module;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Source;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.infra.BenchmarkParams;
|
||||
|
||||
final class SrcUtil {
|
||||
@ -30,4 +37,36 @@ final class SrcUtil {
|
||||
Objects.requireNonNull(url, "Searching for " + resource);
|
||||
return Source.newBuilder("enso", url).name(resource).build();
|
||||
}
|
||||
|
||||
static Value getMainMethod(Context context, String benchmarkName, String code)
|
||||
throws IOException {
|
||||
var src = source(benchmarkName, code);
|
||||
var module = context.eval(src);
|
||||
var moduleType = module.invokeMember(Module.GET_ASSOCIATED_TYPE);
|
||||
var main = module.invokeMember(Module.GET_METHOD, moduleType, "main");
|
||||
if (!main.canExecute()) {
|
||||
throw new AssertionError("Main method should be executable");
|
||||
}
|
||||
return main;
|
||||
}
|
||||
|
||||
/**
|
||||
* Typical builder suitable for benchmarking.
|
||||
*
|
||||
* @return preconfigured builder to use as a base for benchmarking
|
||||
*/
|
||||
static Context.Builder newContextBuilder() {
|
||||
return Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option("engine.MultiTier", "false")
|
||||
.option("engine.BackgroundCompilation", "false")
|
||||
.option("engine.CompilationFailureAction", "Print")
|
||||
.option(
|
||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,8 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
@ -34,18 +29,7 @@ public class StringBenchmarks {
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmark(BenchmarkParams params) throws Exception {
|
||||
var ctx =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.option(
|
||||
"enso.languageHomeOverride",
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
|
||||
var ctx = SrcUtil.newContextBuilder().build();
|
||||
var code =
|
||||
"""
|
||||
from Standard.Base import all
|
||||
|
@ -1,15 +1,19 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.polyglot.MethodNames.Module;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.BenchmarkParams;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
@ -26,17 +30,7 @@ public class TypePatternBenchmarks {
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmark(BenchmarkParams params) throws Exception {
|
||||
var ctx =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.option(
|
||||
"enso.languageHomeOverride",
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
var ctx = SrcUtil.newContextBuilder().build();
|
||||
var code =
|
||||
"""
|
||||
from Standard.Base import Integer, Vector, Any, Float
|
||||
|
@ -1,14 +1,9 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.AbstractList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
@ -35,18 +30,7 @@ public class VectorBenchmarks {
|
||||
|
||||
@Setup
|
||||
public void initializeBenchmark(BenchmarkParams params) throws Exception {
|
||||
var ctx =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.option(
|
||||
"enso.languageHomeOverride",
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
|
||||
var ctx = SrcUtil.newContextBuilder().build();
|
||||
var benchmarkName = SrcUtil.findName(params);
|
||||
var code =
|
||||
"""
|
||||
|
@ -1,18 +1,14 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import org.enso.polyglot.MethodNames;
|
||||
import org.enso.polyglot.RuntimeOptions;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.io.IOAccess;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
@ -71,17 +67,7 @@ public class WarningBenchmarks {
|
||||
|
||||
@Setup
|
||||
public void initializeBench(BenchmarkParams params) throws IOException {
|
||||
this.ctx =
|
||||
Context.newBuilder()
|
||||
.allowExperimentalOptions(true)
|
||||
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||
.logHandler(System.err)
|
||||
.allowIO(IOAccess.ALL)
|
||||
.allowAllAccess(true)
|
||||
.option(
|
||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||
.build();
|
||||
this.ctx = SrcUtil.newContextBuilder().build();
|
||||
var random = new Random(42);
|
||||
|
||||
benchmarkName = SrcUtil.findName(params);
|
||||
|
@ -0,0 +1,226 @@
|
||||
package org.enso.interpreter.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import org.enso.polyglot.MethodNames;
|
||||
import org.graalvm.polyglot.Context;
|
||||
import org.graalvm.polyglot.PolyglotException;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AutoscopedConstructorTest extends TestBase {
|
||||
private static final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
private static Context ctx;
|
||||
|
||||
public AutoscopedConstructorTest() {}
|
||||
|
||||
@BeforeClass
|
||||
public static void prepareCtx() {
|
||||
ctx = createDefaultContext(out);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void resetOut() {
|
||||
out.reset();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void disposeCtx() {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lazyConstructorWithNoArgument() {
|
||||
try {
|
||||
var create =
|
||||
ctx.eval(
|
||||
"enso",
|
||||
"""
|
||||
type N
|
||||
False
|
||||
|
||||
materialize v:N = v.to_text
|
||||
|
||||
create n = N.materialize (~False)
|
||||
""")
|
||||
.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create");
|
||||
assertTrue("Can evaluate", create.canExecute());
|
||||
assertEquals("False", create.execute(42).asString());
|
||||
|
||||
} catch (PolyglotException e) {
|
||||
fail(e.getMessage() + " for \n" + out.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lazyConstructorWithSingleArg() {
|
||||
try {
|
||||
var create =
|
||||
ctx.eval(
|
||||
"enso",
|
||||
"""
|
||||
type M
|
||||
Construct value
|
||||
|
||||
materialize v:M = v.value
|
||||
|
||||
create n = M.materialize (~Construct n)
|
||||
""")
|
||||
.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create");
|
||||
assertTrue("Can evaluate", create.canExecute());
|
||||
assertEquals("42", create.execute(42).toString());
|
||||
|
||||
} catch (PolyglotException e) {
|
||||
fail(e.getMessage() + " for \n" + out.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lazyConstructorWithTwoArgs() {
|
||||
try {
|
||||
var create =
|
||||
ctx.eval(
|
||||
"enso",
|
||||
"""
|
||||
type M
|
||||
Construct v1 v2
|
||||
|
||||
materialize v:M = [v.v1, v.v2]
|
||||
|
||||
create a b = M.materialize (~Construct a b)
|
||||
""")
|
||||
.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create");
|
||||
assertTrue("Can evaluate", create.canExecute());
|
||||
assertEquals("[6, 7]", create.execute(6, 7).toString());
|
||||
} catch (PolyglotException e) {
|
||||
fail(e.getMessage() + " for \n" + out.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lazyConstructorWithTwoArgsCurried() {
|
||||
try {
|
||||
var create =
|
||||
ctx.eval(
|
||||
"enso",
|
||||
"""
|
||||
type M
|
||||
Construct v1 v2
|
||||
|
||||
materialize v:M = [v.v1, v.v2]
|
||||
|
||||
create a b =
|
||||
v0 = ~Construct
|
||||
v1 = v0 a
|
||||
v2 = v1 b
|
||||
M.materialize v2
|
||||
""")
|
||||
.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create");
|
||||
assertTrue("Can evaluate", create.canExecute());
|
||||
assertEquals("[7, 6]", create.execute(7, 6).toString());
|
||||
} catch (PolyglotException e) {
|
||||
fail(e.getMessage() + " for \n" + out.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lazyConstructorWithTwoArgsNamed() {
|
||||
try {
|
||||
var create =
|
||||
ctx.eval(
|
||||
"enso",
|
||||
"""
|
||||
type M
|
||||
Construct v1 v2
|
||||
|
||||
materialize v:M = [v.v1, v.v2]
|
||||
|
||||
create a b =
|
||||
v0 = ~Construct v2=a v1=b
|
||||
M.materialize v0
|
||||
""")
|
||||
.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create");
|
||||
assertTrue("Can evaluate", create.canExecute());
|
||||
assertEquals("[7, 6]", create.execute(6, 7).toString());
|
||||
} catch (PolyglotException e) {
|
||||
fail(e.getMessage() + " for \n" + out.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lazyConstructorWithNamedDefaultedArguments() {
|
||||
try {
|
||||
var module =
|
||||
ctx.eval(
|
||||
"enso",
|
||||
"""
|
||||
type M
|
||||
Construct v1=1 v2=2 v3=3 v4=4
|
||||
|
||||
materialize v:M = [v.v1, v.v2, v.v3, v.v4]
|
||||
|
||||
c0 _ = M.materialize (~Construct)
|
||||
c1 a = M.materialize (~Construct a)
|
||||
c12 a b = M.materialize (~Construct a b)
|
||||
c123 a b c = M.materialize (~Construct a b c)
|
||||
c1234 a b c d = M.materialize (~Construct a b c d)
|
||||
c14 a d = M.materialize (~Construct a v4=d)
|
||||
c13 a c = M.materialize (~Construct a v3=c)
|
||||
c41 a d = M.materialize ((~Construct v4=d) a)
|
||||
c31 a c = M.materialize ((~Construct v3=c) a)
|
||||
""");
|
||||
|
||||
var c0 = module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "c0");
|
||||
var c1 = module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "c1");
|
||||
var c12 = module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "c12");
|
||||
var c123 = module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "c123");
|
||||
var c1234 = module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "c1234");
|
||||
var c14 = module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "c14");
|
||||
var c13 = module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "c13");
|
||||
var c41 = module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "c41");
|
||||
var c31 = module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "c31");
|
||||
|
||||
assertEquals("[1, 2, 3, 4]", c0.execute("ignored").toString());
|
||||
assertEquals("[9, 2, 3, 4]", c1.execute(9).toString());
|
||||
assertEquals("[9, 7, 3, 4]", c12.execute(9, 7).toString());
|
||||
assertEquals("[9, 7, 5, 4]", c123.execute(9, 7, 5).toString());
|
||||
assertEquals("[9, 7, 5, 3]", c1234.execute(9, 7, 5, 3).toString());
|
||||
assertEquals("[8, 2, 3, 7]", c14.execute(8, 7).toString());
|
||||
assertEquals("[8, 2, 7, 4]", c13.execute(8, 7).toString());
|
||||
assertEquals("[8, 2, 3, 7]", c41.execute(8, 7).toString());
|
||||
assertEquals("[8, 2, 7, 4]", c31.execute(8, 7).toString());
|
||||
} catch (PolyglotException e) {
|
||||
fail(e.getMessage() + " for \n" + out.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongConstructorNameYieldsTypeError() {
|
||||
try {
|
||||
var create =
|
||||
ctx.eval(
|
||||
"enso",
|
||||
"""
|
||||
type N
|
||||
False
|
||||
|
||||
materialize v:N = v.to_text
|
||||
|
||||
create n = N.materialize (~True)
|
||||
""")
|
||||
.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create");
|
||||
assertTrue("Can evaluate", create.canExecute());
|
||||
var r = create.execute(42);
|
||||
fail("Expecting an exception, not " + r);
|
||||
} catch (PolyglotException e) {
|
||||
assertTrue(
|
||||
"Expecting type error, but got: " + e.getMessage(),
|
||||
e.getMessage().contains("Type_Error"));
|
||||
}
|
||||
}
|
||||
}
|
@ -1030,6 +1030,16 @@ final class TreeToIr {
|
||||
}
|
||||
case null -> translateSyntaxError(tree, new Syntax.UnsupportedSyntax("Strange unary -"));
|
||||
};
|
||||
case Tree.UnaryOprApp un when "~".equals(un.getOpr().codeRepr()) -> {
|
||||
var methodName = buildName(un.getRhs());
|
||||
var methodRef = new Name.MethodReference(
|
||||
Option.empty(),
|
||||
methodName,
|
||||
methodName.location(),
|
||||
meta(), diag()
|
||||
);
|
||||
yield methodRef;
|
||||
}
|
||||
case Tree.TypeSignature sig -> {
|
||||
var methodName = buildName(sig.getVariable());
|
||||
var methodReference = new CallArgument.Specified(
|
||||
|
@ -15,6 +15,7 @@ import org.enso.interpreter.node.BaseNode;
|
||||
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
||||
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedConstructor;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedConversion;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
@ -236,6 +237,12 @@ public abstract class InvokeCallableNode extends BaseNode {
|
||||
}
|
||||
}
|
||||
|
||||
@Specialization
|
||||
public Object invokeDynamicConstructor(
|
||||
UnresolvedConstructor symbol, VirtualFrame callerFrame, State state, Object[] arguments) {
|
||||
return symbol.withArguments(invokeFunctionNode.getSchema(), arguments);
|
||||
}
|
||||
|
||||
@Specialization
|
||||
public Object invokeDynamicSymbol(
|
||||
UnresolvedSymbol symbol, VirtualFrame callerFrame, State state, Object[] arguments) {
|
||||
|
@ -32,6 +32,7 @@ import org.enso.interpreter.node.expression.builtin.meta.TypeOfNode;
|
||||
import org.enso.interpreter.node.expression.literal.LiteralNode;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.callable.Annotation;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedConstructor;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedConversion;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition.ExecutionMode;
|
||||
@ -41,6 +42,7 @@ import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
||||
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;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||
@ -88,7 +90,15 @@ public abstract class ReadArgumentCheckNode extends Node {
|
||||
expectedTypeMessage = expectedTypeMessage();
|
||||
}
|
||||
var ctx = EnsoContext.get(this);
|
||||
var msg = comment == null ? "expression" : comment;
|
||||
Text msg;
|
||||
if (v instanceof UnresolvedConstructor) {
|
||||
msg = Text.create("Cannot find constructor {got} among {exp}");
|
||||
} else {
|
||||
var where = Text.create(comment == null ? "expression" : comment);
|
||||
var exp = Text.create("expected ");
|
||||
var got = Text.create(" to be {exp}, but got {got}");
|
||||
msg = Text.create(exp, Text.create(where, got));
|
||||
}
|
||||
var err = ctx.getBuiltins().error().makeTypeErrorOfComment(expectedTypeMessage, v, msg);
|
||||
throw new PanicException(err, this);
|
||||
}
|
||||
@ -254,6 +264,15 @@ public abstract class ReadArgumentCheckNode extends Node {
|
||||
throw panicSentinel;
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Object doUnresolvedConstructor(
|
||||
VirtualFrame frame,
|
||||
UnresolvedConstructor unresolved,
|
||||
@Cached UnresolvedConstructor.ConstructNode construct) {
|
||||
var state = Function.ArgumentsHelper.getState(frame.getArguments());
|
||||
return construct.execute(frame, state, expectedType, unresolved);
|
||||
}
|
||||
|
||||
@Specialization(rewriteOn = InvalidAssumptionException.class)
|
||||
Object doCheckNoConversionNeeded(VirtualFrame frame, Object v)
|
||||
throws InvalidAssumptionException {
|
||||
|
@ -54,7 +54,12 @@ public final class TypeToDisplayTextNode extends Node {
|
||||
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
||||
}
|
||||
} else {
|
||||
return "a polyglot object";
|
||||
try {
|
||||
var res = iop.toDisplayString(value);
|
||||
return iop.asString(res);
|
||||
} catch (UnsupportedMessageException ex) {
|
||||
return "a polyglot object";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,16 @@ package org.enso.interpreter.node.expression.constant;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import org.enso.interpreter.node.ExpressionNode;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedConstructor;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||
|
||||
/** Simple constant node that always results in the same {@link UnresolvedSymbol}. */
|
||||
@NodeInfo(shortName = "DynamicSym")
|
||||
public class DynamicSymbolNode extends ExpressionNode {
|
||||
private final UnresolvedSymbol unresolvedSymbol;
|
||||
private final EnsoObject unresolvedSymbol;
|
||||
|
||||
private DynamicSymbolNode(UnresolvedSymbol unresolvedSymbol) {
|
||||
private DynamicSymbolNode(EnsoObject unresolvedSymbol) {
|
||||
this.unresolvedSymbol = unresolvedSymbol;
|
||||
}
|
||||
|
||||
@ -24,6 +26,10 @@ public class DynamicSymbolNode extends ExpressionNode {
|
||||
return new DynamicSymbolNode(symbol);
|
||||
}
|
||||
|
||||
public static DynamicSymbolNode build(UnresolvedConstructor symbol) {
|
||||
return new DynamicSymbolNode(symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dynamic symbol from the node.
|
||||
*
|
||||
|
@ -195,8 +195,8 @@ public final class Error {
|
||||
* @param comment description of the value that was being checked
|
||||
* @return a runtime representation of the error.
|
||||
*/
|
||||
public Atom makeTypeErrorOfComment(Object expected, Object actual, String comment) {
|
||||
return typeError.newInstance(expected, actual, Text.create(comment));
|
||||
public Atom makeTypeErrorOfComment(Object expected, Object actual, Text comment) {
|
||||
return typeError.newInstance(expected, actual, comment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,161 @@
|
||||
package org.enso.interpreter.runtime.callable;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.MaterializedFrame;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.library.ExportLibrary;
|
||||
import com.oracle.truffle.api.library.ExportMessage;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import org.enso.interpreter.node.callable.InvokeCallableNode.ArgumentsExecutionMode;
|
||||
import org.enso.interpreter.node.callable.InvokeCallableNode.DefaultsExecutionMode;
|
||||
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||
import org.enso.interpreter.runtime.data.Type;
|
||||
import org.enso.interpreter.runtime.data.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.state.State;
|
||||
|
||||
/**
|
||||
* Value representing a by-name identified constructor of a yet unknown {@link Type}. Create new
|
||||
* instance by providing name to {@link #build(String)} method. Then apply arguments to it via
|
||||
* {@link #withArguments(Object[])} method.
|
||||
*
|
||||
* <p>Let the object flow thru the interpreter and resolve it when the required {@link Type} is
|
||||
* known.
|
||||
*/
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
public final class UnresolvedConstructor implements EnsoObject {
|
||||
private static final CallArgumentInfo[] NONE = new CallArgumentInfo[0];
|
||||
private final String name;
|
||||
final CallArgumentInfo[] descs;
|
||||
private final Object[] args;
|
||||
|
||||
/**
|
||||
* Creates a new unresolved name.
|
||||
*
|
||||
* @param name constructor name
|
||||
* @param descs argument descriptions to apply to the constructor
|
||||
* @param args argument values to apply to the constructor
|
||||
*/
|
||||
private UnresolvedConstructor(String name, CallArgumentInfo[] descs, Object[] args) {
|
||||
this.name = name;
|
||||
this.descs = descs;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
final String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public String toString() {
|
||||
return "~" + name;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
String toDisplayString(boolean allowSideEffects) {
|
||||
return toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of this node.
|
||||
*
|
||||
* @param name the name (of the constructor) we are searching for
|
||||
* @return a object representing unresolved (constructor)
|
||||
*/
|
||||
public static UnresolvedConstructor build(String name) {
|
||||
return new UnresolvedConstructor(name, NONE, NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this object as executable through the interop library.
|
||||
*
|
||||
* @param additionalDescriptions description of the applied arguments
|
||||
* @param additionalArguments new arguments to add to the unresolved constructor
|
||||
* @return always true @ExportMessage public boolean isExecutable() { return true; }
|
||||
*/
|
||||
public UnresolvedConstructor withArguments(
|
||||
CallArgumentInfo[] additionalDescriptions, Object[] additionalArguments) {
|
||||
if (this.args == NONE) {
|
||||
return new UnresolvedConstructor(this.name, additionalDescriptions, additionalArguments);
|
||||
} else {
|
||||
var newDescs = join(this.descs, additionalDescriptions);
|
||||
var newArgs = join(this.args, additionalArguments);
|
||||
return new UnresolvedConstructor(this.name, newDescs, newArgs);
|
||||
}
|
||||
}
|
||||
|
||||
final UnresolvedConstructor asPrototype() {
|
||||
return new UnresolvedConstructor(this.name, this.descs, null);
|
||||
}
|
||||
|
||||
final boolean sameAsPrototyped(UnresolvedConstructor other) {
|
||||
if (descs.length != other.descs.length) {
|
||||
return false;
|
||||
}
|
||||
if (!name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < descs.length; i++) {
|
||||
if (!Objects.equals(descs[i].getName(), other.descs[i].getName())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static <T> T[] join(T[] arr1, T[] arr2) {
|
||||
var ret = Arrays.copyOf(arr1, arr1.length + arr2.length);
|
||||
System.arraycopy(arr2, 0, ret, arr1.length, arr2.length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public abstract static class ConstructNode extends Node {
|
||||
static final DefaultsExecutionMode EXEC_MODE = DefaultsExecutionMode.EXECUTE;
|
||||
static final ArgumentsExecutionMode ARGS_MODE = ArgumentsExecutionMode.EXECUTE;
|
||||
|
||||
public abstract Object execute(
|
||||
VirtualFrame frame, State state, Type expectedType, UnresolvedConstructor unresolved);
|
||||
|
||||
@Specialization(
|
||||
guards = {"cachedType == expectedType", "prototype.sameAsPrototyped(unresolved)"},
|
||||
limit = "10")
|
||||
Object instantiateCached(
|
||||
VirtualFrame frame,
|
||||
State state,
|
||||
Type expectedType,
|
||||
UnresolvedConstructor unresolved,
|
||||
@Cached("expectedType") Type cachedType,
|
||||
@Cached("unresolved.asPrototype()") UnresolvedConstructor prototype,
|
||||
@Cached("expectedType.getConstructors().get(prototype.getName())") AtomConstructor c,
|
||||
@Cached("build(prototype.descs,EXEC_MODE,ARGS_MODE)") InvokeFunctionNode invoke) {
|
||||
if (c == null) {
|
||||
return null;
|
||||
} else {
|
||||
var fn = c.getConstructorFunction();
|
||||
var r = invoke.execute(fn, frame, state, unresolved.args);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@Specialization(replaces = "instantiateCached")
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
Object instantiateUncached(
|
||||
MaterializedFrame frame, State state, Type expectedType, UnresolvedConstructor unresolved) {
|
||||
var c = expectedType.getConstructors().get(unresolved.getName());
|
||||
if (c == null) {
|
||||
return null;
|
||||
}
|
||||
var fn = c.getConstructorFunction();
|
||||
var invoke = InvokeFunctionNode.build(unresolved.descs, EXEC_MODE, ARGS_MODE);
|
||||
var r = invoke.execute(fn, frame, state, unresolved.args);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
@ -97,6 +97,7 @@ import org.enso.interpreter.runtime.callable.function.{
|
||||
Function => RuntimeFunction
|
||||
}
|
||||
import org.enso.interpreter.runtime.callable.{
|
||||
UnresolvedConstructor,
|
||||
UnresolvedConversion,
|
||||
UnresolvedSymbol,
|
||||
Annotation => RuntimeAnnotation
|
||||
@ -1680,6 +1681,16 @@ class IrToTruffle(
|
||||
UnresolvedSymbol.build(nameStr, moduleScope)
|
||||
)
|
||||
}
|
||||
case Name.MethodReference(
|
||||
None,
|
||||
Name.Literal(nameStr, _, _, _, _, _),
|
||||
_,
|
||||
_,
|
||||
_
|
||||
) =>
|
||||
DynamicSymbolNode.build(
|
||||
UnresolvedConstructor.build(nameStr)
|
||||
)
|
||||
case Name.Self(location, _, passData, _) =>
|
||||
processName(
|
||||
Name.Literal(
|
||||
@ -1715,10 +1726,6 @@ class IrToTruffle(
|
||||
throw new CompilerError(
|
||||
"Blanks should not be present at codegen time."
|
||||
)
|
||||
case _: Name.MethodReference =>
|
||||
throw new CompilerError(
|
||||
"Method references should not be present at codegen time."
|
||||
)
|
||||
case _: Name.Qualified =>
|
||||
throw new CompilerError(
|
||||
"Qualified names should not be present at codegen time."
|
||||
|
@ -15,6 +15,7 @@ import org.openjdk.jmh.runner.RunnerException;
|
||||
import org.openjdk.jmh.runner.options.CommandLineOptionException;
|
||||
import org.openjdk.jmh.runner.options.CommandLineOptions;
|
||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||
import org.openjdk.jmh.runner.options.TimeValue;
|
||||
|
||||
/** Runner class for the benchmarks. Discovers, runs and reports benchmark results. */
|
||||
public class BenchmarksRunner {
|
||||
@ -77,7 +78,12 @@ public class BenchmarksRunner {
|
||||
private static Collection<RunResult> runCompileOnly(List<String> includes)
|
||||
throws RunnerException {
|
||||
System.out.println("Running benchmarks " + includes + " in compileOnly mode");
|
||||
var optsBuilder = new OptionsBuilder().measurementIterations(1).warmupIterations(0).forks(0);
|
||||
var optsBuilder =
|
||||
new OptionsBuilder()
|
||||
.measurementTime(TimeValue.seconds(1))
|
||||
.measurementIterations(1)
|
||||
.warmupIterations(0)
|
||||
.forks(0);
|
||||
includes.forEach(optsBuilder::include);
|
||||
var opts = optsBuilder.build();
|
||||
var runner = new Runner(opts);
|
||||
|
@ -2,6 +2,9 @@ from Standard.Base import all
|
||||
import Standard.Base.Errors.Common.No_Such_Conversion
|
||||
import Standard.Base.Errors.Common.Type_Error
|
||||
|
||||
import Standard.Base.Runtime.State
|
||||
from Standard.Base.Errors.Common import Uninitialized_State
|
||||
|
||||
import project.Semantic.Conversion.Methods
|
||||
import project.Semantic.Conversion.Types
|
||||
import project.Semantic.Conversion_Use.Hello
|
||||
@ -30,6 +33,9 @@ type My_Error
|
||||
type Not_Foo
|
||||
Value notfoo
|
||||
|
||||
type Stateful
|
||||
Value v:Number=(State.get Number)
|
||||
|
||||
Foo.from (that:Bar) = Foo.Value that.bar
|
||||
Foo.from (that:Baz) = Foo.Value that.baz
|
||||
Foo.from (that:Text) = Foo.Value that.length
|
||||
@ -427,6 +433,83 @@ add_specs suite_builder =
|
||||
|
||||
do_duration now
|
||||
|
||||
suite_builder.group "Autoscoped Constructors" group_builder->
|
||||
|
||||
group_builder.specify "Foo.Value as autoscoped" <|
|
||||
|
||||
v = ~Value 10
|
||||
foo = v:Foo
|
||||
Foo.Value 10 . should_equal foo
|
||||
|
||||
group_builder.specify "Autoscope to two different values" <|
|
||||
|
||||
v = ~Value 10
|
||||
foo = v:Foo
|
||||
bar = v:Bar
|
||||
Foo.Value 10 . should_equal foo
|
||||
Bar.Value 10 . should_equal bar
|
||||
|
||||
group_builder.specify "Cannot find constructor" <|
|
||||
v = ~Value 10
|
||||
|
||||
b = Panic.recover Any <|
|
||||
x = v:Back
|
||||
x
|
||||
|
||||
b . should_fail_with Type_Error
|
||||
msg = b.to_display_text
|
||||
msg . should_contain "Cannot find constructor ~Value among Back"
|
||||
|
||||
group_builder.specify "Choose first constructor" <|
|
||||
v = ~Value 10
|
||||
|
||||
m_foo (m:Foo|Bar|Back) = m
|
||||
m_bar (m:Bar|Foo|Back) = m
|
||||
m_back_foo (m:Back|Foo|Bar) = m
|
||||
m_back_bar (m:Back|Bar|Foo) = m
|
||||
|
||||
m_foo v . should_equal <| Foo.Value 10
|
||||
m_bar v . should_equal <| Bar.Value 10
|
||||
m_back_foo v . should_equal <| Foo.Value 10
|
||||
m_back_bar v . should_equal <| Bar.Value 10
|
||||
|
||||
group_builder.specify "Choose suitable constructor" <|
|
||||
v = ~Times 10
|
||||
|
||||
m_foo (m:Foo|Bar) = m
|
||||
m_bar (m:Bar|Foo) = m
|
||||
m_back (m:Foo|Bar|Back) = m
|
||||
|
||||
Panic.recover Any (m_foo v) . should_fail_with Type_Error
|
||||
Panic.recover Any (m_bar v) . should_fail_with Type_Error
|
||||
m_back v . should_equal <| Back.Times 10
|
||||
|
||||
group_builder.specify "Lazy constructor with State" <|
|
||||
v0 = ~Value
|
||||
v1 = ~Value 33
|
||||
|
||||
State.run Number 42 <|
|
||||
s42 = State.get Number
|
||||
s42 . should_equal 42
|
||||
|
||||
v0:Stateful . should_equal <| Stateful.Value 42
|
||||
v1:Stateful . should_equal <| Stateful.Value 33
|
||||
|
||||
v1:Stateful . should_equal <| Stateful.Value 33
|
||||
err = Panic.recover Any <|
|
||||
v = v0:Stateful
|
||||
v
|
||||
err . should_fail_with Uninitialized_State
|
||||
|
||||
group_builder.specify "Autoscope vector elements" <|
|
||||
|
||||
foo_vec (v:Vector) = v.map e->
|
||||
e:Foo . foo
|
||||
|
||||
vec = [~Value 3, ~Value 4, ~Value 5]
|
||||
|
||||
foo_vec vec . should_equal [3, 4, 5]
|
||||
|
||||
suite_builder.group "Polyglot Argument" group_builder->
|
||||
f1 (x : DateTimeFormatter) = x.to_text
|
||||
f2 (x : Text | DateTimeFormatter) = case x of
|
||||
|
@ -294,7 +294,7 @@ add_specs suite_builder =
|
||||
group_builder.specify "Panic if wrong types passed in element_columns" <|
|
||||
t = data.table
|
||||
r = Panic.recover Any (t.to_xml 1.23)
|
||||
r.to_text.should_equal "(Error: (Type_Error.Error Vector | Text | Integer | Regex 1.23 '`element_columns`'))"
|
||||
r.to_text.should_equal "(Error: Type error: expected `element_columns` to be Vector | Text | Integer | Regex, but got Float.)"
|
||||
group_builder.specify "Panic if wrong types passed in element_columns vector" pending='Not working' <|
|
||||
t = data.table
|
||||
r = Panic.recover Any (t.to_xml [1.23])
|
||||
@ -302,27 +302,27 @@ add_specs suite_builder =
|
||||
group_builder.specify "Panic if wrong types passed in attribute_columns" <|
|
||||
t = data.table
|
||||
r = Panic.recover Any (t.to_xml [] 1.23)
|
||||
r.to_text.should_equal "(Error: (Type_Error.Error Vector | Text | Integer | Regex 1.23 '`attribute_columns`'))"
|
||||
r.to_text.should_equal "(Error: Type error: expected `attribute_columns` to be Vector | Text | Integer | Regex, but got Float.)"
|
||||
group_builder.specify "Panic if wrong types passed in attribute_columns vector" pending='Not working' <|
|
||||
t = data.table
|
||||
r = Panic.recover Any (t.to_xml [] [1.23])
|
||||
r.to_text.should_equal "(Error: (Type_Error.Error Vector | Text | Integer | Regex 1.23 '`attribute_columns`'))"
|
||||
r.to_text.should_equal "(Error: Type error: expected `attribute_columns` to be Vector | Text | Integer | Regex, but got Float.)"
|
||||
group_builder.specify "Panic if wrong types passed in value_column" <|
|
||||
t = data.table
|
||||
r = Panic.recover Any (t.to_xml [] [] 1.23)
|
||||
r.to_text.should_equal "(Error: (Type_Error.Error Text | Integer | Nothing 1.23 '`value_column`'))"
|
||||
r.to_text.should_equal "(Error: Type error: expected `value_column` to be Text | Integer | Nothing, but got Float.)"
|
||||
group_builder.specify "Panic if wrong types passed in root_name" <|
|
||||
t = data.table
|
||||
r = Panic.recover Any (t.to_xml [] [] "Year" 1.23)
|
||||
r.to_text.should_equal "(Error: (Type_Error.Error Text 1.23 '`root_name`'))"
|
||||
r.to_text.should_equal "(Error: Type error: expected `root_name` to be Text, but got Float.)"
|
||||
group_builder.specify "Panic if wrong types passed in row_name" <|
|
||||
t = data.table
|
||||
r = Panic.recover Any (t.to_xml [] [] "Year" "Table" 1.23)
|
||||
r.to_text.should_equal "(Error: (Type_Error.Error Text 1.23 '`row_name`'))"
|
||||
r.to_text.should_equal "(Error: Type error: expected `row_name` to be Text, but got Float.)"
|
||||
group_builder.specify "Panic if wrong types passed in on_problems" <|
|
||||
t = data.table
|
||||
r = Panic.recover Any (t.to_xml [] [] "Year" "Table" "row" 1.23)
|
||||
r.to_text.should_equal "(Error: (Type_Error.Error Problem_Behavior 1.23 '`on_problems`'))"
|
||||
r.to_text.should_equal "(Error: Type error: expected `on_problems` to be Problem_Behavior, but got Float.)"
|
||||
group_builder.specify "works with unicode characters" <|
|
||||
unicode_column = ["unicode", ['\u00A9', "👩🔬"]]
|
||||
# | unicode
|
||||
|
Loading…
Reference in New Issue
Block a user